Fundament: atomare Mandanten-Transaktionen, iframe-Vorschau, Uploads bis 25 MB, DSGVO-Felder

- db.ts: tenantTransaction() – atomar auch bei RLS_ENFORCED=true (AsyncLocalStorage
  bindet Operationen an eine craftvia_app-Transaktion, Kontext einmal gesetzt,
  verschachtelte Aufrufe treten bei, fremder Mandant wird abgewiesen)
- services/context.ts: inTransaction(ctx, fn); imports/confirm.ts umgestellt
- next.config.ts: EMBEDDABLE_FILE_ROUTES mit frame-ancestors 'self'/SAMEORIGIN
  (PDF-Vorschau Prüfmaske), proxyClientMaxBodySize 26mb (Import bis 25 MB)
- test-rls-enforcement: RLS-URL-Default aus DATABASE_URL (Lane-DBs)
- dsgvo/pii-fields: 26 Personenreferenzen des Craftvia-Domänenmodells
- ARCHITEKTUR §4.8: Transaktions-, Header-, Upload-, Versions- und PII-Regeln
- Test test-tenant-transaction (Commit/Rollback/Fremdmandant/Verschachtelung),
  grün im Owner- und im RLS-Modus

Gate: tsc, lint, build, 31/31 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 12:29:57 +02:00
co-authored by Claude Opus 5
parent 3e16689b2f
commit 4a25f2cc3b
8 changed files with 243 additions and 13 deletions
+11 -3
View File
@@ -42,9 +42,17 @@ async function expectThrow(fn: () => Promise<unknown>, msg: string) {
}
}
const RLS_URL =
process.env.RLS_DATABASE_URL ??
"postgresql://craftvia_app:craftvia_app_local@localhost:5432/craftvia?schema=public";
/**
* Default: same host/port/database as DATABASE_URL, but as the restricted role craftvia_app.
* Keeps the test pointed at the database that was actually migrated/seeded (e.g. lane DBs).
*/
function defaultRlsUrl(): string {
const base = new URL(process.env.DATABASE_URL ?? "postgresql://localhost:5432/craftvia?schema=public");
base.username = "craftvia_app";
base.password = "craftvia_app_local";
return base.toString();
}
const RLS_URL = process.env.RLS_DATABASE_URL ?? defaultRlsUrl();
const SLUG_A = "zz-rls-test-a";
const SLUG_B = "zz-rls-test-b";