feat(iios): idempotency-command ledger + IdempotencyService (P9)
Adds the doc-mandated IiosIdempotencyCommand table + a reusable IdempotencyService.run() that writes IN_FLIGHT at command start, replays the cached response on a same-key/same-body retry, rejects a same-key/different-body reuse (409), and retries a FAILED command. Tenant-scoped via @@unique([scopeId, commandName, idempotencyKey]) (KG-02/KG-06). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "IiosIdempotencyCommand" (
|
||||
"id" TEXT NOT NULL,
|
||||
"scopeId" TEXT,
|
||||
"commandName" TEXT NOT NULL,
|
||||
"idempotencyKey" TEXT NOT NULL,
|
||||
"schemaVersion" TEXT NOT NULL DEFAULT 'v1',
|
||||
"actorRefId" TEXT,
|
||||
"requestHash" TEXT NOT NULL,
|
||||
"responseHash" TEXT,
|
||||
"response" JSONB,
|
||||
"status" TEXT NOT NULL DEFAULT 'IN_FLIGHT',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"completedAt" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "IiosIdempotencyCommand_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "IiosIdempotencyCommand_scopeId_status_idx" ON "IiosIdempotencyCommand"("scopeId", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "IiosIdempotencyCommand_scopeId_commandName_idempotencyKey_key" ON "IiosIdempotencyCommand"("scopeId", "commandName", "idempotencyKey");
|
||||
@@ -492,6 +492,26 @@ model IiosProcessedEvent {
|
||||
@@id([consumerName, eventId])
|
||||
}
|
||||
|
||||
/// Idempotent-command ledger (P9). Suppresses duplicate externally-visible mutations:
|
||||
/// same (scope, command, key) replays the cached response; a different request → conflict.
|
||||
model IiosIdempotencyCommand {
|
||||
id String @id @default(cuid())
|
||||
scopeId String?
|
||||
commandName String
|
||||
idempotencyKey String
|
||||
schemaVersion String @default("v1")
|
||||
actorRefId String?
|
||||
requestHash String
|
||||
responseHash String?
|
||||
response Json?
|
||||
status String @default("IN_FLIGHT") // IN_FLIGHT | COMPLETED | FAILED
|
||||
createdAt DateTime @default(now())
|
||||
completedAt DateTime?
|
||||
|
||||
@@unique([scopeId, commandName, idempotencyKey])
|
||||
@@index([scopeId, status])
|
||||
}
|
||||
|
||||
// ─── P2: messaging — receipts & unread ────────────────────────────
|
||||
|
||||
/// Delivery/read receipt for a message interaction, per actor.
|
||||
|
||||
Reference in New Issue
Block a user