Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
6.9 KiB
6.9 KiB
Scratchpad — Client Portal Board Visibility Model Correction
- Plan slug:
client-portal-board-visibility-model-correction - Created:
2026-04-15
What This Is
Keep a lightweight, continuously-updated log of discoveries and decisions made while implementing this plan.
Decisions
- (2026-04-15) Treat this work as an implementation correction, not a new feature or schema expansion.
- (2026-04-15) Boards are tenant-scoped for this feature; visibility groups are client-scoped.
- (2026-04-15) Board pickers should show all active tenant boards.
- (2026-04-15) Inactive boards stay in stored group membership but should be excluded from board pickers and new ticket creation choices.
- (2026-04-15) Keep visibility resolver board membership tenant-scoped without forcing active-only filtering so historical group membership data remains intact; enforce active-only for pickers and ticket creation paths.
Discoveries / Constraints
- (2026-04-15) The original migration created
client_portal_visibility_groups(tenant, group_id, client_id, ...)andclient_portal_visibility_group_boards(tenant, group_id, board_id)but did not addboards.client_id. - (2026-04-15) The live schema confirms
boardshas noclient_idcolumn. - (2026-04-15) Current MSP and client-portal visibility-group actions query
boards.client_id, causing intermittent 500s and false empty board states. - (2026-04-15) The shared resolver in
packages/tickets/src/lib/clientPortalVisibility.tsalso filters onb.client_id, so the mismatch affects enforcement, not just UI loading. - (2026-04-15) Candidate smoke client: Emerald City (
ea00c9e1-a294-40f8-84e7-f3e9bb9dd41c) with active boards including General Support and Projects. - (2026-04-15)
packages/clientsvisibility-group tests currently pull a transitive dependency path that fails in this workspace (@alga-psa/event-schemasexport resolution viapackages/workflow-streams), so package-local execution for those tests remains environment-blocked.
Commands / Runbooks
- (2026-04-15) Verify migration/schema:
PGPASSWORD=postpass123 psql -h localhost -p 57433 -U postgres -d server -c "select to_regclass('public.client_portal_visibility_groups'), to_regclass('public.client_portal_visibility_group_boards');"
- (2026-04-15) Inspect board schema:
PGPASSWORD=postpass123 psql -h localhost -p 57433 -U postgres -d server -Atc "select column_name from information_schema.columns where table_schema='public' and table_name='boards';"
- (2026-04-15) Verify candidate smoke client boards/tickets:
PGPASSWORD=postpass123 psql -h localhost -p 57433 -U postgres -d server -F $'\t' -Atc "select b.board_id, b.board_name, count(*) from tickets t join boards b on b.board_id = t.board_id and b.tenant = t.tenant where t.client_id = 'ea00c9e1-a294-40f8-84e7-f3e9bb9dd41c' and t.is_closed = false group by b.board_id, b.board_name order by count(*) desc;"
- (2026-04-15) Current live app / smoke context:
- server URL
http://localhost:3784 - log pane
2c6e6434-e6bd-4f16-a306-4ddf10c5f3d5
- server URL
- (2026-04-15) Executed test commands:
cd packages/client-portal && npx vitest run src/actions/client-portal-actions/visibilityGroupActions.test.tscd packages/tickets && npx vitest run src/lib/clientPortalVisibility.test.ts src/lib/clientPortalVisibility.userModelLifecycle.test.ts src/actions/ticketFormActions.clientPortalVisibility.test.tscd packages/client-portal && npx vitest run src/actions/client-portal-actions/client-tickets.visibility.test.ts -t "rejects inactive boards"cd packages/clients && npx vitest run src/actions/contact-actions/visibilityGroupActions.integration.test.ts src/actions/contact-actions/visibilityGroupActions.permission.test.ts(blocked by package export resolution issue described above)
Links / References
- Original feature PRD:
ee/docs/plans/2026-03-15-client-portal-board-visibility-groups/PRD.md - Model-correction design:
docs/plans/2026-04-15-client-portal-board-visibility-model-correction-design.md - Migration:
server/migrations/20260315110000_create_client_portal_visibility_groups.cjs - MSP contact actions:
packages/clients/src/actions/contact-actions/contactActions.tsx - Client portal group actions:
packages/client-portal/src/actions/client-portal-actions/visibilityGroupActions.ts - Shared resolver:
packages/tickets/src/lib/clientPortalVisibility.ts
Open Questions
- Whether inactive boards should remain effective for historical ticket-detail visibility or be fully excluded from resolved board IDs as well as pickers/creation. Current default is to preserve historical membership and only exclude from pickers and creation choices.
Implementation Log
- (2026-04-15)
F001,F013: Updated MSP board picker action (getClientPortalVisibilityBoardsByClient) to load active boards by tenant only (tenant + is_inactive=false) withoutboards.client_id. - (2026-04-15)
F003,F004: Updated MSP create/update group validation to accept only board IDs that exist in-tenant and are active (is_inactive=false), rejecting missing/cross-tenant/inactive IDs with existing validation error. - (2026-04-15)
F002,F013: Updated client-portal admin board picker action (getClientPortalVisibilityGroupBoards) to load active tenant boards withoutboards.client_id. - (2026-04-15)
F003,F004: ReplacedensureBoardsBelongToClientwithensureBoardsAreActiveInTenantfor client-portal admin create/update flows. - (2026-04-15)
F007,F008: Updated shared resolver (getClientContactVisibilityContext) to removeb.client_idfiltering while preserving strictgroup.client_id === contact.client_idmismatch guard. - (2026-04-15)
F011,F014: Updated ticket creation board option loading (getClientTicketFormData) to exclude inactive boards for both unrestricted and restricted contacts. - (2026-04-15)
F011,F014: Updated client portal ticket submit flow (createClientTicket) to resolve boards only from active records (is_inactive=false) and fail closed when requested board is inactive/disallowed. - (2026-04-15)
F016: Updated model-facing docs (context.md) and added smoke runbook artifact (SMOKE.md) clarifying tenant-scoped boards vs client-scoped groups. - (2026-04-15)
T001: Added MSP board-loading integration test to assert tenant-only active-board query path (noclient_idfilter requirement). - (2026-04-15)
T002: Added client-portal admin board-loading test to assert active tenant board loading path. - (2026-04-15)
T003: Added explicit inactive-board rejection test for visibility-group creation. - (2026-04-15)
T005,T011: Updated resolver lifecycle/unit tests to removeb.client_idassumptions and added explicit empty-group behavior coverage. - (2026-04-15)
T008: Added ticket form and ticket creation tests to verify inactive boards are excluded/rejected under restricted visibility. - (2026-04-15)
T012: AddedSMOKE.mdrunbook for Emerald City seeded-scenario validation across restricted/full/pre-invite flows.