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

6.8 KiB

PRD — Ticket Origin Badge (Internal, Client Portal, Inbound Email, API)

  • Slug: 2026-02-09-ticket-origin-badge
  • Date: 2026-02-09
  • Status: Draft

Summary

Add a ticket-level origin badge so users can see where a ticket was created:

  • Internal (MSP)
  • Client Portal
  • Inbound Email
  • API

The badge should be visible in ticket details and should work consistently for both MSP and client portal views.

Problem

Today, users can see ticket response state and per-comment response source, but not the ticket creation origin at a glance. This makes triage and context handoff slower, especially when teams handle mixed intake channels.

Goals

  • Show a clear ticket origin badge in ticket details.
  • Support four first-class origins: internal, client_portal, inbound_email, api.
  • Persist ticket origin at creation time so we do not rely only on heuristics.
  • Keep a fallback resolver for legacy tickets created before origin persistence.
  • Keep origin storage extensible for future values (for example ai_agent) without schema redesign.

Non-goals

  • No ticket list/table filtering by origin in this phase.
  • No redesign of ticket details layout beyond adding the badge.
  • No changes to existing per-comment responseSource badges in conversation.
  • No analytics/reporting dashboard for ticket origin in this phase.

Users and Primary Flows

Flow A — MSP user creates a ticket internally

  1. Internal user creates ticket from MSP app (addTicket / related internal flows).
  2. Ticket origin resolves to internal.
  3. Badge shows internal origin in ticket details.

Flow B — Client creates a ticket in client portal

  1. Client user creates ticket from client portal (createClientTicket).
  2. Ticket origin resolves to client_portal.
  3. Badge shows client portal origin in ticket details.

Flow C — Inbound email creates a new ticket

  1. Inbound email processing creates ticket (processInboundEmailInApp / createTicketFromEmail).
  2. Ticket origin resolves to inbound_email.
  3. Badge shows inbound email origin in ticket details.

Flow D — External integration creates a ticket through API

  1. API request creates ticket (POST /api/v1/tickets -> ApiTicketController -> TicketService).
  2. Ticket origin resolves to api.
  3. Badge shows API origin in ticket details.

UX / UI Notes

  • Badge is ticket-level (not per-comment) and indicates creation origin.
  • Placement:
    • MSP: in packages/tickets/src/components/ticket/TicketDetails.tsx header, near ticket number and response-state badge.
    • Client portal: in packages/client-portal/src/components/tickets/TicketDetails.tsx header/status area.
  • Proposed labels:
    • Created Internally
    • Created via Client Portal
    • Created via Inbound Email
    • Created via API
  • Badge should always render exactly one origin value for valid tickets.
  • Unknown future origin values should render safely with a generic fallback label (Created via Other) until a specific label is added.

Requirements

Functional Requirements

  • Add persistent ticket_origin field on tickets table (text).
  • Canonical first-class values for this phase: internal | client_portal | inbound_email | api.
  • Add a shared normalization/helper (normalizeTicketOrigin / getTicketOrigin) used by both MSP and client portal details paths.
  • Origin resolution precedence for reads:
    1. If tickets.ticket_origin exists, use it.
    2. Else use legacy fallback resolver (email metadata, creator user type, etc.).
    3. Else resolve internal.
  • Set ticket_origin explicitly on create paths:
    • MSP app creates -> internal
    • Client portal creates -> client_portal
    • Inbound email creates -> inbound_email
    • API creates -> api
  • Ensure ticket detail actions return derived origin for UI consumption:
    • packages/tickets/src/actions/ticketActions.ts#getTicketById
    • packages/client-portal/src/actions/client-portal-actions/client-tickets.ts#getClientTicketDetails
  • Add a shared TicketOriginBadge component in @alga-psa/tickets/components.
  • Render badge in both ticket detail UIs using shared labels/translation keys.
  • Keep existing comment-level response source behavior unchanged.

Non-functional Requirements

  • Backward compatible with existing tickets (legacy tickets without ticket_origin still resolve correctly).
  • No additional heavy queries; origin derivation should be O(1) per ticket details load.
  • Resolver must be deterministic and unit-testable.

Data / API / Integrations

  • Existing signals already available in current codebase:
    • tickets.email_metadata (inbound email-created tickets)
    • tickets.entered_by + creator users.user_type
    • Existing create path context:
      • MSP app currently passes source: 'web_app'
      • Client portal passes source: 'client_portal'
      • Inbound email paths pass source: 'email'
      • API service passes source: 'api'
  • Existing code pointers:
    • Internal create: packages/tickets/src/actions/ticketActions.ts
    • Client portal create: packages/client-portal/src/actions/client-portal-actions/client-tickets.ts
    • Inbound email create: shared/services/email/processInboundEmailInApp.ts, shared/workflow/actions/emailWorkflowActions.ts
    • API create: server/src/app/api/v1/tickets/route.ts, server/src/lib/api/services/TicketService.ts

Security / Permissions

  • No new permissions required.
  • Origin badge displays metadata about ticket origin only; it does not expose sensitive payloads.

Observability

  • No new metrics/logging required for MVP.

Rollout / Migration

  • DB migration to add tickets.ticket_origin.
  • Data backfill (migration or one-time script) for existing rows:
    • email_metadata present -> inbound_email
    • creator user type client -> client_portal
    • otherwise -> internal
  • Keep legacy fallback resolver in code as a safety net.

Open Questions

  1. Confirm final internal label copy: Created Internally vs Created by MSP.
  2. Should this badge remain ticket-details-only, or also appear in ticket list rows now?
  3. Should inbound email badge stay generic, or include provider label (Gmail, Microsoft, IMAP) in this phase?
  4. For future origins like ai_agent, should we show raw value with title-case fallback or keep a strict whitelist + generic Other label?
  5. Do we want to expose ticket origin in exports/reporting in this phase (currently no)?

Acceptance Criteria (Definition of Done)

  • New ticket created internally shows internal origin badge in MSP ticket details.
  • New ticket created in client portal shows client_portal origin badge in both MSP and client portal ticket details.
  • New inbound email-created ticket shows inbound_email origin badge in ticket details.
  • New API-created ticket shows api origin badge in ticket details.
  • Legacy tickets still render a stable origin badge using fallback rules.
  • Existing comment response-source badge behavior is unchanged.