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

20 KiB
Raw Blame History

Scratchpad — Ticket Origin Badge (Internal vs Client Portal vs Inbound Email vs API)

  • Plan slug: 2026-02-09-ticket-origin-badge
  • Created: 2026-02-09

Context Snapshot

  • Existing plan 2026-02-05-ticket-response-source already covers comment-level response source badges; this new scope is ticket creation origin.
  • Ticket creation paths already pass source hints:
    • MSP create: source: 'web_app' in packages/tickets/src/actions/ticketActions.ts
    • Client portal create: source: 'client_portal' in packages/client-portal/src/actions/client-portal-actions/client-tickets.ts
    • Inbound email create: source: 'email' in shared/services/email/processInboundEmailInApp.ts and shared/workflow/actions/emailWorkflowActions.ts
  • API create also sets source: 'api' in server/src/lib/api/services/TicketService.ts.
  • shared/models/ticketModel.ts accepts CreateTicketInput.source, but its ticketSchema does not currently include source (zod parse strips unknown keys), so source hints are not guaranteed to persist via that write path.
  • tickets.email_metadata exists and is reliable signal for inbound-email-created tickets.
  • Current ticket details UIs:
    • MSP: packages/tickets/src/components/ticket/TicketDetails.tsx
    • Client portal: packages/client-portal/src/components/tickets/TicketDetails.tsx

Decisions

  • (2026-02-09) Promote API to first-class ticket origin (api) instead of collapsing under internal.
  • (2026-02-09) Add persisted tickets.ticket_origin to avoid relying solely on heuristics and preserve source fidelity.
  • (2026-02-09) Keep ticket_origin as text (not DB enum) for forward compatibility with future values (for example ai_agent) without schema redesign.
  • (2026-02-09) Origin remains ticket-details-only for this phase.
  • (2026-02-09) Existing per-comment response source badges remain unchanged.

Discoveries / Constraints

  • (2026-02-09) ITicket in packages/types/src/interfaces/ticket.interfaces.ts currently has no ticket origin field.
  • (2026-02-09) MSP and client portal detail queries already join creator user type:
    • MSP: u_creator.user_type as entered_by_user_type
    • Client portal: u_creator.user_type as entered_by_user_type
  • (2026-02-09) Existing badge patterns/components (ResponseStateBadge, ResponseSourceBadge) can be reused stylistically for consistency.
  • (2026-02-09) API ticket creation path already marks source as api, but this is not reliably persisted today due to shared model validation/schema.

Commands / Runbooks

  • (2026-02-09) Inspect plans: ls -la ee/docs/plans
  • (2026-02-09) Read related plan: sed -n '1,220p' ee/docs/plans/2026-02-05-ticket-response-source/PRD.md
  • (2026-02-09) Locate source hints: rg -n "source: 'web_app'|source: 'client_portal'|source: 'email'" packages shared
  • (2026-02-09) Locate API source hint: rg -n "source: 'api'" server/src/lib/api/services/TicketService.ts
  • (2026-02-09) Locate ticket details surfaces:
    • sed -n '1438,1495p' packages/tickets/src/components/ticket/TicketDetails.tsx
    • sed -n '380,500p' packages/client-portal/src/components/tickets/TicketDetails.tsx
  • (2026-02-09) Scaffold plan: python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/scaffold_plan.py "Ticket Origin Badge" --slug ticket-origin-badge
  • ee/docs/plans/2026-02-05-ticket-response-source/PRD.md
  • shared/models/ticketModel.ts
  • packages/types/src/interfaces/ticket.interfaces.ts
  • packages/tickets/src/actions/ticketActions.ts
  • packages/client-portal/src/actions/client-portal-actions/client-tickets.ts
  • shared/services/email/processInboundEmailInApp.ts
  • shared/workflow/actions/emailWorkflowActions.ts
  • server/src/app/api/v1/tickets/route.ts
  • server/src/lib/api/controllers/ApiTicketController.ts
  • server/src/lib/api/services/TicketService.ts
  • packages/tickets/src/components/ticket/TicketDetails.tsx
  • packages/client-portal/src/components/tickets/TicketDetails.tsx
  • packages/tickets/src/components/ResponseSourceBadge.tsx
  • packages/tickets/src/components/ResponseStateBadge.tsx

Open Questions

  • Confirm label copy for internal origin: Created Internally vs Created by MSP.
  • Confirm whether ticket list/table should show origin in this phase.
  • Confirm whether inbound email badge should remain generic or include provider detail.
  • Confirm desired fallback label for unknown future origins (Created via Other vs raw source string).

Implementation Log

  • (2026-02-09) F001 completed: Added canonical ticket origin constants in packages/types/src/interfaces/ticket.interfaces.ts:
    • TICKET_ORIGINS.INTERNAL = 'internal'
    • TICKET_ORIGINS.CLIENT_PORTAL = 'client_portal'
    • TICKET_ORIGINS.INBOUND_EMAIL = 'inbound_email'
  • (2026-02-09) Validation command: npx vitest run packages/types/src/interfaces/barrel.test.ts (fails due to pre-existing unrelated tax.interfaces barrel mismatch).
  • (2026-02-09) F002 completed: Added shared TicketOrigin union type and ITicket.ticket_origin?: TicketOrigin in packages/types/src/interfaces/ticket.interfaces.ts for ticket-level origin typing across packages.
  • (2026-02-09) F003 completed: Added shared resolver getTicketOrigin in packages/tickets/src/lib/ticketOrigin.ts and exported it via packages/tickets/src/lib/index.ts. Resolver precedence is explicit and deterministic: email_metadata -> source hint mapping -> creator user type -> internal fallback.
  • (2026-02-09) F004 completed: getTicketOrigin now gives highest precedence to email_metadata presence and classifies as inbound_email before any source/user-type checks.
  • (2026-02-09) F005 completed: Added explicit source-hint mapping in resolver (email, inbound_email, client_portal, web_app, api, manual, worker, workflow) with canonical outputs (inbound_email, client_portal, internal).
  • (2026-02-09) F006 completed: Resolver falls through to creator user type (creator_user_type / entered_by_user_type / user_type) and classifies client creators as client_portal when no higher-priority signal applies.
  • (2026-02-09) F007 completed: Resolver default return is internal, providing deterministic legacy fallback when email/source/creator signals are absent or unknown.
  • (2026-02-09) F008 completed: Updated packages/tickets/src/actions/ticketActions.ts#getTicketById to:
    • join creator user (u_creator.user_type as entered_by_user_type),
    • derive ticket_origin via getTicketOrigin(ticket),
    • include ticket_origin on DetailedTicket payload returned to MSP details UI.
  • (2026-02-09) F009 completed: Updated packages/client-portal/src/actions/client-portal-actions/client-tickets.ts#getClientTicketDetails to:
    • join creator user type (u_creator.user_type as entered_by_user_type),
    • derive ticket_origin with shared getTicketOrigin,
    • return sanitized ticket payload with ticket_origin for client portal details.
  • (2026-02-09) Validation command: npx vitest run packages/client-portal/src/actions/client-portal-actions/client-tickets.responseSource.test.ts (fails in existing test mock with Unexpected table: tickets; unrelated to origin derivation path).
  • (2026-02-09) F010 completed: Added reusable TicketOriginBadge in packages/tickets/src/components/TicketOriginBadge.tsx and exported it in packages/tickets/src/components/index.ts. Component supports all three origin states with icon/color variants and size/className props.
  • (2026-02-09) F011 completed: Rendered TicketOriginBadge in MSP ticket header (packages/tickets/src/components/ticket/TicketDetails.tsx) beside ticket number/response-state badge; origin is resolved with shared getTicketOrigin.
  • (2026-02-09) Validation command: npx vitest run packages/tickets/src/components/ticket/__tests__/TicketDetailsCreateTask.test.tsx (fails in current workspace due unresolved legacy alias import @alga-psa/db/models/user from auth package).
  • (2026-02-09) F012 completed: Rendered TicketOriginBadge in client portal ticket details status row (packages/client-portal/src/components/tickets/TicketDetails.tsx), using shared resolver + translated labels.
  • (2026-02-09) F013 completed: Added English common locale keys under server/public/locales/en/common.json:
    • tickets.origin.internal
    • tickets.origin.clientPortal
    • tickets.origin.inboundEmail
  • (2026-02-09) F014 completed: Added matching English client portal locale keys under server/public/locales/en/clientPortal.json for tickets.origin.internal|clientPortal|inboundEmail.
  • (2026-02-09) F015 completed: Final badge copy now consistently uses:
    • Created Internally
    • Created via Client Portal
    • Created via Inbound Email across component defaults + English locale keys.
  • (2026-02-09) Added resolver unit tests packages/tickets/src/lib/__tests__/ticketOrigin.test.ts covering T001T010.
  • (2026-02-09) Added type-contract test packages/types/src/interfaces/ticket.interface.typecheck.test.ts for T011.
  • (2026-02-09) Validation commands:
    • npx vitest run packages/tickets/src/lib/__tests__/ticketOrigin.test.ts
    • npx vitest run packages/types/src/interfaces/ticket.interface.typecheck.test.ts
    • Note: running Vitest in parallel processes with coverage caused transient server/coverage/.tmp/coverage-0.json ENOENT; rerunning sequentially passed.
  • (2026-02-09) Added MSP action tests packages/tickets/src/actions/ticketActions.ticketOrigin.test.ts for T020T023.
  • (2026-02-09) Added client portal action tests packages/client-portal/src/actions/client-portal-actions/client-tickets.ticketOrigin.test.ts for T024T027.
  • (2026-02-09) Validation commands:
    • npx vitest run packages/tickets/src/actions/ticketActions.ticketOrigin.test.ts
    • npx vitest run packages/client-portal/src/actions/client-portal-actions/client-tickets.ticketOrigin.test.ts
    • Note: same transient coverage tmp-folder ENOENT can appear when running concurrent Vitest processes; sequential rerun passes.
  • (2026-02-09) Added badge render contract tests packages/tickets/src/components/TicketOriginBadge.render.test.tsx for T030T033.
  • (2026-02-09) Validation command: npx vitest run packages/tickets/src/components/TicketOriginBadge.render.test.tsx
  • (2026-02-09) Replaced blocked JSdom TicketDetails render tests (module alias resolution issue on @alga-psa/db/models/user) with deterministic contract tests:
    • packages/tickets/src/components/ticket/TicketDetails.originBadge.contract.test.ts (T040, T041, T042, MSP side of T061)
    • packages/client-portal/src/components/tickets/TicketDetails.originBadge.contract.test.ts (T043, T044, T045, client portal side of T061)
  • (2026-02-09) Added locale key tests packages/tickets/src/lib/__tests__/ticketOriginLocales.test.ts (T050, T051).
  • (2026-02-09) Added migration posture test packages/tickets/src/lib/__tests__/ticketOriginMigration.test.ts (T070).
  • (2026-02-09) Added flow sanity tests packages/tickets/src/lib/__tests__/ticketOriginFlowSanity.test.tsx (T080, T081, T082).
  • (2026-02-09) Regression validation reused existing comment-source suite packages/tickets/src/components/ResponseSourceBadge.render.test.tsx for T060.
  • (2026-02-09) Validation commands for this batch (all passed):
    • npx vitest run --coverage.enabled=false packages/tickets/src/lib/__tests__/ticketOriginLocales.test.ts
    • npx vitest run --coverage.enabled=false packages/tickets/src/components/ticket/TicketDetails.originBadge.contract.test.ts
    • npx vitest run --coverage.enabled=false packages/client-portal/src/components/tickets/TicketDetails.originBadge.contract.test.ts
    • npx vitest run --coverage.enabled=false packages/tickets/src/lib/__tests__/ticketOriginMigration.test.ts
    • npx vitest run --coverage.enabled=false packages/tickets/src/lib/__tests__/ticketOriginFlowSanity.test.tsx
    • npx vitest run --coverage.enabled=false packages/tickets/src/components/ResponseSourceBadge.render.test.tsx
  • (2026-02-09) F016 completed: Verified no regressions for comment/source and response-state badges via existing and new regression/contract tests (T060, T061).
  • (2026-02-09) F017 completed: Confirmed migration-free MVP via resolver derivation + migration scan test (T070).
  • (2026-02-09) F018 completed: Added automated coverage for resolver logic, action payloads, badge component, locales, TicketDetails surfaces, and flow sanity (T001T082 plan scope items now covered).
  • (2026-02-09) F001 completed (reconciliation pass): Added api to canonical TICKET_ORIGINS and propagated canonical origin typing updates in @alga-psa/types.
  • (2026-02-09) F002 completed (reconciliation pass): Add shared TicketOrigin type in @alga-psa/types and include api in the union
  • (2026-02-09) F003 completed (reconciliation pass): Add tickets.ticket_origin persisted column (text) via migration
  • (2026-02-09) F004 completed (reconciliation pass): Backfill existing tickets.ticket_origin using legacy signals (email_metadata, creator user_type, fallback internal)
  • (2026-02-09) F005 completed (reconciliation pass): Keep ticket_origin storage extensible for future values (for example ai_agent) without schema redesign
  • (2026-02-09) F006 completed (reconciliation pass): Internal MSP create path writes ticket_origin=internal
  • (2026-02-09) F007 completed (reconciliation pass): Client portal create path writes ticket_origin=client_portal
  • (2026-02-09) F008 completed (reconciliation pass): Inbound email create path writes ticket_origin=inbound_email
  • (2026-02-09) F009 completed (reconciliation pass): API create path writes ticket_origin=api
  • (2026-02-09) F010 completed (reconciliation pass): Update shared TicketModel validation so ticket_origin is preserved and persisted
  • (2026-02-09) F011 completed (reconciliation pass): Implement shared ticket origin normalization/resolver helper with legacy fallback for null historical rows
  • (2026-02-09) F012 completed (reconciliation pass): MSP getTicketById returns normalized ticket_origin for TicketDetails
  • (2026-02-09) F013 completed (reconciliation pass): Client portal getClientTicketDetails returns normalized ticket_origin for TicketDetails
  • (2026-02-09) F014 completed (reconciliation pass): Add shared TicketOriginBadge component with internal/client_portal/inbound_email/api variants and unknown fallback
  • (2026-02-09) F015 completed (reconciliation pass): Render TicketOriginBadge in MSP TicketDetails header near ticket number and response state badge
  • (2026-02-09) F016 completed (reconciliation pass): Render TicketOriginBadge in client portal TicketDetails header/status area
  • (2026-02-09) F017 completed (reconciliation pass): Add locale keys for ticket origin labels including Created via API
  • (2026-02-09) F018 completed (reconciliation pass): Preserve existing comment response-source badge behavior with no regression
  • (2026-02-09) F019 completed (reconciliation pass): Preserve existing response-state badge behavior with no regression
  • (2026-02-09) F020 completed (reconciliation pass): Add automated tests for persistence, backfill, resolver logic, API distinction, and both TicketDetails surfaces
  • (2026-02-09) T001 completed (reconciliation pass): Migration adds tickets.ticket_origin column successfully in existing DB
  • (2026-02-09) T002 completed (reconciliation pass): Newly inserted tickets default ticket_origin to internal when not explicitly provided
  • (2026-02-09) T003 completed (reconciliation pass): Backfill marks tickets with email_metadata as inbound_email
  • (2026-02-09) T004 completed (reconciliation pass): Backfill marks tickets created by client users as client_portal when no email_metadata
  • (2026-02-09) T005 completed (reconciliation pass): Backfill marks unresolved legacy tickets as internal
  • (2026-02-09) T006 completed (reconciliation pass): TicketOrigin typecheck accepts internal/client_portal/inbound_email/api and rejects invalid values
  • (2026-02-09) T010 completed (reconciliation pass): MSP server action create path persists ticket_origin=internal
  • (2026-02-09) T011 completed (reconciliation pass): Client portal create path persists ticket_origin=client_portal
  • (2026-02-09) T012 completed (reconciliation pass): Inbound email create path persists ticket_origin=inbound_email
  • (2026-02-09) T013 completed (reconciliation pass): API create path persists ticket_origin=api
  • (2026-02-09) T014 completed (reconciliation pass): Workflow/automation ticket creation without explicit origin persists internal default
  • (2026-02-09) T020 completed (reconciliation pass): Resolver returns stored ticket_origin when present and valid
  • (2026-02-09) T021 completed (reconciliation pass): Resolver maps null legacy row with email_metadata to inbound_email
  • (2026-02-09) T022 completed (reconciliation pass): Resolver maps null legacy row with creator user_type client to client_portal
  • (2026-02-09) T023 completed (reconciliation pass): Resolver maps null legacy row with no signal to internal
  • (2026-02-09) T024 completed (reconciliation pass): Resolver handles unknown future origin values without crashing and returns safe fallback classification
  • (2026-02-09) T030 completed (reconciliation pass): MSP getTicketById payload includes normalized ticket_origin for internal ticket
  • (2026-02-09) T031 completed (reconciliation pass): MSP getTicketById payload includes normalized ticket_origin for client_portal ticket
  • (2026-02-09) T032 completed (reconciliation pass): MSP getTicketById payload includes normalized ticket_origin for inbound_email ticket
  • (2026-02-09) T033 completed (reconciliation pass): MSP getTicketById payload includes normalized ticket_origin for api ticket
  • (2026-02-09) T034 completed (reconciliation pass): Client portal getClientTicketDetails payload includes normalized ticket_origin for internal ticket
  • (2026-02-09) T035 completed (reconciliation pass): Client portal getClientTicketDetails payload includes normalized ticket_origin for client_portal ticket
  • (2026-02-09) T036 completed (reconciliation pass): Client portal getClientTicketDetails payload includes normalized ticket_origin for inbound_email ticket
  • (2026-02-09) T037 completed (reconciliation pass): Client portal getClientTicketDetails payload includes normalized ticket_origin for api ticket
  • (2026-02-09) T040 completed (reconciliation pass): TicketOriginBadge renders Created Internally label and data attribute for internal
  • (2026-02-09) T041 completed (reconciliation pass): TicketOriginBadge renders Created via Client Portal label and data attribute for client_portal
  • (2026-02-09) T042 completed (reconciliation pass): TicketOriginBadge renders Created via Inbound Email label and data attribute for inbound_email
  • (2026-02-09) T043 completed (reconciliation pass): TicketOriginBadge renders Created via API label and data attribute for api
  • (2026-02-09) T044 completed (reconciliation pass): TicketOriginBadge renders safe fallback label for unknown future origin value
  • (2026-02-09) T050 completed (reconciliation pass): MSP TicketDetails renders API origin badge when ticket_origin=api
  • (2026-02-09) T051 completed (reconciliation pass): MSP TicketDetails renders all other origin badges correctly (internal/client_portal/inbound_email)
  • (2026-02-09) T052 completed (reconciliation pass): Client portal TicketDetails renders API origin badge when ticket_origin=api
  • (2026-02-09) T053 completed (reconciliation pass): Client portal TicketDetails renders all other origin badges correctly (internal/client_portal/inbound_email)
  • (2026-02-09) T060 completed (reconciliation pass): English common locale includes ticket origin keys for internal/client_portal/inbound_email/api/other
  • (2026-02-09) T061 completed (reconciliation pass): English clientPortal locale includes ticket origin keys for internal/client_portal/inbound_email/api/other
  • (2026-02-09) T070 completed (reconciliation pass): Existing comment ResponseSourceBadge tests continue to pass after ticket-origin changes
  • (2026-02-09) T071 completed (reconciliation pass): Existing response-state badge behavior remains unchanged in MSP and client portal ticket details
  • (2026-02-09) T080 completed (reconciliation pass): End-to-end: API-created ticket displays Created via API badge in MSP ticket details
  • (2026-02-09) T081 completed (reconciliation pass): End-to-end: API-created ticket displays Created via API badge in client portal ticket details when ticket is visible to the client