feat(service): P3.1 inbox tables + extract ActorResolver
IiosInboxItem + IiosInboxItemStateHistory (migration inbox-init). Extracted resolveScope/resolveActor/ensureParticipant into a shared ActorResolver (IdentityModule) so message + inbox layers share identity resolution; MessageService delegates (P2 tests unchanged). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -75,6 +75,26 @@ enum IiosReceiptKind {
|
||||
RATE_LIMITED
|
||||
}
|
||||
|
||||
enum IiosInboxItemKind {
|
||||
NEEDS_REPLY
|
||||
NEEDS_REVIEW
|
||||
NEEDS_APPROVAL
|
||||
SUPPORT_UPDATE
|
||||
MEETING_FOLLOWUP
|
||||
DIGEST
|
||||
SYSTEM_ALERT
|
||||
CRM_OWNER_INTEREST
|
||||
}
|
||||
|
||||
enum IiosInboxState {
|
||||
OPEN
|
||||
SNOOZED
|
||||
DONE
|
||||
ARCHIVED
|
||||
CANCELLED
|
||||
STALE
|
||||
}
|
||||
|
||||
// ─── Kernel tables ────────────────────────────────────────────────
|
||||
|
||||
/// Frozen six-vector scope. orgId + appId are REQUIRED (no global-by-null).
|
||||
@@ -93,6 +113,7 @@ model IiosScope {
|
||||
channels IiosChannel[]
|
||||
threads IiosThread[]
|
||||
interactions IiosInteraction[]
|
||||
inboxItems IiosInboxItem[]
|
||||
|
||||
@@index([orgId, appId, tenantId])
|
||||
}
|
||||
@@ -135,6 +156,7 @@ model IiosActorRef {
|
||||
interactions IiosInteraction[]
|
||||
receipts IiosMessageReceipt[]
|
||||
unreadCounters IiosUnreadCounter[]
|
||||
inboxItemsOwned IiosInboxItem[]
|
||||
}
|
||||
|
||||
/// A configured channel surface (PORTAL in P1).
|
||||
@@ -177,6 +199,7 @@ model IiosThread {
|
||||
participants IiosThreadParticipant[]
|
||||
interactions IiosInteraction[]
|
||||
unreadCounters IiosUnreadCounter[]
|
||||
inboxItems IiosInboxItem[]
|
||||
|
||||
@@index([scopeId, status])
|
||||
}
|
||||
@@ -219,8 +242,9 @@ model IiosInteraction {
|
||||
traceId String?
|
||||
metadata Json?
|
||||
|
||||
parts IiosMessagePart[]
|
||||
receipts IiosMessageReceipt[]
|
||||
parts IiosMessagePart[]
|
||||
receipts IiosMessageReceipt[]
|
||||
inboxItems IiosInboxItem[]
|
||||
|
||||
@@unique([scopeId, idempotencyKey])
|
||||
@@index([threadId, occurredAt])
|
||||
@@ -299,3 +323,49 @@ model IiosUnreadCounter {
|
||||
|
||||
@@id([threadId, actorId])
|
||||
}
|
||||
|
||||
// ─── P3: Inbox (work/awareness surface) ───────────────────────────
|
||||
|
||||
/// A durable action/awareness item owned by one actor. Fed by the event
|
||||
/// projector (deterministic, collapse-per-thread). NOT a thin unread projection.
|
||||
model IiosInboxItem {
|
||||
id String @id @default(cuid())
|
||||
scopeId String
|
||||
scope IiosScope @relation(fields: [scopeId], references: [id], onDelete: Cascade)
|
||||
ownerActorId String
|
||||
ownerActor IiosActorRef @relation(fields: [ownerActorId], references: [id])
|
||||
kind IiosInboxItemKind
|
||||
state IiosInboxState @default(OPEN)
|
||||
title String
|
||||
summary String?
|
||||
priority String @default("NORMAL")
|
||||
dueAt DateTime?
|
||||
sourceInteractionId String?
|
||||
sourceInteraction IiosInteraction? @relation(fields: [sourceInteractionId], references: [id])
|
||||
threadId String?
|
||||
thread IiosThread? @relation(fields: [threadId], references: [id])
|
||||
traceId String?
|
||||
actionRef Json?
|
||||
policyDecisionRef String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
metadata Json?
|
||||
|
||||
stateHistory IiosInboxItemStateHistory[]
|
||||
|
||||
@@index([ownerActorId, state, priority])
|
||||
}
|
||||
|
||||
/// Audit trail of inbox-item state transitions.
|
||||
model IiosInboxItemStateHistory {
|
||||
id String @id @default(cuid())
|
||||
inboxItemId String
|
||||
inboxItem IiosInboxItem @relation(fields: [inboxItemId], references: [id], onDelete: Cascade)
|
||||
fromState IiosInboxState?
|
||||
toState IiosInboxState
|
||||
actorId String?
|
||||
reasonCode String?
|
||||
at DateTime @default(now())
|
||||
|
||||
@@index([inboxItemId])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user