feat(inquiries): triage workflow on the inbox (R2-M2)
The inquiry inbox was read-only — every inquiry stayed there forever
with no way to mark "I handled this" or "this is spam." Now:
- Migration 0045 adds triage_state ('open' | 'assigned' | 'converted'
| 'dismissed' default 'open') + triaged_at + triaged_by columns to
website_submissions, plus a (port_id, triage_state, received_at)
index for the inbox query.
- New PATCH /api/v1/admin/website-submissions/[id]/triage flips the
state with audit log entry.
- List endpoint takes a `state` filter (default 'inbox' = open +
assigned, hides converted + dismissed).
- UI: per-row Convert / Assign / Dismiss / Reopen actions; second
filter row for state; triage badge per card. "Convert" jumps to
/clients with prefill_name / prefill_email / prefill_phone /
prefill_source / prefill_inquiry_id query params + marks the row
converted (the client-create form will read those — same prefill
pattern other entry points use).
1175/1175 vitest passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -55,11 +55,21 @@ export const websiteSubmissions = pgTable(
|
||||
sourceIp: text('source_ip'),
|
||||
userAgent: text('user_agent'),
|
||||
receivedAt: timestamp('received_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
/** Triage workflow state. Default 'open'; transitions to
|
||||
* 'converted' (operator created a client/interest from this row),
|
||||
* 'dismissed' (operator marked as not actionable), or 'assigned'
|
||||
* (operator opened it but hasn't resolved yet). The inbox default
|
||||
* query filters to open + assigned. */
|
||||
triageState: text('triage_state').notNull().default('open'),
|
||||
triagedAt: timestamp('triaged_at', { withTimezone: true }),
|
||||
/** better-auth user id of the operator who last changed triage_state. */
|
||||
triagedBy: text('triaged_by'),
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex('idx_ws_submission_id').on(table.submissionId),
|
||||
index('idx_ws_port_received').on(table.portId, table.receivedAt),
|
||||
index('idx_ws_kind').on(table.kind),
|
||||
index('idx_ws_triage_state').on(table.portId, table.triageState, table.receivedAt),
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user