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
108 lines
14 KiB
Markdown
108 lines
14 KiB
Markdown
# Scratchpad — Client Portal Board Visibility Groups
|
|
|
|
- Plan slug: `client-portal-board-visibility-groups`
|
|
- Created: `2026-03-15`
|
|
|
|
## What This Is
|
|
|
|
Keep a lightweight, continuously-updated log of discoveries and decisions made while implementing this plan.
|
|
|
|
Prefer short bullets. Append new entries as you learn things, and also *update earlier notes* when a decision changes or an open question is resolved.
|
|
|
|
## Decisions
|
|
|
|
- (2026-03-15) Existing portal users keep full board access until restricted. `NULL` assignment is the backward-compatible state.
|
|
- (2026-03-15) Visibility is modeled as per-client reusable groups rather than per-user board checklists.
|
|
- (2026-03-15) V1 supports one group per contact/portal user, not multiple groups.
|
|
- (2026-03-15) MSP assignment changes are not locked. Client admins can replace them later.
|
|
- (2026-03-15) Groups are scoped per client, not shared tenant-wide.
|
|
- (2026-03-15) Recommended assignment anchor is the contact record, because portal ticket access already resolves through `users.contact_id` and this supports pre-invitation configuration.
|
|
- (2026-03-15) Deleting an assigned group should fail rather than silently restoring full access.
|
|
|
|
## Discoveries / Constraints
|
|
|
|
- (2026-03-15) Client portal ticket access is client-wide today. `packages/client-portal/src/actions/client-portal-actions/client-tickets.ts` resolves the signed-in user to `users.contact_id`, then `contacts.client_id`, and filters tickets by `t.client_id = contact.client_id`.
|
|
- (2026-03-15) The existing MSP contact portal management surface already exists in `packages/clients/src/components/contacts/ContactPortalTab.tsx`.
|
|
- (2026-03-15) The existing MSP-side contact action for portal admin state lives in `packages/clients/src/actions/contact-actions/contactActions.tsx`.
|
|
- (2026-03-15) Client portal locale files already exist at `server/public/locales/{de,en,es,fr,it,nl,pl,xx,yy}/client-portal.json`.
|
|
- (2026-03-15) Client portal user self-service and contact-linked client-user logic already exists in `packages/client-portal/src/actions/client-portal-actions/clientUserActions.ts`.
|
|
- (2026-03-15) Added MSP portal-side visibility-group capabilities in `ContactPortalTab.tsx`:
|
|
- render assignment selector for selected visibility group / full-access
|
|
- render group editor (name/description/boards)
|
|
- wire create/edit/delete actions against new contact action handlers
|
|
- (2026-03-15) Implemented client-anchored contact action functions in `contactActions.tsx`:
|
|
- list groups, boards, group detail
|
|
- create/update/delete group with board validation
|
|
- assign/unassign visibility group with client-scoped guard
|
|
- delete blocked if currently assigned
|
|
- (2026-03-15) Added `visibilityGroups` locale keys in `server/public/locales/de/es/fr/it/nl/pl/xx/yy/client-portal.json` with English fallback values for parity.
|
|
- (2026-03-15) Added server-side guard tests for contact-actions (`visibilityGroupActions.permission.test.ts`) covering cross-client assignment guard, delete-blocked-when-assigned, and delete-success-unassigned.
|
|
- (2026-03-15) Flipped checklists for F019/F020/F022/F023/F024 and T026/T033/T034 to `true` after implementation.
|
|
- (2026-03-15) Moved the portal board-visibility resolver into shared tickets lib code at `packages/tickets/src/lib/clientPortalVisibility.ts` so both client-portal actions and ticket-form actions use the same enforcement path.
|
|
- (2026-03-15) Tightened shared resolver scoping to join through `boards` and only return board IDs that still belong to the contact's client, which prevents rogue membership rows from broadening access.
|
|
- (2026-03-15) Fixed `getDashboardMetrics` to apply the visibility filter on a chainable ticket query instead of calling `.where(...)` on a `void` helper result.
|
|
- (2026-03-15) `getClientTicketFormData` now uses the shared resolver; invalid/mismatched assignments fail closed by returning no boards instead of silently restoring unrestricted board choices.
|
|
- (2026-03-15) Added migration contract coverage in `server/src/test/unit/migrations/clientPortalVisibilityGroupsMigration.test.ts` and shared resolver coverage in `packages/tickets/src/lib/clientPortalVisibility.test.ts`.
|
|
- (2026-03-15) Flipped checklists for F001/F002/F003/F004/F005/F006 and T001/T002/T003/T004/T005/T006/T007 to `true` after code/test verification.
|
|
- (2026-03-15) Added client portal visibility enforcement tests in `packages/client-portal/src/actions/client-portal-actions/client-tickets.visibility.test.ts` for restricted/unrestricted ticket list behavior, hidden-board detail/document guards, and disallowed-board ticket creation rejection.
|
|
- (2026-03-15) Added dashboard visibility coverage in `packages/client-portal/src/actions/client-portal-actions/dashboard.visibility.test.ts` to prove ticket-backed metrics respect the resolved board set.
|
|
- (2026-03-15) Flipped checklists for F007/F008/F009/F010/F011/F012/F013 and T008/T009/T010/T011/T012/T015/T016/T017 to `true` after code/test verification.
|
|
- (2026-03-15) Updated `ClientAddTicket.tsx` to surface a localized no-boards empty state for restricted contacts and keep ticket creation disabled when no boards are available.
|
|
- (2026-03-15) Added ticket-form visibility tests in `packages/tickets/src/actions/ticketFormActions.clientPortalVisibility.test.ts` and dialog UI tests in `packages/client-portal/src/components/tickets/ClientAddTicket.visibility.test.tsx`.
|
|
- (2026-03-15) Added `create.noBoardsAvailable` to all supported `server/public/locales/*/features/tickets.json` files used by the restricted-ticket empty state.
|
|
- (2026-03-15) Flipped checklists for T013/T014/T037 to `true` after code/test verification.
|
|
- (2026-03-15) Added client portal admin action coverage in `packages/client-portal/src/actions/client-portal-actions/visibilityGroupActions.test.ts` for T018/T019/T020/T021/T022/T023/T024/T025/T027/T032.
|
|
- (2026-03-15) Added locale coverage in `packages/client-portal/src/components/settings/visibilityGroupsLocales.test.ts` for T035/T036 and validated the new `clientSettings.visibilityGroups.*` keys across all supported client portal locales.
|
|
- (2026-03-15) Added MSP contact portal tab UI coverage in `packages/clients/src/components/contacts/ContactPortalTab.visibilityGroups.test.tsx` for T029/T030 to verify assignment replacement plus create/edit flows in the PSA surface.
|
|
- (2026-03-15) Added lifecycle/integration coverage in `packages/tickets/src/lib/clientPortalVisibility.userModelLifecycle.test.ts` and `packages/clients/src/actions/contact-actions/visibilityGroupActions.integration.test.ts` for T028/T031/T038.
|
|
- (2026-03-15) Fixed a second parse error in `packages/clients/src/actions/contact-actions/contactActions.tsx` by correcting the `assignClientPortalVisibilityGroupToContact` `withAuth(...)` export terminator from `};` to `});`.
|
|
- (2026-03-15) Flipped checklists for F014/F015/F016/F017/F018/F021 and T018/T019/T020/T021/T022/T023/T024/T025/T027/T028/T029/T030/T031/T032/T035/T036/T038 to `true` after visibility-focused test verification.
|
|
|
|
## Commands / Runbooks
|
|
|
|
- (2026-03-15) Search client portal ticket entry points:
|
|
`rg -n "client.*ticket|portal.*ticket|get.*ticket|list.*ticket" packages/client-portal server/src/app/client-portal packages/portal-shared --glob '!node_modules'`
|
|
- (2026-03-15) Search portal/contact admin surfaces:
|
|
`rg -n "portal admin|portal invitation|contact.*portal|contact.*user" packages server --glob '!node_modules'`
|
|
- (2026-03-15) Inspect client portal locale coverage:
|
|
`find server/public/locales -maxdepth 2 -name 'client-portal.json' | sort`
|
|
- (2026-03-15) Run targeted migration/resolver tests from the server Vitest root:
|
|
`cd server && npx vitest run src/test/unit/migrations/clientPortalVisibilityGroupsMigration.test.ts ../packages/tickets/src/lib/clientPortalVisibility.test.ts`
|
|
- (2026-03-15) Run targeted ticket/dashboard visibility tests from the server Vitest root:
|
|
`cd server && npx vitest run ../packages/client-portal/src/actions/client-portal-actions/client-tickets.visibility.test.ts ../packages/client-portal/src/actions/client-portal-actions/dashboard.visibility.test.ts`
|
|
- (2026-03-15) Run targeted ticket-form/dialog visibility tests from the server Vitest root:
|
|
`cd server && npx vitest run ../packages/tickets/src/actions/ticketFormActions.clientPortalVisibility.test.ts ../packages/client-portal/src/components/tickets/ClientAddTicket.visibility.test.tsx`
|
|
- (2026-03-15) Run client portal admin/localization visibility tests from the server Vitest root:
|
|
`cd server && npx vitest run ../packages/client-portal/src/actions/client-portal-actions/visibilityGroupActions.test.ts ../packages/client-portal/src/components/settings/visibilityGroupsLocales.test.ts`
|
|
- (2026-03-15) Run MSP visibility group tests from the server Vitest root:
|
|
`cd server && npx vitest run ../packages/clients/src/actions/contact-actions/visibilityGroupActions.permission.test.ts ../packages/clients/src/actions/contact-actions/visibilityGroupActions.integration.test.ts ../packages/clients/src/components/contacts/ContactPortalTab.visibilityGroups.test.tsx`
|
|
- (2026-03-15) Run lifecycle visibility tests from the server Vitest root:
|
|
`cd server && npx vitest run ../packages/tickets/src/lib/clientPortalVisibility.userModelLifecycle.test.ts`
|
|
- (2026-03-15) Consolidated visibility-focused regression run from the server Vitest root:
|
|
`cd server && npx vitest run src/test/unit/migrations/clientPortalVisibilityGroupsMigration.test.ts ../packages/tickets/src/lib/clientPortalVisibility.test.ts ../packages/tickets/src/lib/clientPortalVisibility.userModelLifecycle.test.ts ../packages/client-portal/src/actions/client-portal-actions/client-tickets.visibility.test.ts ../packages/client-portal/src/actions/client-portal-actions/dashboard.visibility.test.ts ../packages/tickets/src/actions/ticketFormActions.clientPortalVisibility.test.ts ../packages/client-portal/src/components/tickets/ClientAddTicket.visibility.test.tsx ../packages/client-portal/src/actions/client-portal-actions/visibilityGroupActions.test.ts ../packages/client-portal/src/components/settings/visibilityGroupsLocales.test.ts ../packages/clients/src/actions/contact-actions/visibilityGroupActions.permission.test.ts ../packages/clients/src/actions/contact-actions/visibilityGroupActions.integration.test.ts ../packages/clients/src/components/contacts/ContactPortalTab.visibilityGroups.test.tsx`
|
|
|
|
## Links / References
|
|
|
|
- [client-tickets.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/client-portal/src/actions/client-portal-actions/client-tickets.ts)
|
|
- [ContactPortalTab.tsx](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/clients/src/components/contacts/ContactPortalTab.tsx)
|
|
- [contactActions.tsx](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/clients/src/actions/contact-actions/contactActions.tsx)
|
|
- [clientUserActions.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/client-portal/src/actions/client-portal-actions/clientUserActions.ts)
|
|
- [client-portal.json](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/server/public/locales/en/client-portal.json)
|
|
- [clientPortalVisibility.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/tickets/src/lib/clientPortalVisibility.ts)
|
|
- [clientPortalVisibility.test.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/tickets/src/lib/clientPortalVisibility.test.ts)
|
|
- [clientPortalVisibilityGroupsMigration.test.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/server/src/test/unit/migrations/clientPortalVisibilityGroupsMigration.test.ts)
|
|
- [client-tickets.visibility.test.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/client-portal/src/actions/client-portal-actions/client-tickets.visibility.test.ts)
|
|
- [dashboard.visibility.test.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/client-portal/src/actions/client-portal-actions/dashboard.visibility.test.ts)
|
|
- [ticketFormActions.clientPortalVisibility.test.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/tickets/src/actions/ticketFormActions.clientPortalVisibility.test.ts)
|
|
- [ClientAddTicket.visibility.test.tsx](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/client-portal/src/components/tickets/ClientAddTicket.visibility.test.tsx)
|
|
- [visibilityGroupActions.test.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/client-portal/src/actions/client-portal-actions/visibilityGroupActions.test.ts)
|
|
- [visibilityGroupsLocales.test.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/client-portal/src/components/settings/visibilityGroupsLocales.test.ts)
|
|
- [ContactPortalTab.visibilityGroups.test.tsx](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/clients/src/components/contacts/ContactPortalTab.visibilityGroups.test.tsx)
|
|
- [visibilityGroupActions.integration.test.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/clients/src/actions/contact-actions/visibilityGroupActions.integration.test.ts)
|
|
- [clientPortalVisibility.userModelLifecycle.test.ts](/Users/roberisaacs/alga-psa.worktrees/test/portal-user-ticket-visibility/packages/tickets/src/lib/clientPortalVisibility.userModelLifecycle.test.ts)
|
|
|
|
## Open Questions
|
|
|
|
- Should the client portal admin UI live under account/settings or under a dedicated administration route?
|
|
- Should the PSA-side group CRUD live only in the contact portal tab, or also at the client level?
|