RFC-003 §0 Phase 0 — the (eventId, handlerName) offset contract.
- prisma: ProjectionOffset model + 20260424100000_add_projection_offset
migration (composite PK, handlerName/appliedAt index for reconciliation)
- infra: PrismaProjectionOffsetStore (createMany skipDuplicates +
applyWithOffset transactional helper that rolls offset+mutation back
together on failure)
- module: bind PROJECTION_OFFSET_STORE → PrismaProjectionOffsetStore
- testing: assertProjectorIdempotent harness ("replay N times → single
state mutation") for Phase 2/3 projector specs to reuse
- tests: 12 specs lock the contract — replay 5x → 1 mutation, broken
projectors fail loudly, two projectors keep independent offsets
Note: prisma format normalised existing column alignment when the new
model was added; the meaningful diff is the appended ProjectionOffset
block at the bottom of schema.prisma.
Acceptance criteria from issue:
- migration applies cleanly (validated via prisma format/parse)
- harness exported from read-models/testing and used by example
projector spec at __tests__/idempotency-harness.spec.ts
Co-Authored-By: Paperclip <noreply@paperclip.ing>
24 lines
1.0 KiB
SQL
24 lines
1.0 KiB
SQL
-- RFC-003 Phase 0 (GOO-187): projection_offset table.
|
|
--
|
|
-- Idempotency contract for CQRS projectors. Every projector dispatch
|
|
-- wraps `apply()` in a transaction that inserts (event_id, handler_name)
|
|
-- here. Re-deliveries hit the composite primary key, roll back, and the
|
|
-- projector observes a no-op.
|
|
--
|
|
-- Port: apps/api/src/modules/read-models/domain/projection-offset-store.ts
|
|
-- Prisma adapter: apps/api/src/modules/read-models/infrastructure/prisma-projection-offset-store.ts
|
|
-- Test harness: apps/api/src/modules/read-models/testing/
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "projection_offset" (
|
|
"eventId" TEXT NOT NULL,
|
|
"handlerName" TEXT NOT NULL,
|
|
"appliedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"payloadHash" TEXT,
|
|
|
|
CONSTRAINT "projection_offset_pkey" PRIMARY KEY ("eventId", "handlerName")
|
|
);
|
|
|
|
-- CreateIndex (handler-scoped scans for reconciliation tooling)
|
|
CREATE INDEX "projection_offset_handlerName_appliedAt_idx" ON "projection_offset"("handlerName", "appliedAt" DESC);
|