feat(service): P6.1 route tables (route_binding, route_decision, moderation_flag) + enums + events
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,8 @@ export const IIOS_EVENTS = {
|
|||||||
ticketCreated: 'com.insignia.iios.support.ticket.created.v1',
|
ticketCreated: 'com.insignia.iios.support.ticket.created.v1',
|
||||||
ticketStateChanged: 'com.insignia.iios.support.ticket.state.changed.v1',
|
ticketStateChanged: 'com.insignia.iios.support.ticket.state.changed.v1',
|
||||||
callbackRequested: 'com.insignia.iios.support.callback.requested.v1',
|
callbackRequested: 'com.insignia.iios.support.callback.requested.v1',
|
||||||
|
routeDecisionPreviewed: 'com.insignia.iios.route.decision.previewed.v1',
|
||||||
|
routeApproved: 'com.insignia.iios.route.approved.v1',
|
||||||
notificationQueued: 'com.insignia.iios.notification.queued.v1',
|
notificationQueued: 'com.insignia.iios.notification.queued.v1',
|
||||||
deliveryAttempted: 'com.insignia.iios.delivery.attempted.v1',
|
deliveryAttempted: 'com.insignia.iios.delivery.attempted.v1',
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "IiosRouteMode" AS ENUM ('MANUAL', 'AUTOMATIC', 'HYBRID', 'SIMULATION_ONLY');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "IiosOutputFormat" AS ENUM ('FORWARD', 'THREADED', 'DIGEST', 'SUMMARY', 'TRANSCRIPT');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "IiosRouteDecisionState" AS ENUM ('ALLOW', 'DENY', 'REVIEW', 'SUPPRESS', 'SIMULATED');
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "IiosRouteBinding" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"scopeId" TEXT NOT NULL,
|
||||||
|
"originChannelType" TEXT NOT NULL,
|
||||||
|
"originRef" TEXT,
|
||||||
|
"destinationChannelType" TEXT NOT NULL,
|
||||||
|
"destinationRef" TEXT,
|
||||||
|
"restrictionProfile" TEXT,
|
||||||
|
"mode" "IiosRouteMode" NOT NULL DEFAULT 'SIMULATION_ONLY',
|
||||||
|
"outputFormat" "IiosOutputFormat" NOT NULL DEFAULT 'FORWARD',
|
||||||
|
"frequency" TEXT NOT NULL DEFAULT 'IMMEDIATE',
|
||||||
|
"includeAttachments" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"requiresReview" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
"rulepackVersion" TEXT NOT NULL DEFAULT 'v1',
|
||||||
|
"enabled" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "IiosRouteBinding_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "IiosRouteDecision" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"interactionId" TEXT NOT NULL,
|
||||||
|
"routeBindingId" TEXT NOT NULL,
|
||||||
|
"decisionState" "IiosRouteDecisionState" NOT NULL,
|
||||||
|
"reasonCodes" TEXT[],
|
||||||
|
"previewPayload" JSONB NOT NULL,
|
||||||
|
"outputFormat" "IiosOutputFormat" NOT NULL,
|
||||||
|
"rulepackVersion" TEXT NOT NULL,
|
||||||
|
"simulationId" TEXT,
|
||||||
|
"decidedByActorId" TEXT,
|
||||||
|
"executed" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"executedCommandId" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "IiosRouteDecision_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "IiosModerationFlag" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"interactionId" TEXT NOT NULL,
|
||||||
|
"flagType" TEXT NOT NULL,
|
||||||
|
"severity" TEXT NOT NULL DEFAULT 'LOW',
|
||||||
|
"proposedBy" TEXT NOT NULL DEFAULT 'RULE',
|
||||||
|
"confidence" DOUBLE PRECISION,
|
||||||
|
"explanation" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"resolvedAt" TIMESTAMP(3),
|
||||||
|
|
||||||
|
CONSTRAINT "IiosModerationFlag_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "IiosRouteBinding_scopeId_originChannelType_idx" ON "IiosRouteBinding"("scopeId", "originChannelType");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "IiosRouteDecision_decisionState_idx" ON "IiosRouteDecision"("decisionState");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "IiosRouteDecision_interactionId_routeBindingId_key" ON "IiosRouteDecision"("interactionId", "routeBindingId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "IiosModerationFlag_interactionId_idx" ON "IiosModerationFlag"("interactionId");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "IiosRouteDecision" ADD CONSTRAINT "IiosRouteDecision_routeBindingId_fkey" FOREIGN KEY ("routeBindingId") REFERENCES "IiosRouteBinding"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
@@ -121,6 +121,29 @@ enum IiosCallbackStatus {
|
|||||||
CANCELLED
|
CANCELLED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum IiosRouteMode {
|
||||||
|
MANUAL
|
||||||
|
AUTOMATIC
|
||||||
|
HYBRID
|
||||||
|
SIMULATION_ONLY
|
||||||
|
}
|
||||||
|
|
||||||
|
enum IiosOutputFormat {
|
||||||
|
FORWARD
|
||||||
|
THREADED
|
||||||
|
DIGEST
|
||||||
|
SUMMARY
|
||||||
|
TRANSCRIPT
|
||||||
|
}
|
||||||
|
|
||||||
|
enum IiosRouteDecisionState {
|
||||||
|
ALLOW
|
||||||
|
DENY
|
||||||
|
REVIEW
|
||||||
|
SUPPRESS
|
||||||
|
SIMULATED
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Kernel tables ────────────────────────────────────────────────
|
// ─── Kernel tables ────────────────────────────────────────────────
|
||||||
|
|
||||||
/// Frozen six-vector scope. orgId + appId are REQUIRED (no global-by-null).
|
/// Frozen six-vector scope. orgId + appId are REQUIRED (no global-by-null).
|
||||||
@@ -577,3 +600,66 @@ model IiosRateLimitBucket {
|
|||||||
|
|
||||||
@@id([channelType, bucketKey])
|
@@id([channelType, bucketKey])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── P6: Routing (preview-first community forwarding) ──────────────
|
||||||
|
|
||||||
|
/// One origin→destination route rule. Preview-first: SIMULATION_ONLY + disabled
|
||||||
|
/// + requiresReview by default. Restricted destinations are deny-by-default.
|
||||||
|
model IiosRouteBinding {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
scopeId String
|
||||||
|
originChannelType String
|
||||||
|
originRef String?
|
||||||
|
destinationChannelType String
|
||||||
|
destinationRef String?
|
||||||
|
restrictionProfile String? // e.g. CHILD / SENIORS / ADULT / PUBLIC
|
||||||
|
mode IiosRouteMode @default(SIMULATION_ONLY)
|
||||||
|
outputFormat IiosOutputFormat @default(FORWARD)
|
||||||
|
frequency String @default("IMMEDIATE")
|
||||||
|
includeAttachments Boolean @default(false)
|
||||||
|
requiresReview Boolean @default(true)
|
||||||
|
rulepackVersion String @default("v1")
|
||||||
|
enabled Boolean @default(false)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
decisions IiosRouteDecision[]
|
||||||
|
|
||||||
|
@@index([scopeId, originChannelType])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Per-(interaction, binding) routing decision + rendered preview. No send during simulation.
|
||||||
|
model IiosRouteDecision {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
interactionId String
|
||||||
|
routeBindingId String
|
||||||
|
routeBinding IiosRouteBinding @relation(fields: [routeBindingId], references: [id], onDelete: Cascade)
|
||||||
|
decisionState IiosRouteDecisionState
|
||||||
|
reasonCodes String[]
|
||||||
|
previewPayload Json
|
||||||
|
outputFormat IiosOutputFormat
|
||||||
|
rulepackVersion String
|
||||||
|
simulationId String?
|
||||||
|
decidedByActorId String?
|
||||||
|
executed Boolean @default(false)
|
||||||
|
executedCommandId String?
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
@@unique([interactionId, routeBindingId])
|
||||||
|
@@index([decisionState])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A deterministic (RULE) or later AI-proposed flag on an interaction. AI can
|
||||||
|
/// propose but never allow a route (P7).
|
||||||
|
model IiosModerationFlag {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
interactionId String
|
||||||
|
flagType String
|
||||||
|
severity String @default("LOW")
|
||||||
|
proposedBy String @default("RULE")
|
||||||
|
confidence Float?
|
||||||
|
explanation String?
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
resolvedAt DateTime?
|
||||||
|
|
||||||
|
@@index([interactionId])
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type { PrismaClient } from '@prisma/client';
|
|||||||
export async function resetDb(prisma: PrismaClient): Promise<void> {
|
export async function resetDb(prisma: PrismaClient): Promise<void> {
|
||||||
await prisma.$executeRawUnsafe(
|
await prisma.$executeRawUnsafe(
|
||||||
`TRUNCATE TABLE
|
`TRUNCATE TABLE
|
||||||
|
"IiosRouteDecision","IiosRouteBinding","IiosModerationFlag",
|
||||||
"IiosInboundRawEvent","IiosDeliveryAttempt","IiosOutboundCommand","IiosRateLimitBucket",
|
"IiosInboundRawEvent","IiosDeliveryAttempt","IiosOutboundCommand","IiosRateLimitBucket",
|
||||||
"IiosTicketStateHistory","IiosTicketThreadLink","IiosCallbackRequest","IiosTicket",
|
"IiosTicketStateHistory","IiosTicketThreadLink","IiosCallbackRequest","IiosTicket",
|
||||||
"IiosSupportTeamMember","IiosSupportQueue",
|
"IiosSupportTeamMember","IiosSupportQueue",
|
||||||
|
|||||||
Reference in New Issue
Block a user