feat(GRO-106): staff messages page

- Adds staff conversations API (GET /api/conversations, GET /api/conversations/:id/messages, POST /api/conversations/:id/messages) with auth scoping and cross-tenant protection
- Adds staffReadAt column to conversations table for unread tracking
- Adds staff Messages page with two-column inbox layout (thread list + conversation view + composer)
- Adds Messages entry to staff sidebar navigation
- Includes tests for the MessagesPage component

Part of GRO-106 (SMS/MMS integration) Phase 1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 10:27:06 +00:00
committed by Flea Flicker [agent]
parent f43e566dbd
commit c4978be280
9 changed files with 3728 additions and 185 deletions
@@ -0,0 +1,4 @@
-- Add staffReadAt column to conversations for unread tracking
ALTER TABLE "conversations" ADD COLUMN "staff_read_at" timestamp;
CREATE INDEX "idx_conversations_business_id_staff_read_at" ON "conversations"("business_id", "staff_read_at" DESC);
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -220,7 +220,7 @@
"breakpoints": true
},
{
"idx": 31,
"idx": 32,
"version": "7",
"when": 1778818472097,
"tag": "0032_staff_read_at",
+1
View File
@@ -463,6 +463,7 @@ export const conversations = pgTable(
businessNumber: text("business_number").notNull(),
lastMessageAt: timestamp("last_message_at"),
status: text("status").notNull().default("active"),
staffReadAt: timestamp("staff_read_at"),
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow(),
staffReadAt: timestamp("staff_read_at"),