feat(p8): calendar/meeting schema + enums + events + migration

Task 8.1: 12 Calendar/Meeting tables (meeting_request, meeting, participant,
transcript, segment, summary, generic action_item + meeting link, provider
account, calendar_event, availability_window, sync_cursor) + 13 enums; migration
calendar-init. Adds calendar.meeting.requested/scheduled/reminder.queued/
summarized events. resetDb truncates the new tables. Kernel already had the
MEETING_REQUEST / MEETING_FOLLOWUP / callback.meetingRef stubs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-01 17:51:35 +05:30
parent 37f8ceeaf3
commit 21772e7611
4 changed files with 612 additions and 0 deletions
+312
View File
@@ -189,6 +189,101 @@ enum IiosAiClaimValidation {
REJECTED
}
// ─── Calendar / Meeting enums (P8) ────────────────────────────────
enum IiosMeetingType {
ZOOM
PHONE
IN_PERSON
CALLBACK
INTERNAL
}
enum IiosMeetingStatus {
REQUESTED
SCHEDULED
CONFIRMED
CANCELLED
COMPLETED
NO_SHOW
}
enum IiosMeetingRequestStatus {
PENDING
PROPOSED
ACCEPTED
DECLINED
SCHEDULED
CANCELLED
}
enum IiosParticipantRole {
ORGANIZER
REQUIRED
OPTIONAL
}
enum IiosAttendanceStatus {
INVITED
ACCEPTED
DECLINED
TENTATIVE
ATTENDED
NO_SHOW
}
enum IiosParticipantVisibility {
FULL
LIMITED
NONE
}
enum IiosConsentStatus {
UNKNOWN
GRANTED
DENIED
REVOKED
}
enum IiosTranscriptStatus {
PENDING
READY
BLOCKED
}
enum IiosSummaryStatus {
PROPOSED
APPROVED
PUBLISHED
REJECTED
}
enum IiosActionItemStatus {
OPEN
IN_PROGRESS
DONE
CANCELLED
}
enum IiosCalendarProviderType {
SIMULATED
GOOGLE
OUTLOOK
ICS
}
enum IiosCalendarSyncStatus {
IDLE
SYNCING
ERROR
}
enum IiosCalendarEventStatus {
CONFIRMED
TENTATIVE
CANCELLED
}
// ─── Kernel tables ────────────────────────────────────────────────
/// Frozen six-vector scope. orgId + appId are REQUIRED (no global-by-null).
@@ -843,3 +938,220 @@ model IiosEmbeddingRef {
@@unique([sourceType, sourceId, version])
}
// ─── Calendar / Meeting SDK tables (P8) — interaction specialization ────────
/// A request to schedule/reschedule/cancel a meeting. Genesis: a P4 callback
/// (callbackRequestId), an accepted P7 AI EVENT claim (sourceClaimId), or direct.
model IiosMeetingRequest {
id String @id @default(cuid())
scopeId String
interactionId String?
requestedByActorId String
targetActorId String?
requestedWindowJson Json
meetingType IiosMeetingType @default(CALLBACK)
status IiosMeetingRequestStatus @default(PENDING)
resultingMeetingId String?
callbackRequestId String?
sourceClaimId String?
createdAt DateTime @default(now())
@@index([scopeId, status])
}
/// A meeting: Zoom / phone / in-person / callback / internal. Owns calendar
/// semantics; a message is only a related artifact.
model IiosMeeting {
id String @id @default(cuid())
scopeId String
interactionId String?
calendarEventId String?
meetingType IiosMeetingType
providerRef String?
joinUrlRef String?
status IiosMeetingStatus @default(REQUESTED)
organizerActorId String
threadId String?
title String
startAt DateTime?
endAt DateTime?
timezone String @default("UTC")
createdAt DateTime @default(now())
participants IiosMeetingParticipant[]
transcripts IiosMeetingTranscript[]
summaries IiosMeetingSummary[]
actionItems IiosMeetingActionItem[]
@@index([scopeId, status])
}
/// Attendee with role, attendance, per-attendee recording consent + visibility.
/// The consent + visibility model is the P8 safety spine (KG-14 / Scenario 6).
model IiosMeetingParticipant {
id String @id @default(cuid())
meetingId String
meeting IiosMeeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
actorRefId String?
sourceHandleId String?
role IiosParticipantRole @default(REQUIRED)
attendanceStatus IiosAttendanceStatus @default(INVITED)
recordingConsent IiosConsentStatus @default(UNKNOWN)
visibility IiosParticipantVisibility @default(FULL)
createdAt DateTime @default(now())
@@unique([meetingId, actorRefId])
@@index([meetingId])
}
/// Transcript artifact metadata. Created only after the consent gate passes;
/// otherwise status=BLOCKED with no segments.
model IiosMeetingTranscript {
id String @id @default(cuid())
meetingId String
meeting IiosMeeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
sourceType String @default("SIMULATED")
transcriptRef String
consentRefId String?
status IiosTranscriptStatus @default(PENDING)
language String @default("en")
createdAt DateTime @default(now())
segments IiosTranscriptSegment[]
@@index([meetingId])
}
/// Speaker-attributed transcript segment.
model IiosTranscriptSegment {
id String @id @default(cuid())
transcriptId String
transcript IiosMeetingTranscript @relation(fields: [transcriptId], references: [id], onDelete: Cascade)
segmentNo Int
speakerActorId String?
startMs Int
endMs Int
contentRef String
confidence Float?
createdAt DateTime @default(now())
@@index([transcriptId])
}
/// AI or human meeting summary; links to a P7 ai_artifact.
model IiosMeetingSummary {
id String @id @default(cuid())
meetingId String
meeting IiosMeeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
aiArtifactId String?
summaryType String @default("AI")
status IiosSummaryStatus @default(PROPOSED)
approvedByActorId String?
publishedAt DateTime?
createdAt DateTime @default(now())
@@index([meetingId])
}
/// Generic task/follow-up (Inbox-owned source of truth), derived from meetings,
/// support, messages or CRM workflows.
model IiosActionItem {
id String @id @default(cuid())
scopeId String
sourceInteractionId String?
sourceMessageId String?
ownerActorId String?
ownerTeamId String?
title String
status IiosActionItemStatus @default(OPEN)
dueAt DateTime?
completedAt DateTime?
createdAt DateTime @default(now())
meetingLinks IiosMeetingActionItem[]
@@index([scopeId, status])
}
/// Meeting-derived action item linked to a generic action_item.
model IiosMeetingActionItem {
id String @id @default(cuid())
meetingId String
meeting IiosMeeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
actionItemId String
actionItem IiosActionItem @relation(fields: [actionItemId], references: [id], onDelete: Cascade)
ownerActorId String?
sourceSegmentId String?
status IiosActionItemStatus @default(OPEN)
createdAt DateTime @default(now())
@@unique([meetingId, actionItemId])
@@index([meetingId])
}
/// Connected calendar/provider account or service mailbox; stores refs, not secrets.
model IiosCalendarProviderAccount {
id String @id @default(cuid())
scopeId String
actorRefId String?
providerType IiosCalendarProviderType @default(SIMULATED)
accountHandleToken String
secretRef String?
syncStatus IiosCalendarSyncStatus @default(IDLE)
createdAt DateTime @default(now())
events IiosCalendarEvent[]
cursors IiosCalendarSyncCursor[]
@@index([scopeId])
}
/// Imported or created calendar event with policy-scoped metadata.
model IiosCalendarEvent {
id String @id @default(cuid())
scopeId String
providerAccountId String?
providerAccount IiosCalendarProviderAccount? @relation(fields: [providerAccountId], references: [id], onDelete: Cascade)
externalEventId String?
title String
startAt DateTime
endAt DateTime
status IiosCalendarEventStatus @default(CONFIRMED)
visibilityClass String @default("internal")
interactionId String?
createdAt DateTime @default(now())
@@unique([providerAccountId, externalEventId])
@@index([scopeId])
}
/// Availability / scheduling constraints for an actor or team.
model IiosAvailabilityWindow {
id String @id @default(cuid())
scopeId String
actorRefId String?
teamProjectionId String?
startAt DateTime
endAt DateTime
source String @default("USER")
recurrenceJson Json?
status String @default("ACTIVE")
createdAt DateTime @default(now())
@@index([scopeId, actorRefId])
}
/// Incremental sync cursor / replay position for a provider calendar.
model IiosCalendarSyncCursor {
id String @id @default(cuid())
providerAccountId String
providerAccount IiosCalendarProviderAccount @relation(fields: [providerAccountId], references: [id], onDelete: Cascade)
externalCursor String?
lastSyncAt DateTime?
status IiosCalendarSyncStatus @default(IDLE)
errorCode String?
createdAt DateTime @default(now())
@@unique([providerAccountId])
}