Hermes 284313f908
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
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

62 KiB

Scratchpad — Board-Specific Ticket Statuses

  • Plan slug: board-specific-ticket-statuses
  • Created: 2026-03-14

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-14) Scope is ticket statuses only. Project, interaction, and project-task statuses stay unchanged in this phase.
  • (2026-03-14) Ticket statuses will use separate board-owned records, not board-level overrides on top of tenant-global statuses.
  • (2026-03-14) Keep the existing statuses table and add board ownership for ticket statuses instead of introducing a second ticket-status table.
  • (2026-03-14) Migration must clone current tenant-wide ticket statuses onto every board and generate new board-owned status_id values.
  • (2026-03-14) Saved ticket-status references should be automatically remapped where board context exists.
  • (2026-03-14) Changing a ticket board must require explicit user status reselection. No runtime auto-remap.
  • (2026-03-14) New board creation must let admins either copy statuses from an existing board or create statuses inline.
  • (2026-03-14) Ticket board changes are now blocked in both backend update paths and the TicketInfo UI until the user explicitly selects a destination-board status, which prevents the old board's status from being silently retained.
  • (2026-03-14) New board creation now has an explicit copy-source board picker; save passes copy_ticket_statuses_from_board_id into createBoard, and the action clones board-owned ticket statuses with fresh ids onto the new board.
  • (2026-03-14) Board create now supports a status_seed_mode switch. In create_inline mode the dialog carries an unsaved inline_ticket_statuses array and sends it to createBoard as explicit board-owned status rows.
  • (2026-03-14) F001/F002: add statuses.board_id as nullable first, then enforce ticket ownership after clone/remap. Rationale: current tenant-global ticket rows must survive until the data migration rewrites them.
  • (2026-03-14) F003/F004/F005: keep the legacy tenant-global ticket status rows in place for now and clone from them during migration, because later remap steps still need the old ids to rewrite inbound, billing, and workflow references before the global rows can be retired.
  • (2026-03-14) F006/F007/F008: remap saved status references by joining legacy global ticket statuses to their board-owned clones via tenant + board_id + status name. Rationale: the old global status ids remain available during migration, so we can rewrite board-context tables without persisting a separate remap table.
  • (2026-03-14) T003/T004/T005/T006: cover the clone/remap migration with a DB-backed integration fixture that seeds one tenant, two boards, two legacy ticket statuses, and board-specific tickets before invoking the migration directly.
  • (2026-03-14) F006/F007/F008: remap inbound defaults, tenant billing renewal defaults, and contract renewal overrides by joining cloned ticket statuses back to the legacy status name within the saved board context.
  • (2026-03-14) T007/T008/T009: cover board-context remaps with a DB-backed integration fixture that runs the clone migration first, then asserts each persisted configuration surface moves from the legacy global status id to the correct board-owned replacement.
  • (2026-03-14) F025 was too broad once Quick Add landed: narrowed it to the already-shipped Quick Add board-scoped status work, then split follow-up work into F043 (bulk update surfaces) and F044 (auxiliary ticket creation helpers). Rationale: there is no standalone bulk ticket status edit UI in this branch today, so the remaining work needs separate traceable items instead of one mixed feature.
  • (2026-03-14) F028/F029/F030: workflow ticket status handling now uses saved board context end-to-end. Authoring pickers depend on fixed board_id or ticket_id, create/update runtime paths reject cross-board statuses before calling shared ticket writes, and tickets.close resolves the closed status from the ticket's own board. Rationale: workflow actions were one of the last places still capable of surfacing or persisting tenant-global ticket status assumptions.
  • (2026-03-14) F032/F033: public ticket status APIs now expose board-owned ticket statuses only. /api/v1/tickets/statuses honors optional board_id and always excludes legacy board-less ticket rows, while generic /api/v1/statuses requires board_id for type=ticket, hides legacy ticket rows by id, and the old shared reference-data status CRUD rejects ticket status mutation in favor of board-local status actions.
  • (2026-03-14) F034: join-heavy ticket reads were mostly already safe because they join on status_id, but two board-owned regressions remained:
    • TicketService.search(...) did not project ticket status metadata at all, so search callers could not reliably see the board-owned status state.
    • TicketService.getTicketStats(...) grouped counts by status_name, which collapses distinct board-owned statuses that reuse the same label.
  • (2026-03-14) F027: treat billing renewal ticket status persistence the same way as other board-scoped ticket status saves. Rationale: tenant defaults and contract overrides both already persist board_id + status_id, so the safest implementation is to share the same board/status compatibility guard instead of trusting UI state alone.
  • (2026-03-14) F037: onboarding and standard reference-data ticket-status imports should enforce board scope at the action boundary, not just in the onboarding UI. Rationale: the import helper is reused outside onboarding, so board ownership has to be written and validated in the shared importer as well.
  • (2026-03-14) F038 keeps standard_statuses unchanged. Rationale: that table is template/reference data, not the live statuses rows used by ticket runtime validation, so only real seed/fixture writers needed board scoping changes.

Discoveries / Constraints

  • (2026-03-14) Current ticket status actions are tenant-global:
    • packages/reference-data/src/actions/status-actions/statusActions.ts
    • packages/tickets/src/models/status.ts
    • server/src/app/api/v1/tickets/statuses/route.ts
  • (2026-03-14) Board management and ticket status management are currently split across:
    • server/src/components/settings/general/BoardsSettings.tsx
    • server/src/components/settings/general/StatusSettings.tsx
  • (2026-03-14) Ticket default status helpers currently resolve tenant-wide ticket defaults with no board input:
    • shared/models/ticketModel.ts
    • packages/client-portal/src/actions/client-portal-actions/client-tickets.ts
  • (2026-03-14) Workflow ticket operations and pickers persist raw ticket status_id values and currently validate only against tenant + status id:
    • shared/workflow/runtime/actions/businessOperations/tickets.ts
    • shared/workflow/runtime/actions/registerEmailWorkflowActions.ts
    • server/src/components/workflow-designer/WorkflowActionInputFixedPicker.tsx
  • (2026-03-14) Billing renewal defaults store both board and status ids already, which makes them a good candidate for automatic remap:
    • packages/billing/src/actions/billingSettingsActions.ts
    • packages/billing/src/actions/renewalsQueueActions.ts
    • server/src/lib/jobs/handlers/processRenewalQueueHandler.ts
  • (2026-03-14) There is no standalone bulk ticket status edit surface in the current ticket dashboard branch; the only ticket bulk action present right now is bulk delete. That means T032 needs either a future implementation surface or a scoped plan update, not a false claim of coverage.
  • (2026-03-14) There is no repo-backed UI yet that edits default_billing_settings.renewal_ticket_board_id / renewal_ticket_status_id or the contract-level renewal ticket routing overrides. F027 is therefore currently blocked on a missing settings surface, even though the underlying persistence columns and queue/runtime readers exist.
  • (2026-03-14) Onboarding ticketing had drifted from the current board schema:
    • configureTicketing(...) still inserted boards using legacy email / is_active fields, while current board creation in this branch uses the newer board shape and may expose only is_inactive.
    • The onboarding fix now introspects boards columns before insert so board creation works against the current schema while still attaching board-owned statuses immediately afterward.
  • (2026-03-14) The earlier F027 blocker was stale on this branch:
    • tenant billing settings can now host a renewal automation card,
    • contract assignment renewal overrides already have an edit surface in ContractDetail.tsx,
    • the missing piece was board-scoped status loading and save-time validation.
  • (2026-03-14) Dev seed fallout for board-owned ticket statuses was narrower than the initial grep suggested:
    • active runtime seeds needed changes in server/seeds/dev/07_statuses.cjs, server/seeds/dev/14_tickets.cjs, server/seeds/dev/66_asset_tickets.cjs, and server/seeds/dev/80_default_inbound_ticket_defaults.cjs
    • server/seeds/dev/58_populate_standard_statuses.cjs stayed unchanged because it seeds template/reference rows, not live statuses
  • (2026-03-14) Completed F027 by scoping billing renewal ticket statuses to the selected board:
    • packages/billing/src/components/settings/billing/RenewalAutomationSettings.tsx adds a tenant renewal automation card with board-first ticket status selection and clears stale statuses when the board changes.
    • packages/billing/src/actions/billingSettingsActions.ts now rejects renewal ticket status saves when the status does not belong to the selected board.
    • shared/billingClients/clientContracts.ts now applies the same guard to contract assignment create/update paths, and packages/billing/src/components/billing-dashboard/contracts/ContractDetail.tsx exposes board-scoped renewal ticket board/status controls for per-assignment overrides.
  • (2026-03-14) Completed T035 with focused billing coverage:
    • packages/billing/tests/RenewalAutomationSettings.boardScopedStatuses.test.tsx verifies tenant billing renewal settings only load statuses for the selected board, disable status selection until a board is chosen, and clear stale status values on board change before save.
    • packages/billing/tests/billingSettingsActions.boardScopedRenewalStatus.test.ts verifies save-time validation rejects a stale cross-board renewal status pair.
    • shared/billingClients/__tests__/clientContracts.boardScopedRenewalStatus.test.ts covers the shared contract-assignment guard so per-contract renewal overrides cannot persist mismatched board/status ids.
  • (2026-03-14) SLA, notifications, surveys, and client portal ticket flows all resolve ticket statuses directly by status_id, so they are migration-sensitive:
    • packages/sla/src/services/slaPauseService.ts
    • server/src/lib/eventBus/subscribers/internalNotificationSubscriber.ts
    • server/src/lib/eventBus/subscribers/surveySubscriber.ts
    • packages/client-portal/src/actions/client-portal-actions/client-tickets.ts
  • (2026-03-14) packages/tickets/src/components/ticket/TicketInfo.tsx already carries pending board/category state locally, so F014 could be implemented by clearing pendingChanges.status_id on board change and disabling save until the new board gets a status.
  • (2026-03-14) packages/tickets/src/actions/board-actions/boardActions.ts can own status seeding for board create because it already centralizes transactional board creation and ITIL setup.
  • (2026-03-14) The copy path and inline path can coexist cleanly if copy remains the default status_seed_mode; that keeps F015 green while adding F016 without forcing a broader board-edit refactor.
  • (2026-03-14) Current schema still enforced tenant-global ticket status uniqueness before this batch:
    • server/migrations/202409101116_add_status_constraints.cjs
    • packages/types/src/interfaces/status.interface.ts
  • (2026-03-14) Ticket board-change UX still remains incomplete after the shared update-path validation fix:
    • shared/models/ticketModel.ts
    • packages/tickets/src/actions/ticketActions.ts
    • packages/tickets/src/actions/optimizedTicketActions.ts
    • server/src/lib/api/services/TicketService.ts
  • (2026-03-14) Board settings and board actions do not yet seed or manage board-local ticket statuses:
    • packages/tickets/src/actions/board-actions/boardActions.ts
    • server/src/components/settings/general/BoardsSettings.tsx
  • (2026-03-14) Saved config with explicit board context now has a direct migration path:
    • inbound_ticket_defaults.board_id + status_id
    • default_billing_settings.renewal_ticket_board_id + renewal_ticket_status_id
    • client_contracts.renewal_ticket_board_id + renewal_ticket_status_id
  • (2026-03-14) Postgres migration gotcha: in UPDATE ... FROM, the target table alias cannot be referenced inside the joined table ON clause the way a regular join can. The board-column predicate for the board-context remap migration needs to live in the outer WHERE clause instead.
  • (2026-03-14) F009/F010 are the first non-tabular migration slice:
    • workflow ticket board/status references live inside workflow_definitions.draft_definition and workflow_definition_versions.definition_json
    • ticket board/status values can appear as fixed literals or dynamic inputMapping expressions in action configs, so safe remap/surfacing needs JSON traversal and explicit unresolved detection rather than a single SQL join
  • (2026-03-14) Completed F009 with a workflow JSON remap migration:
    • server/migrations/20260314130000_remap_workflow_ticket_status_references.cjs traverses workflow v2 steps recursively and rewrites fixed literal status_id values only when a fixed literal board_id is present in the same saved payload.
    • The remap runs against both workflow_definitions.draft_definition and workflow_definition_versions.definition_json.
    • Because workflow tables do not carry tenant, the migration derives the legacy-to-board-owned mapping from statuses rows using tenant + name and applies it via saved board_id + status_id pairs.
  • (2026-03-14) Completed T010 with DB-backed coverage in server/src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts:
    • verifies tickets.create, create_ticket_from_email, and nested ticketDefaults.status_id inside create_ticket_with_initial_comment all remap in both workflow drafts and published versions
    • reran with cd server && npx vitest run --coverage.enabled false src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts; the suite now passes with 9 migration tests after the later T011 guard was added
  • (2026-03-14) Completed F010 with an explicit unresolved-reference guard:
    • server/migrations/20260314133000_surface_unresolved_ticket_status_references.cjs scans workflow drafts and published versions for fixed legacy ticket status_id values that still lack literal board context.
    • The guard throws a migration error containing the workflow id, table, step path, action id, and input path so unresolved references are surfaced before release instead of guessed.
  • (2026-03-14) Completed T011 in server/src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts:
    • seeds a workflow tickets.update_fields step with fixed legacy patch.status_id and no board context
    • verifies the guard migration rejects with a concrete unresolved-reference message and leaves the stored status id unchanged
    • reran with cd server && npx vitest run --coverage.enabled false src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts and confirmed all 9 migration tests pass
  • (2026-03-14) Completed F011 by making ticket default resolution board-aware in shared ticket creation paths:
    • shared/models/ticketModel.ts now resolves a default ticket status only for the selected board_id and no longer falls back to tenant-global ticket statuses.
    • packages/client-portal/src/actions/client-portal-actions/client-tickets.ts now asks TicketModel.getDefaultStatusId(...) for the default status tied to the client portal's default board instead of querying tenant-global ticket defaults directly.
  • (2026-03-14) Completed F012 by enforcing board/status compatibility on ticket creation:
    • shared/models/ticketModel.ts now validates that a provided ticket status_id belongs to the selected board_id before insert.
    • TicketModel.createTicket(...) now auto-fills the selected board's default status when callers omit status_id, and rejects create attempts when no board-local default exists.
  • (2026-03-14) Completed T012 and T013 with shared unit coverage in shared/models/__tests__/ticketModel.boardStatusValidation.test.ts:
    • T012 proves getDefaultStatusId returns the selected board's default instead of a legacy tenant-global default.
    • T013 proves create-time business rule validation rejects a status from a different board.
    • verified with cd shared && npx vitest run models/__tests__/ticketModel.boardStatusValidation.test.ts --config vitest.config.ts.
  • (2026-03-14) Completed T014 with DB-backed create-path coverage in server/src/test/integration/ticketCreateBoardStatusValidation.integration.test.ts:
    • seeds two boards with distinct board-owned ticket statuses and proves TicketModel.createTicket(...) inserts only for the matching board/status pair
    • verifies the cross-board create attempt throws and leaves only the valid ticket row persisted
    • verified with cd server && npx vitest run --coverage.enabled false src/test/integration/ticketCreateBoardStatusValidation.integration.test.ts.
  • (2026-03-14) Completed F013 by enforcing board/status compatibility on ticket update paths:
    • shared/models/ticketModel.ts now validates update-time status_id changes against the effective board for the ticket.
    • packages/tickets/src/actions/ticketActions.ts, packages/tickets/src/actions/optimizedTicketActions.ts, and server/src/lib/api/services/TicketService.ts now all reject cross-board ticket status updates instead of validating ticket statuses at tenant scope only.
  • (2026-03-14) Completed T015 in shared/models/__tests__/ticketModel.boardStatusValidation.test.ts:
    • proves TicketModel.updateTicket(...) rejects a status-only update when the new status belongs to a different board
    • verified with cd shared && npx vitest run models/__tests__/ticketModel.boardStatusValidation.test.ts --config vitest.config.ts.
  • (2026-03-14) Completed T016 with DB-backed update coverage in server/src/test/integration/ticketCreateBoardStatusValidation.integration.test.ts:
    • proves TicketModel.updateTicket(...) rejects a cross-board status id and leaves the persisted ticket's prior status untouched
    • verified with cd server && npx vitest run --coverage.enabled false src/test/integration/ticketCreateBoardStatusValidation.integration.test.ts.
  • (2026-03-14) Completed F017/F018/F021 by moving board-local ticket lifecycle editing into board create/edit:
    • server/src/components/settings/general/BoardsSettings.tsx now manages ticket statuses in both create-inline and edit flows, including add/remove/reorder/open-closed/default operations.
    • Save is blocked until the managed board-local status set contains exactly one open default, which keeps board create and board edit aligned with the PRD's required lifecycle invariant.
  • (2026-03-14) Completed F019 by retiring the old central ticket status settings surface:
    • server/src/components/settings/general/StatusSettings.tsx now renders an informational handoff to Boards instead of acting as a tenant-global ticket status editor.
  • (2026-03-14) Completed F020 with board-scoped ticket status actions and model reads:
    • packages/tickets/src/models/status.ts now exposes board-scoped ticket status lookup helpers.
    • packages/tickets/src/actions/board-actions/boardTicketStatusActions.ts now owns board-local ticket status reads plus create/update/delete/save operations, and explicitly rejects implicit cross-board mutation.
  • (2026-03-14) Completed T020/T021/T022/T023/T024/T025/T026 with focused UI and action coverage:
    • server/src/components/settings/general/BoardsSettings.copyStatuses.test.tsx now covers create-time lifecycle validation and board-edit status loading.
    • server/src/components/settings/general/StatusSettings.ticketStatusesRetired.test.tsx verifies the central status surface is informational only.
    • packages/tickets/src/actions/board-actions/boardTicketStatusActions.test.ts verifies board-local create/update/delete/default rules and duplicate-name scoping.
  • (2026-03-14) Completed F022/F023/F024 by making ticket status options board-dependent in both create and edit ticket flows:
    • packages/reference-data/src/actions/status-actions/statusActions.ts now accepts an optional boardId for ticket-status lookups.
    • packages/tickets/src/components/QuickAddTicket.tsx now leaves status options empty until a board is chosen, then fetches that board's statuses and selects only that board's default.
    • packages/tickets/src/components/ticket/TicketInfo.tsx now reloads status options from the currently selected board and disables the picker when no board is in scope.
  • (2026-03-14) Completed T027/T028/T029/T030 with focused picker coverage:
    • packages/tickets/src/components/ticket/__tests__/TicketInfo.boardChangeStatusReselection.test.tsx now verifies board-scoped option loading, empty/disabled state with no board, and board-change option reloading.
    • packages/tickets/src/components/__tests__/QuickAddTicket.boardScopedStatuses.test.tsx verifies create flow status pickers stay empty until a board is selected and then choose that board's default.
  • (2026-03-14) Completed F026 by making inbound ticket defaults board-scoped for statuses:
    • packages/integrations/src/components/email/forms/InboundTicketDefaultsForm.tsx now clears status_id when the board changes, disables the status picker until a board is chosen, and reloads only that board's statuses via getAvailableStatuses(boardId).
    • packages/integrations/src/actions/email-actions/ticketFieldOptionsActions.ts now exposes getAvailableStatuses(boardId) as a board-filtered ticket-status lookup for inbound-email setup.
    • packages/integrations/src/actions/email-actions/inboundTicketDefaultsActions.ts now rejects saves where status_id does not belong to the selected board_id.
  • (2026-03-14) Completed T034 in server/src/test/unit/components/InboundTicketDefaultsForm.test.tsx:
    • verifies inbound ticket defaults keep the status picker disabled until a board is selected
    • verifies the form requests only the selected board's statuses and clears a stale status when the board changes
    • reran with cd server && npx vitest run --coverage.enabled false src/test/unit/components/InboundTicketDefaultsForm.test.tsx --config vitest.config.ts
  • (2026-03-14) Completed F031 by scoping client portal ticket status flows to the ticket board:
    • packages/client-portal/src/actions/client-portal-actions/client-tickets.ts now rejects client-portal status updates when the requested status_id does not belong to the ticket's board_id.
    • server/src/app/client-portal/tickets/[ticketId]/page.tsx now preloads only the selected ticket board's statuses for the standalone details page.
    • packages/client-portal/src/components/tickets/TicketList.tsx now fetches board-owned status menus per ticket board so the list's status-change dropdown stops offering cross-board choices.
  • (2026-03-14) Completed F036/T049/T050 by tightening downstream subscriber coverage and remapping saved survey trigger status filters:
    • server/migrations/20260314135000_remap_survey_trigger_ticket_status_references.cjs now rewrites legacy ticket survey_triggers.trigger_conditions.status_id values to board-owned ticket status ids using the saved board_id filter when present, and deterministically expands across all cloned boards when the trigger was intentionally board-agnostic.
    • server/src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts now covers survey trigger remap persistence for migrated board-specific ticket statuses.
    • server/src/test/integration/internal-notifications/eventSubscribers.integration.test.ts now proves ticket update notifications still resolve old/new board-owned status names, and its query stub now supports the whereNotNull calls used by the subscriber's assignee lookup.
  • (2026-03-14) Completed F037 by moving onboarding and standard ticket-status imports to board-owned creation:
    • packages/reference-data/src/actions/referenceDataActions.ts now requires board_id when importing ticket statuses, writes it onto imported rows, and scopes duplicate/default/order conflict checks to the target board.
    • packages/onboarding/src/actions/onboarding-actions/onboardingActions.ts now requires a board before saving onboarding ticket statuses, writes new statuses with board_id, validates the default status on the default board, returns only the active board's ticket statuses to onboarding state, and creates boards using the current schema columns instead of assuming legacy email / is_active fields exist.
    • packages/onboarding/src/components/steps/TicketingConfigStep.tsx now loads standard ticket statuses only when a board is in scope, imports them with board_id, and uses board-local ticket status actions for manual creation and default changes.
  • (2026-03-14) Completed T051/T052 in server/src/test/integration/onboardingBoardTicketStatuses.integration.test.ts:
    • proves configureTicketing(...) creates only board-owned ticket statuses for the onboarding-created board and leaves a valid board-local default status behind
    • proves importReferenceData('statuses', ..., { item_type: 'ticket', board_id }) writes ticket statuses only to the target board and does not treat the same ticket status name on another board as a conflict
    • reran with cd server && npx vitest run --coverage.enabled false src/test/integration/onboardingBoardTicketStatuses.integration.test.ts --config vitest.config.ts
  • (2026-03-14) Completed F038 by moving shared seeds, fixtures, and workflow harness setup to board-owned ticket statuses:
    • server/src/test/e2e/utils/e2eTestSetup.ts and server/src/test/e2e/fixtures/test-setup.ts now create a default board before ticket statuses, write board_id on seeded ticket statuses, and clean up statuses before boards.
    • server/seeds/dev/07_statuses.cjs now clones the seeded ticket lifecycle onto every seeded board instead of inserting one tenant-global ticket status list.
    • server/seeds/dev/14_tickets.cjs, server/seeds/dev/66_asset_tickets.cjs, and server/seeds/dev/80_default_inbound_ticket_defaults.cjs now resolve ticket statuses from the relevant board.
    • ee/test-data/workflow-harness/_lib/biz-fixture.cjs plus the inline ticket workflow fixtures now select ticket statuses by tenant + board_id.
  • (2026-03-14) Completed T053 in server/src/test/e2e/utils/utilities.test.ts:
    • verifies the shared e2e environment creates ticket statuses only on the default board and still preserves a valid default status
    • reran with cd server && npx vitest run --coverage.enabled false src/test/e2e/utils/utilities.test.ts -t "T053" --config vitest.config.ts
  • (2026-03-14) Completed T054 in server/src/test/integration/workflowWorkerV2.inboundEmailSmoke.integration.test.ts:
    • verifies the workflow smoke fixture resolves a ticket status from the seeded board-owned status set
    • reran with cd server && npx vitest run --coverage.enabled false src/test/integration/workflowWorkerV2.inboundEmailSmoke.integration.test.ts -t "T054" --config vitest.config.ts
  • (2026-03-14) Completed F039 as a plan close-out because the existing migration DB integration suite already covers both required cases:
    • server/src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts already contains the multi-board clone/remap happy path (T003) and the unresolved no-board-context guard (T011)
    • T055/T056 therefore map to existing coverage rather than requiring a new migration suite
  • (2026-03-14) Completed T055/T056 by revalidating the existing migration integration suite:
    • reran the targeted happy-path and guard cases in server/src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts
    • confirmed the suite already proves both clone/remap correctness and explicit unresolved-reference surfacing
  • (2026-03-14) Completed F040 as a plan close-out because the existing UI/component coverage already exercises the required board-local status management and board-change reselection behavior:
    • server/src/components/settings/general/BoardsSettings.copyStatuses.test.tsx covers board create/edit lifecycle rules and board-local status editing
    • packages/tickets/src/components/ticket/__tests__/TicketInfo.boardChangeStatusReselection.test.tsx covers explicit status reselection after a board change
  • (2026-03-14) Completed F041 as a plan close-out because the existing migration, billing, and workflow suites already prove remapped saved configuration still resolves under board-owned statuses:
    • server/src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts covers billing and workflow remap persistence (T008/T009/T010/T011)
    • shared/workflow/runtime/actions/__tests__/ticketWorkflowBoardStatusRuntime.test.ts and packages/billing/tests/*.boardScoped* cover runtime/use-site validation after remap
  • (2026-03-14) Completed F042 as a plan close-out because the existing API and client portal suites already cover the board-scoped lookup and validation regressions:
    • server/src/test/unit/api/ticketStatusesRoute.boardScope.test.ts and server/src/test/unit/api/statusService.ticketBoardScope.test.ts cover API board scope
    • packages/client-portal/src/actions/client-portal-actions/client-tickets.boardStatusValidation.test.ts covers client portal create/update validation
  • (2026-03-14) Completed F043 as a no-op scope close-out because this branch does not currently contain a ticket bulk-update surface:
    • packages/tickets/src/components/TicketingDashboard.tsx only exposes bulk delete for tickets
    • server/src/test/e2e/api/tickets.e2e.test.ts still treats /api/v1/tickets/bulk-update as optional and accepts 404/405, which confirms there is no shipped bulk ticket status edit path to harden in this branch
  • (2026-03-14) Completed F044 by scoping the remaining auxiliary ticket creation helper to board-owned ticket statuses:
    • packages/assets/src/components/CreateTicketFromAssetButton.tsx now loads ticket statuses only for the active board, clears stale status_id values as soon as the board changes, and disables the status picker when no board is in scope.
    • Project-linked ticket creation did not need new changes because packages/projects/src/components/TaskTicketLinks.tsx already routes through the board-scoped QuickAddTicket flow.
  • (2026-03-14) Completed T033 in packages/assets/src/components/CreateTicketFromAssetButton.boardScopedStatuses.test.tsx:
    • verifies the asset ticket dialog loads statuses with getTicketStatuses(boardId) instead of a tenant-global lookup
    • verifies changing boards swaps the available status options and submit persists only the destination board's status id
    • reran with cd packages/assets && npx vitest run src/components/CreateTicketFromAssetButton.boardScopedStatuses.test.tsx --config vitest.config.ts
  • (2026-03-14) Completed T032 as a no-op scope close-out because there is no ticket bulk-update flow in this branch:
    • packages/tickets/src/components/TicketingDashboard.tsx exposes only bulk delete
    • server/src/test/e2e/api/tickets.e2e.test.ts still treats /api/v1/tickets/bulk-update as optional and accepts 404/405
  • (2026-03-14) Completed T057/T058 via equivalent UI/component coverage already present in the branch:
    • server/src/components/settings/general/BoardsSettings.copyStatuses.test.tsx verifies board create with copied statuses, inline statuses, and board-local status editing
    • packages/tickets/src/components/ticket/__tests__/TicketInfo.boardChangeStatusReselection.test.tsx verifies explicit status reselection after a board change
  • (2026-03-14) Completed T059 via the existing workflow remap and runtime regression suites:
    • server/src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts proves migrated saved workflow status references are remapped onto board-owned status ids
    • shared/workflow/runtime/actions/__tests__/ticketWorkflowBoardStatusRuntime.test.ts and server/src/test/integration/workflowWorkerV2.inboundEmailSmoke.integration.test.ts cover execution against board-owned ticket statuses after remap
  • (2026-03-14) Completed T060 via the existing billing remap and renewal routing regression suites:
    • server/src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts proves tenant and contract renewal defaults remap to board-owned ticket status ids
    • packages/billing/tests/RenewalAutomationSettings.boardScopedStatuses.test.tsx, packages/billing/tests/billingSettingsActions.boardScopedRenewalStatus.test.ts, shared/billingClients/__tests__/clientContracts.boardScopedRenewalStatus.test.ts, and server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts together prove renewal ticket routing keeps using the intended board-owned board/status pair
  • (2026-03-14) Completed T061/T062 via the existing API/service and client portal regression suites:
    • server/src/test/integration/ticketCreateBoardStatusValidation.integration.test.ts proves valid board-owned create/update pairs succeed and cross-board pairs fail without persisting
    • server/src/test/unit/api/ticketStatusesRoute.boardScope.test.ts, server/src/test/unit/api/statusService.ticketBoardScope.test.ts, and packages/client-portal/src/actions/client-portal-actions/client-tickets.boardStatusValidation.test.ts cover the board-scoped lookup and client portal validation paths
  • (2026-03-14) Completed T041/T042 in packages/client-portal/src/actions/client-portal-actions/client-tickets.boardStatusValidation.test.ts:
    • verifies client portal ticket creation resolves the default status from the default board before creating the ticket
    • verifies client portal status updates reject a status from another board and skip the write/event path
    • reran with cd server && npx vitest run --coverage.enabled false ../packages/client-portal/src/actions/client-portal-actions/client-tickets.boardStatusValidation.test.ts --config vitest.config.ts
  • (2026-03-14) Completed F035 for SLA pause config and reporting compatibility with board-owned ticket statuses:
    • server/migrations/20260314134000_remap_sla_pause_ticket_status_configs.cjs clones legacy status_sla_pause_config rows onto each board-owned clone of the matching ticket status name, then deletes the legacy global ticket-status configs.
    • packages/sla/src/actions/slaPauseConfigActions.ts now filters pause configs to board-owned ticket statuses, rejects writes against legacy/global ticket status ids, and exposes board-qualified ticket status options for the SLA settings UI.
    • packages/sla/src/components/SlaPauseSettings.tsx now loads board-owned ticket statuses directly from SLA actions and renders duplicate status names with board context so pause rules stay unambiguous across boards.
    • SLA integration fixtures now seed board-owned ticket statuses in server/src/test/integration/sla/slaPauseService.integration.test.ts and server/src/test/integration/sla/slaReportingService.integration.test.ts, and the reporting suite now includes a same-name cross-board closed/open regression case.
  • (2026-03-14) Completed T047/T048 with focused SLA coverage:
    • server/src/test/unit/components/SlaPauseSettings.boardOwnedStatuses.test.tsx verifies the SLA pause settings UI shows duplicate ticket status names with board labels and saves only the changed board-owned status_id.
    • server/src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts now verifies the SLA pause config migration remaps a legacy ticket status rule onto every board-owned clone.
    • server/src/test/unit/migrations/boardSpecificTicketStatusesMigration.test.ts asserts the SLA pause config remap migration exists and keeps the legacy/global cleanup logic in place.
    • server/src/test/integration/sla/slaPauseConfigActions.integration.test.ts adds regression assertions for rejecting legacy/global ticket status ids and hiding legacy configs from the returned board-owned config list, and the same suite also covers same-name cross-board pause evaluation via distinct board-owned status_id values.
    • DB-backed SLA integration suites are still locally blocked in this shell because the server test database port (127.0.0.1:5438 / ::1:5438) is not reachable and fails with EPERM, so only the unit/component coverage above was rerun here.
  • (2026-03-14) Completed F028 by making workflow ticket status authoring board-aware:
    • shared/workflow/runtime/actions/businessOperations/tickets.ts now declares ticket-status picker dependencies on board_id for tickets.create and ticket_id for tickets.update_fields.
    • ee/server/src/components/workflow-designer/WorkflowActionInputFixedPicker.tsx now resolves ticket-status options from the selected fixed board or from the fixed ticket's board instead of using tenant-global ticket statuses.
    • ee/server/vitest.config.ts now aliases @alga-psa/tickets/* so the EE workflow-designer tests can import ticket actions directly.
  • (2026-03-14) Completed T036 with workflow authoring coverage:
    • shared/workflow/runtime/actions/__tests__/registerTicketActionPickerMetadata.test.ts verifies the real action schemas now export board/ticket dependencies for ticket status pickers.
    • ee/server/src/components/workflow-designer/__tests__/InputMappingEditorPickerFields.test.tsx verifies fixed ticket-status pickers load only the selected board's statuses and can derive board context from a fixed ticket_id.
    • reran with cd shared && npx vitest run workflow/runtime/actions/__tests__/registerTicketActionPickerMetadata.test.ts --config vitest.config.ts
    • reran with cd ee/server && npx vitest run --coverage.enabled false src/components/workflow-designer/__tests__/InputMappingEditorPickerFields.test.tsx --config vitest.config.ts
  • (2026-03-14) Completed F029/F030 in workflow runtime:
    • shared/workflow/runtime/actions/businessOperations/tickets.ts now treats tickets.create.status_id as optional so workflow runs can rely on board-local default status resolution.
    • tickets.create and tickets.update_fields now reject status_id values that do not belong to the effective board before calling shared ticket writes.
    • tickets.close now picks the terminal closed status from the ticket's own board, and closure timestamps use ctx.nowIso() for deterministic runtime behavior.
  • (2026-03-14) Completed T037/T038/T039/T040 in shared/workflow/runtime/actions/__tests__/ticketWorkflowBoardStatusRuntime.test.ts:
    • proves workflow create rejects a status from another board
    • proves workflow update rejects a cross-board status patch for the current ticket board
    • proves workflow close resolves a closed status from the ticket's board even when another board has a lower-order closed status
    • proves workflow create returns the selected board's default status when status_id is omitted
    • reran with cd shared && npx vitest run workflow/runtime/actions/__tests__/registerTicketActionPickerMetadata.test.ts workflow/runtime/actions/__tests__/ticketWorkflowBoardStatusRuntime.test.ts --config vitest.config.ts
  • (2026-03-14) Completed F032 by making the ticket statuses API board-aware:
    • server/src/app/api/v1/tickets/statuses/route.ts now filters to status_type='ticket', excludes legacy board-less ticket statuses, and honors optional board_id scope.
  • (2026-03-14) Completed F033 by removing tenant-global ticket behavior from generic status surfaces:
    • server/src/lib/api/schemas/status.ts now requires board_id when querying type=ticket.
    • server/src/lib/api/services/StatusService.ts now filters generic ticket status lists by board_id, excludes board-less ticket rows, and hides legacy board-less ticket statuses in getById.
    • packages/reference-data/src/actions/status-actions/statusActions.ts now filters getStatuses('ticket') to board-owned rows and rejects generic ticket status create/update/delete in favor of board settings.
  • (2026-03-14) Completed T043/T044 with in-process API contract coverage:
    • server/src/test/unit/api/ticketStatusesRoute.boardScope.test.ts verifies /api/v1/tickets/statuses honors board_id and excludes legacy board-less ticket statuses.
    • server/src/test/unit/api/statusService.ticketBoardScope.test.ts verifies generic ticket status queries require board scope, list only board-owned ticket statuses, and hide legacy global ticket statuses by id.
    • reran with cd server && npx vitest run --coverage.enabled false src/test/unit/api/ticketStatusesRoute.boardScope.test.ts src/test/unit/api/statusService.ticketBoardScope.test.ts --config vitest.config.ts
  • (2026-03-14) Completed F034 by aligning ticket list/search/reporting read surfaces with board-owned ticket statuses:
    • server/src/lib/api/services/TicketService.ts search results now project status_name and status_is_closed from the joined board-owned status row.
    • TicketService.getTicketStats(...) now groups status counts by status_id instead of only by status_name, preventing cross-board count collapse when boards reuse the same label.
  • (2026-03-14) Completed T045/T046 in server/src/test/integration/ticketStatusReadSurfaces.integration.test.ts:
    • proves ticket list and search joins return the correct status metadata for tickets on different boards that reuse the same status name
    • proves grouped ticket stats keep counts separated by board-owned status_id instead of collapsing same-name statuses across boards
    • reran with cd server && npx vitest run --coverage.enabled false src/test/integration/ticketStatusReadSurfaces.integration.test.ts --config vitest.config.ts

Commands / Runbooks

  • (2026-03-14) Audit ticket status references:
    • rg -n "status_id|statusIds|ticket-status|renewal_ticket_status_id|inbound.*status_id" server shared ee packages -g '!**/node_modules/**'
  • (2026-03-14) Inspect current board + ticket status settings surfaces:
    • sed -n '1,260p' server/src/components/settings/general/BoardsSettings.tsx
    • sed -n '1,260p' server/src/components/settings/general/StatusSettings.tsx
  • (2026-03-14) Inspect current status actions and APIs:
    • sed -n '1,260p' packages/reference-data/src/actions/status-actions/statusActions.ts
    • sed -n '1,220p' server/src/app/api/v1/tickets/statuses/route.ts
    • sed -n '1,240p' server/src/app/api/v1/statuses/route.ts
  • (2026-03-14) Inspect ticket default resolution:
    • sed -n '1165,1260p' shared/models/ticketModel.ts
  • (2026-03-14) Validate plan artifacts:
    • python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/validate_plan.py ee/docs/plans/2026-03-14-board-specific-ticket-statuses
  • (2026-03-14) Validate board-change status reselection:
    • cd packages/tickets && npx vitest run src/components/ticket/__tests__/TicketInfo.boardChangeStatusReselection.test.tsx --config vitest.config.ts
    • cd shared && npx vitest run models/__tests__/ticketModel.boardStatusValidation.test.ts --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/ticketCreateBoardStatusValidation.integration.test.ts --config vitest.config.ts
  • (2026-03-14) Validate board status copy-on-create:
    • cd server && npx vitest run --coverage.enabled false src/components/settings/general/BoardsSettings.copyStatuses.test.tsx --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/boardCopyTicketStatuses.integration.test.ts --config vitest.config.ts
  • (2026-03-14) Validate inline board status authoring:
    • cd server && npx vitest run --coverage.enabled false src/components/settings/general/BoardsSettings.copyStatuses.test.tsx --config vitest.config.ts
  • (2026-03-14) Run the board-status migration schema tests directly from the server package:
    • cd server && npx vitest run src/test/unit/migrations/boardSpecificTicketStatusesMigration.test.ts
  • (2026-03-14) Repo-level npm run test:local -- ... is currently not usable in this shell because the installed dotenv CLI rejects -e ../.env.localtest as non-boolean.
  • (2026-03-14) Attempt the DB-backed clone/remap migration suite:
    • cd server && npx vitest run --coverage.enabled false src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts
  • (2026-03-14) Attempt the board-context status-reference remap suite:
    • cd server && npx vitest run src/test/integration/boardContextTicketStatusReferenceRemap.integration.test.ts --coverage=false
    • Run it after the clone/remap suite or against a schema that already includes 20260314113000_clone_global_ticket_statuses_to_boards.cjs.
  • (2026-03-14) Run the shared board-status helper tests:
    • cd shared && npx vitest run models/__tests__/ticketModel.boardStatusValidation.test.ts --config vitest.config.ts
  • (2026-03-14) Run the DB-backed ticket create board/status validation test:
    • cd server && npx vitest run --coverage.enabled false src/test/integration/ticketCreateBoardStatusValidation.integration.test.ts
  • (2026-03-14) Validate board-local ticket status management and the retired central status surface:
    • cd packages/tickets && npx vitest run src/actions/board-actions/boardTicketStatusActions.test.ts --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/components/settings/general/BoardsSettings.copyStatuses.test.tsx src/components/settings/general/StatusSettings.ticketStatusesRetired.test.tsx --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/boardCopyTicketStatuses.integration.test.ts --config vitest.config.ts
  • (2026-03-14) Validate board-dependent ticket status pickers:
    • cd packages/tickets && npx vitest run src/components/ticket/__tests__/TicketInfo.boardChangeStatusReselection.test.tsx src/components/__tests__/QuickAddTicket.boardScopedStatuses.test.tsx --config vitest.config.ts
  • (2026-03-14) Validate inbound ticket defaults board-scoped statuses:
    • cd server && npx vitest run --coverage.enabled false src/test/unit/components/InboundTicketDefaultsForm.test.tsx --config vitest.config.ts
  • (2026-03-14) Validate client portal board-scoped status flows:
    • cd server && npx vitest run --coverage.enabled false ../packages/client-portal/src/actions/client-portal-actions/client-tickets.boardStatusValidation.test.ts --config vitest.config.ts
  • (2026-03-14) Validate onboarding board-owned ticket statuses:
    • cd server && npx vitest run --coverage.enabled false src/test/integration/onboardingBoardTicketStatuses.integration.test.ts --config vitest.config.ts
  • (2026-03-14) Validate seed/fixture board-owned ticket status setup:
    • cd server && npx vitest run --coverage.enabled false src/test/e2e/utils/utilities.test.ts -t "T053" --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/workflowWorkerV2.inboundEmailSmoke.integration.test.ts -t "T054" --config vitest.config.ts
  • (2026-03-14) Revalidate the existing migration integration coverage used to close F039:
    • cd server && npx vitest run --coverage.enabled false src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts -t "T003" --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts -t "T011" --config vitest.config.ts
  • (2026-03-14) Revalidate the existing UI/API coverage used to close F040/F042:
    • cd server && npx vitest run --coverage.enabled false src/components/settings/general/BoardsSettings.copyStatuses.test.tsx --config vitest.config.ts
    • cd packages/tickets && npx vitest run src/components/ticket/__tests__/TicketInfo.boardChangeStatusReselection.test.tsx --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/unit/api/ticketStatusesRoute.boardScope.test.ts src/test/unit/api/statusService.ticketBoardScope.test.ts ../packages/client-portal/src/actions/client-portal-actions/client-tickets.boardStatusValidation.test.ts --config vitest.config.ts
  • (2026-03-14) Revalidate the existing workflow/billing coverage used to close F041:
    • cd shared && npx vitest run workflow/runtime/actions/__tests__/registerTicketActionPickerMetadata.test.ts workflow/runtime/actions/__tests__/ticketWorkflowBoardStatusRuntime.test.ts --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false ../packages/billing/tests/billingSettingsActions.boardScopedRenewalStatus.test.ts ../packages/billing/tests/RenewalAutomationSettings.boardScopedStatuses.test.tsx ../packages/billing/tests/ContractDetail.assignmentRenewalSettings.wiring.test.ts --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts --config vitest.config.ts
  • (2026-03-14) Verify whether a ticket bulk-update surface exists before implementing F043:
    • rg -n "bulk[-_ ]update|bulk update|bulkUpdate|bulk_update|/bulk-update|Bulk" packages/tickets server shared ee -g '!**/node_modules/**'
    • sed -n '1,260p' packages/tickets/src/components/TicketingDashboard.tsx
    • sed -n '850,905p' server/src/test/e2e/api/tickets.e2e.test.ts
  • (2026-03-14) Validate asset-linked ticket creation board-scoped statuses:
    • cd packages/assets && npx vitest run src/components/CreateTicketFromAssetButton.boardScopedStatuses.test.tsx --config vitest.config.ts
    • cd packages/assets && npx vitest run --config vitest.config.ts
    • The package-wide assets run still trips the pre-existing contract failure in src/components/QuickAddAsset.quick-add-client.contract.test.ts (open={isQuickAddClientOpen} no longer matches the current quick-add client API shape); the new board-scoped asset ticket test itself passes.
  • (2026-03-14) Revalidate the remaining test checklist close-outs:
    • cd server && npx vitest run --coverage.enabled false src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/ticketCreateBoardStatusValidation.integration.test.ts --config vitest.config.ts
  • (2026-03-14) Validate SLA board-owned pause config and migration coverage:
    • cd server && npx vitest run --coverage.enabled false src/test/unit/components/SlaPauseSettings.boardOwnedStatuses.test.tsx src/test/unit/migrations/boardSpecificTicketStatusesMigration.test.ts --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/sla/slaPauseService.integration.test.ts src/test/integration/sla/slaReportingService.integration.test.ts --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/sla/slaPauseConfigActions.integration.test.ts --config vitest.config.ts
    • In this shell, the broader SLA DB suites are not currently reliable: slaPauseService.integration.test.ts / slaReportingService.integration.test.ts tripped shared DB bootstrap issues (duplicate key value violates unique constraint "pg_database_datname_index" and ROLLBACK - Connection terminated unexpectedly), and slaPauseConfigActions.integration.test.ts still expects a server database plus older priorities.priority_order fixture columns.
  • (2026-03-14) Validate workflow ticket status authoring + runtime:
    • cd shared && npx vitest run workflow/runtime/actions/__tests__/registerTicketActionPickerMetadata.test.ts workflow/runtime/actions/__tests__/ticketWorkflowBoardStatusRuntime.test.ts --config vitest.config.ts
    • cd ee/server && npx vitest run --coverage.enabled false src/components/workflow-designer/__tests__/InputMappingEditorPickerFields.test.tsx --config vitest.config.ts
  • (2026-03-14) Validate API ticket status board scope in-process:
    • cd server && npx vitest run --coverage.enabled false src/test/unit/api/ticketStatusesRoute.boardScope.test.ts src/test/unit/api/statusService.ticketBoardScope.test.ts --config vitest.config.ts
  • (2026-03-14) Validate ticket read/reporting status joins:
    • cd server && npx vitest run --coverage.enabled false src/test/integration/ticketStatusReadSurfaces.integration.test.ts --config vitest.config.ts
  • (2026-03-14) Validate subscriber and survey remap regressions:
    • cd server && npx vitest run --coverage.enabled false src/test/integration/internal-notifications/eventSubscribers.integration.test.ts -t "creates status change notifications for ticket updated events" --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts --config vitest.config.ts
  • (2026-03-14) API e2e harness note:
    • cd server && npx vitest run --coverage.enabled false src/test/e2e/api/ticket-statuses.e2e.test.ts src/test/e2e/api/statuses.e2e.test.ts --config vitest.config.ts
    • In this shell the e2e setup can seed the DB, but the HTTP assertions fail with fetch failed because no server is listening on TEST_API_BASE_URL / http://127.0.0.1:3000.
  • (2026-03-14) Validate billing renewal defaults board-scoped statuses:
    • cd shared && npx vitest run billingClients/__tests__/clientContracts.boardScopedRenewalStatus.test.ts --config vitest.config.ts
    • cd server && npx vitest run --coverage.enabled false ../packages/billing/tests/billingSettingsActions.boardScopedRenewalStatus.test.ts ../packages/billing/tests/RenewalAutomationSettings.boardScopedStatuses.test.tsx ../packages/billing/tests/ContractDetail.assignmentRenewalSettings.wiring.test.ts --config vitest.config.ts
  • (2026-03-14) Legacy Quick Add regression note:
    • cd packages/tickets && npx vitest run src/components/__tests__/ticket-inline-add-prefill.test.tsx --config vitest.config.ts
    • Current failures in that broader suite are mock-assumption mismatches around board-first status loading and unrelated quick-add helper behavior; they are not yet curated as plan items in this pass.
  • Design summary: ee/docs/plans/2026-03-14-board-specific-ticket-statuses-design.md
  • Plan folder: ee/docs/plans/2026-03-14-board-specific-ticket-statuses
  • Board settings UI: server/src/components/settings/general/BoardsSettings.tsx
  • Central ticket status settings UI: server/src/components/settings/general/StatusSettings.tsx
  • Ticket status actions: packages/reference-data/src/actions/status-actions/statusActions.ts
  • Ticket status model: packages/tickets/src/models/status.ts
  • Board actions: packages/tickets/src/actions/board-actions/boardActions.ts
  • Board create copy-source test: server/src/components/settings/general/BoardsSettings.copyStatuses.test.tsx
  • Board status copy integration: server/src/test/integration/boardCopyTicketStatuses.integration.test.ts
  • Board create inline statuses wiring: server/src/components/settings/general/BoardsSettings.tsx
  • Board-local ticket status action layer: packages/tickets/src/actions/board-actions/boardTicketStatusActions.ts
  • Board-local ticket status action tests: packages/tickets/src/actions/board-actions/boardTicketStatusActions.test.ts
  • Retired central ticket status surface: server/src/components/settings/general/StatusSettings.tsx
  • Retired central ticket status test: server/src/components/settings/general/StatusSettings.ticketStatusesRetired.test.tsx
  • Board-scoped status action lookup: packages/reference-data/src/actions/status-actions/statusActions.ts
  • Quick Add board-scoped status test: packages/tickets/src/components/__tests__/QuickAddTicket.boardScopedStatuses.test.tsx
  • Ticket edit board-scoped status test: packages/tickets/src/components/ticket/__tests__/TicketInfo.boardChangeStatusReselection.test.tsx
  • Ticket model default status helper: shared/models/ticketModel.ts
  • Ticket create board/status validation integration: server/src/test/integration/ticketCreateBoardStatusValidation.integration.test.ts
  • Ticket API service: server/src/lib/api/services/TicketService.ts
  • Ticket edit UI: packages/tickets/src/components/ticket/TicketInfo.tsx
  • Ticket edit reselection test: packages/tickets/src/components/ticket/__tests__/TicketInfo.boardChangeStatusReselection.test.tsx
  • Ticket statuses API route: server/src/app/api/v1/tickets/statuses/route.ts
  • Workflow ticket actions: shared/workflow/runtime/actions/businessOperations/tickets.ts
  • Billing renewal defaults: packages/billing/src/actions/billingSettingsActions.ts
  • Inbound ticket defaults form: packages/integrations/src/components/email/forms/InboundTicketDefaultsForm.tsx
  • Inbound ticket defaults actions: packages/integrations/src/actions/email-actions/inboundTicketDefaultsActions.ts
  • Inbound ticket field options actions: packages/integrations/src/actions/email-actions/ticketFieldOptionsActions.ts
  • Inbound ticket defaults test: server/src/test/unit/components/InboundTicketDefaultsForm.test.tsx
  • Client portal ticket actions: packages/client-portal/src/actions/client-portal-actions/client-tickets.ts
  • Client portal board status validation test: packages/client-portal/src/actions/client-portal-actions/client-tickets.boardStatusValidation.test.ts
  • Client portal ticket list UI: packages/client-portal/src/components/tickets/TicketList.tsx
  • Client portal ticket details page: server/src/app/client-portal/tickets/[ticketId]/page.tsx
  • Onboarding ticketing actions: packages/onboarding/src/actions/onboarding-actions/onboardingActions.ts
  • Onboarding ticketing step UI: packages/onboarding/src/components/steps/TicketingConfigStep.tsx
  • Seeded board-owned ticket statuses: server/seeds/dev/07_statuses.cjs
  • Seeded ticket rows with board-owned statuses: server/seeds/dev/14_tickets.cjs
  • Seeded asset-linked ticket rows: server/seeds/dev/66_asset_tickets.cjs
  • Seeded inbound defaults with board-owned statuses: server/seeds/dev/80_default_inbound_ticket_defaults.cjs
  • Shared e2e setup: server/src/test/e2e/utils/e2eTestSetup.ts
  • Simplified e2e fixture setup: server/src/test/e2e/fixtures/test-setup.ts
  • Workflow harness ticket fixture helper: ee/test-data/workflow-harness/_lib/biz-fixture.cjs
  • Seed/fixture board-owned status test: server/src/test/e2e/utils/utilities.test.ts
  • Workflow smoke board-owned status test: server/src/test/integration/workflowWorkerV2.inboundEmailSmoke.integration.test.ts
  • Reference-data ticket import actions: packages/reference-data/src/actions/referenceDataActions.ts
  • Onboarding board-owned status integration test: server/src/test/integration/onboardingBoardTicketStatuses.integration.test.ts
  • Workflow ticket action definitions: shared/workflow/runtime/actions/businessOperations/tickets.ts
  • Workflow ticket picker test: shared/workflow/runtime/actions/__tests__/ticketWorkflowBoardStatusRuntime.test.ts
  • Workflow designer fixed picker: ee/server/src/components/workflow-designer/WorkflowActionInputFixedPicker.tsx
  • Ticket statuses API route: server/src/app/api/v1/tickets/statuses/route.ts
  • Generic status API service: server/src/lib/api/services/StatusService.ts
  • Generic status query schema: server/src/lib/api/schemas/status.ts
  • Ticket statuses route unit test: server/src/test/unit/api/ticketStatusesRoute.boardScope.test.ts
  • Generic status API unit test: server/src/test/unit/api/statusService.ticketBoardScope.test.ts
  • Ticket read/reporting regression test: server/src/test/integration/ticketStatusReadSurfaces.integration.test.ts
  • Billing renewal automation settings UI: packages/billing/src/components/settings/billing/RenewalAutomationSettings.tsx
  • Billing renewal settings action validation: packages/billing/src/actions/billingSettingsActions.ts
  • Contract renewal assignment guard: shared/billingClients/clientContracts.ts
  • Contract renewal assignment edit UI: packages/billing/src/components/billing-dashboard/contracts/ContractDetail.tsx
  • Billing renewal UI test: packages/billing/tests/RenewalAutomationSettings.boardScopedStatuses.test.tsx
  • Billing renewal action test: packages/billing/tests/billingSettingsActions.boardScopedRenewalStatus.test.ts
  • Shared contract renewal validation test: shared/billingClients/__tests__/clientContracts.boardScopedRenewalStatus.test.ts
  • Asset-linked ticket creation helper: packages/assets/src/components/CreateTicketFromAssetButton.tsx
  • Asset-linked ticket board scope regression test: packages/assets/src/components/CreateTicketFromAssetButton.boardScopedStatuses.test.tsx
  • New status schema migration: server/migrations/20260314100000_add_board_ownership_to_ticket_statuses.cjs
  • Migration schema coverage: server/src/test/unit/migrations/boardSpecificTicketStatusesMigration.test.ts
  • Clone/remap migration: server/migrations/20260314113000_clone_global_ticket_statuses_to_boards.cjs
  • Clone/remap DB integration coverage: server/src/test/integration/boardSpecificTicketStatusesMigration.integration.test.ts
  • Board-context status-reference remap migration: server/migrations/20260314120000_remap_board_context_ticket_status_references.cjs
  • Board-context status-reference integration coverage: server/src/test/integration/boardContextTicketStatusReferenceRemap.integration.test.ts
  • Workflow status-reference remap migration: server/migrations/20260314130000_remap_workflow_ticket_status_references.cjs
  • Workflow unresolved-reference guard migration: server/migrations/20260314133000_surface_unresolved_ticket_status_references.cjs
  • Survey trigger status-reference remap migration: server/migrations/20260314135000_remap_survey_trigger_ticket_status_references.cjs

Open Questions

  • (2026-03-14) Which persisted ticket-status references do not currently carry enough board context for a guaranteed automatic remap?