Work / DwarSeva / Wiki / Decisions
2026-10-23-infra-may-touch-prisma
Decisioncanonicalverified 2026-10-23
DECISION.2026-10-23.INFRA-MAY-TOUCH-PRISMADecision
Two infrastructure files may use PrismaService directly; nothing else outside a repository may. They are src/api/health/health.service.ts (the SELECT 1 connection ping) and src/shared/services/dataloader.service.ts (the GraphQL batch loaders). The only-repositories-touch-prisma rule in apps/server/.dependency-cruiser.cjs names exactly these two files.
Why
layered-architecture says no layer calls the database except a repository. That rule protects business logic: it keeps queries, soft-delete filtering and type conversion in one layer. Neither file holds business logic.
- The health ping checks the connection itself, not any data. A repository for it would wrap one raw query in a class with no model.
- The dataloader batches lookups across many models to stop N+1 queries in GraphQL. It is data access already; splitting it across every model's repository would rebuild it, not move it.
Options weighed:
- Move both into repositories — rejected, for the reasons above.
- Exempt
src/shared/as a whole — rejected: too wide, a future shared helper could query freely. - Name the two files — chosen. Any new exception needs its own decision.
The other two files the rule caught on 2026-10-23 held domain logic and were fixed instead: the push token pruner now goes through its repository, and the subscription scheduler — a second copy of SubscriptionPlanJobsService running at the same hour — was removed, its per-admin notices moved into the jobs service.
Impact
zeno checkfails if any other non-repository file importsPrismaService.- Adding a third exception means editing this page and the rule together.
Status
Active
Sources
- apps/server/.dependency-cruiser.cjs — rule
only-repositories-touch-prisma - apps/server/src/api/health/health.service.ts
- apps/server/src/shared/services/dataloader.service.ts