---
title: "Durable security decisions and projections"
description: "Commit credential revocation with canonical audit and durable intent, then recover downstream projections without restoring access."
tags: ["api-keys","audit","events","transactions","composition"]
---

A downstream audit/read-model failure must not undo a security decision that already committed. Compose [API keys](/docs/packages/identity/api-keys), Audit, and Events with explicit transaction ownership; do not replace required handlers with no-ops or silently change their event semantics.

## Source transaction

Commit these together through the **same physical transaction handle**:

1. The native credential decision, such as `apiKeys.revoke`.
2. A canonical, IDs-only audit record through `bindAuditRegistry` and `PrismaAuditPersistence`.
3. The immutable observational envelope through `PrismaEventOutboxWriter`.

Canonical audit or intent persistence failure rolls back the decision. This does not permit unjournaled revocation; creation and onboarding retain the same required-evidence rule. Only after commit does `PrismaOutboxPump` dispatch the durable intent. Projection failure leaves it retryable and the credential revoked.

## Recoverable projection

In a separate post-commit transaction, atomically claim `(stableHandlerName, originalEventId)` through the audit receipt seam and write the projection. A failed effect must roll back its receipt. Concurrent repair and lost acknowledgments then produce one committed database effect. Remote I/O needs its own idempotency mechanism or recovery protocol; a local receipt cannot make it atomic.

Preserve the original actor, occurrence time, event ID, and immutable credential-generation ID, including impersonation attribution where relevant. Never substitute the repair operator, repair time, or a current mutable email. Secrets, hashes, and credential envelopes do not belong in audit intent.

Keep handler identities and receipts for the supported replay horizon. Do not prune pending outbox rows or receipts with projection rows. The outbox is temporary transport state, not indefinite replay history; retain canonical audit under the product's reviewed retention policy. Bound worker leases, retries, backoff, and shutdown, and limit each pump to owned event names.

## Evidence and limits

The repository's `scripts/test-security-audit-projection-postgres.mjs` fixture exercises native adapters on an owned disposable PostgreSQL cluster: late audit/intent failures, failed projection, competing repairs, and lost acknowledgment/replay. Recorded runtime qualification is Prisma 6.12.0 / PostgreSQL 17.11, not every Prisma adapter or a deployed worker.

Qualify your exact database/client versions and physical transaction before adoption. This recipe does not establish that remote Audit drivers participate in the transaction or that ambiguous connection/commit failures are safe to retry. If canonical audit-chain work cannot fit the source transaction, a separately reviewed minimal durable journal is needed.
