Skip to main content

Data access boundaries

Tier: Public
Status: v1.0 (as-built contract)
Audience: contributors, module authors, third-party integrators, self-hosting operators.

This document states where data lives and who may touch it — the Prisma/API split that keeps ACL, tenancy, and schema evolution centralized on the platform.

Not Postgres topology. Replication, pgpool, and read-routing are in POSTGRES-REPLICATION-ARCHITECTURE.md and CROSS-PLATFORM-BOUNDARIES.md §7.
Not authorization policy. Workspace roles and membership gates are in TENANCY-AND-ACL.md.


1. Summary

LayerData accessORM / store
services/apiSource of truth — reads/writes PostgresPrisma (only ORM in the monorepo)
apps/webHTTP onlyNone — @umbraculum/api-client + @umbraculum/contracts
apps/nativeHTTP only (offline cache planned)None on wire; future SQLite device cache synced via API
Third-party modulesHTTP + pinned contractsNone — no Prisma, no direct Postgres
In-repo module slicesPlatform Prisma client inside services/apiConsume platform client; own schema via multiSchema

Rule: clients and external integrators never connect to Postgres. The API is the integration boundary.


2. Why the API boundary (not in-process ORM extension)

RFC-0001 Decision F makes cross-cutting concerns platform-owned. A single data-access path gives:

  1. ACL and tenancy — every mutation passes through the same session context and service-layer gates (TENANCY-AND-ACL.md).
  2. Schema evolution — one Prisma migration story per Postgres schema; contracts version the wire shape.
  3. Multi-client parity — web, native, and future integrators see the same validated DTOs (CONTRACTS-VALIDATION-STRATEGY.md).
  4. AI tool safety — tools call services, not raw DB connections (PLATFORM-ARCHITECTURE.md §6.2).

Modules extend domain data in their own Prisma schemas (brewery, pim, mrp, …) but consume the platform client — they do not ship a parallel ORM or connection pool.


3. Server: Prisma in services/api

  • Schema: services/api/prisma/schema.prisma
  • Client: generated Prisma client used only inside the API service and its tests/CLI.
  • Schemas: platform.* (tenancy, auth, billing, AI, integrations), module schemas (brewery, automation, pim, mrp, crp, rendering) per RFC-0010 and RFC-0002.
  • Migrations: forward-only via prisma migrate; directUrl for admin lane — see CROSS-PLATFORM-BOUNDARIES.md §7.

Module services under services/api/src/modules/<code>/services/ use the shared app.prisma instance injected at route registration time.


4. Clients: HTTP + contracts

Web and native

Clients render and validate; for server-centralized domains (water chemistry, analysis, …) they do not re-implement canonical formulas. See CODING-STANDARDS.md (“API centralization guardrails”).

Third-party / community modules

  • Pin @umbraculum/<code>-contracts (MIT) and call documented HTTP routes.
  • Partial OpenAPI catalog: API-OPENAPI.md
  • Contracts packages do not export Prisma types or client wrappers (RFC-0002).

5. Native offline (planned; not a second source of truth)

Brew-day reliability targets write locally first, sync when online (modules/verticals/brewery/IMPLEMENTATION-LOG.md §6):

  • Device SQLite holds pending measurements/notes.
  • Postgres remains authoritative — sync pushes through the same API endpoints with the same ACL gates.
  • Native does not get a Prisma client or direct Postgres URL.

Ubuntu Touch does not use the native offline path — it runs apps/web in a Morph webview (online-first). See design/ubuntu-touch-shell-strategy.md.


6. What each package may import

Package / appMay use Prisma?May call HTTP API?
services/apiYesN/A (is the API)
apps/web, apps/nativeNoYes (@umbraculum/api-client)
packages/*-contractsNoN/A (types + parsers only)
packages/platform/api-clientNoYes (implements fetch)
Third-party npm moduleNoYes

Client-safe vertical packages (apps/web, apps/native)

These brewery-vertical packages contain no Prisma, no services/api imports, and no server-only deps. Apps may import them directly (HTTP + contracts remain the persistence boundary):

PackageRole
@umbraculum/brewery-beerjsonBeerJSON adaptation helpers (packages/verticals/brewery/beerjson)
@umbraculum/brewery-recipes-uiCross-platform recipe/water UI (packages/verticals/brewery/recipes-ui)

Allowlist source of truth: scripts/eslint/appClientPackageAllowlist.mjs. ESLint burn-in: docs/design/solid-client-safe-imports-spike.md (WS6).


7. Module author checklist

  • All persistence goes through services/api services using the platform Prisma client.
  • New module domain models live in a module-owned Postgres schema (@@schema("…")), not ad-hoc tables in public.
  • Wire shapes are defined in @umbraculum/<code>-contracts, not Prisma types leaked to clients.
  • No DATABASE_URL in web, native, or published SDK packages.
  • AI tools call services; no prisma in tool handlers beyond what services already encapsulate.

8. Cross-references