Imported from davipatricio/menuza-v2 (
packages/db/AGENTS.md). Install upstream withnpx skills add davipatricio/menuza-v2 --skill db. Copyright stays with the author.
@menuza/db
- Owns the Prisma 8 data contract, migration packages, emitted contract artifacts, and the database client lifecycle.
- Contract source:
prisma/contract.prisma. Emitted artifacts (contract.json,contract.d.ts) land inprisma/generated/client/and are gitignored. Re-runbun run db:generate(=prisma contract emit) after every contract edit. - Migrations are explicit and committed under
migrations/(Prisma 8 layout:migrations/app/<ts>_<name>+migrations/snapshots/<hash>). No auto-migration at app startup. Day-to-day loop: edit contract →prisma contract emit→prisma migration plan --name foo→ review the planned package →prisma db migrate --advance-ref db. - The
dbref anchorsmigration plan's origin;db migratewithout--advance-ref(e.g. CI deploys) must not move it. - Singleton client lives in
src/client.ts(postgres<Contract>(...), lazy connection). Importing consumers must calldisconnectDb()on shutdown. UsepingDb()for readiness probes. - Query spans:
src/otel-middleware.tsrecords one CLIENT span per query/execute, but only when a span is already active. Statement text is truncated; bound parameters are never recorded. - Tenant-scoped queries MUST include an explicit
whereontenantId. The runtimetenantIsolationMiddleware()is fail-closed: querying or mutating a tenant-scoped model withouttenantId(or with a cross-tenant ID under an active tenant scope) throwsTenantIsolationError. Intentionally global lookups (e.g. proxy host resolution) must useunscoped(). DATABASE_URLcomes from the repo-root.envin both places that need it:prisma.config.tsself-loads it viaprocess.loadEnvFile, and runtime callers must export it before importing the client (bun --env-file-if-exists=...wrappers).- Runtime:
@prisma/orm-postgres(ships its ownpgbinding). No driver adapter, noprisma://Accelerate URL. - Timestamps:
Timestamp(3)columns encode/decode asTemporal.PlainDateTime(UTC-naive to match values written by the old v7 client). Bun shipsTemporal; Node <26.8 would needtemporal-polyfill. - No
@default(cuid())or@updatedAtin v8 contracts: seed/scripts setid(randomUUID) andupdatedAtexplicitly.
Distribution
- Source-based workspace. Consumers import the TS source directly via Bun/Next.
tsdownwas evaluated and rejected: contract artifacts (contract.jsonimported withwith { type: "json" }) and the runtime's target codecs must not be inlined into a bundle.