1bc2de655a
Uniform stock management for healthcare linen rooms. Licensed under the GNU AGPL v3.
42 lines
2.2 KiB
TypeScript
42 lines
2.2 KiB
TypeScript
import { PrismaClient } from "@prisma/client";
|
|
import { PrismaPg } from "@prisma/adapter-pg";
|
|
|
|
/* The console's database clients. Two, and the difference between them is the whole design.
|
|
*
|
|
* opsDb() connects as `ops_ro`, a Postgres role granted SELECT on control-plane columns only —
|
|
* counts, dates, configuration — and nothing on customer content: no wearer's name, no photo, no
|
|
* request text, no coordinator's email. The grants are in the ops_ro_grants migration and are
|
|
* proven on production by scripts/ops-ro-probe.cjs. The point is that the guard is the database,
|
|
* not code review: there is no row-level security in this product and no linter, so a query
|
|
* written against the wrong table in some future screen must fail with a permission error rather
|
|
* than return data.
|
|
*
|
|
* revealDb() connects as `ops_reveal`, which may read exactly four columns of one table: a
|
|
* facility's id and its three coordinator contacts. It exists so that revealing a contact is not an
|
|
* exception carved into code but a second, narrower door with its own key — widening the reveal's
|
|
* SELECT fails at the database too. Only lib/ops/reveal.ts may use it.
|
|
*
|
|
* Both are read-only by construction. The console's own tables — Operator, OperatorEvent,
|
|
* RevealGrant — are written through lib/db.ts, because they are the console's records.
|
|
*
|
|
* Both are lazy: nothing runs at import time, so a box without the variables still starts the
|
|
* product; only the console fails, and it fails closed. Small pools — this is a small box, and
|
|
* lib/db.ts already holds the main one. */
|
|
const g = globalThis as unknown as { __opsDb?: PrismaClient; __revealDb?: PrismaClient };
|
|
|
|
function make(envVar: "OPS_DATABASE_URL" | "OPS_REVEAL_DATABASE_URL", max: number): PrismaClient {
|
|
const url = process.env[envVar];
|
|
if (!url) throw new Error(`${envVar} not set`);
|
|
return new PrismaClient({ adapter: new PrismaPg({ connectionString: url, max }), log: ["error"] });
|
|
}
|
|
|
|
export function opsDb(): PrismaClient {
|
|
if (!g.__opsDb) g.__opsDb = make("OPS_DATABASE_URL", 2);
|
|
return g.__opsDb;
|
|
}
|
|
|
|
export function revealDb(): PrismaClient {
|
|
if (!g.__revealDb) g.__revealDb = make("OPS_REVEAL_DATABASE_URL", 1);
|
|
return g.__revealDb;
|
|
}
|