Fundament: Doku, Testanpassungen, Restbereinigung
- AGENTS.md und README.md auf Craftvia umgeschrieben (Regeln, Andockpunkte, Stack mit Garage, tsx-Tests, Gate, Demo-Logins) - ISMS-Dokumente entfernt (SPEC, Prototypen, Lane-Prompts, Übergaben, Konzepte Incidents/Framework); Fundament-Doku (Deploy, Sicherheit, Backup, Identity) bleibt - Fundament-Tests an Craftvia-Rollen/Branding angepasst, Resttreffer certvia/isms in Skripten und Kommentaren bereinigt Gate: prisma generate, migrate status, tsc, lint, build, 22/22 Testskripte grün. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// Rollen-Rechte-Sync (Wartung): gleicht die Rollen→Rechte-Zuordnung ALLER bestehenden
|
||||
// Mandanten mit dem aktuellen Rechtekatalog (ROLE_DEFS) ab. Nötig, weil Rechte bei der
|
||||
// Provisionierung in die DB geschrieben werden — neu hinzugekommene Rechte (z. B.
|
||||
// `onboarding:use`, `validate_objects`) fehlen bestehenden Mandanten sonst, bis dieses
|
||||
// `report:approve_team`, `lotse:use`) fehlen bestehenden Mandanten sonst, bis dieses
|
||||
// Skript läuft. Rein additiv (entfernt keine bestehenden Zuordnungen).
|
||||
//
|
||||
// Lauf (lokal): npx tsx scripts/sync-role-permissions.ts
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// NextAuth-Session voraussetzen; die sicherheitsrelevante Logik ist die Query.)
|
||||
//
|
||||
// Lauf: npx tsx scripts/test-action-guard-authz.ts
|
||||
// Nutzt die lokale Postgres-DB (Container isms-tool-postgres-1); .env liegt im Worktree.
|
||||
// Nutzt die lokale Postgres-DB (Compose-Service postgres); .env liegt im Worktree.
|
||||
|
||||
import "dotenv/config";
|
||||
import { prisma } from "../src/server/db";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Direkt-Download-Pfad: exportTenant(persist:false) liefert das verschlüsselte
|
||||
// Artefakt als Buffer OHNE Store-Roundtrip (Grundlage der /api/platform/backup/download-Route).
|
||||
// Lauf: npx tsx scripts/test-backup-download.ts (nutzt lokale isms-DB)
|
||||
// Lauf: npx tsx scripts/test-backup-download.ts (nutzt lokale Craftvia-DB)
|
||||
import "dotenv/config";
|
||||
import { prisma } from "../src/server/db";
|
||||
import { exportTenant } from "../src/server/backup/export";
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// die die Engine anfasst.
|
||||
//
|
||||
// Lauf: npx tsx scripts/test-backup-isolation.ts
|
||||
// Nutzt die lokale isms-DB (geseedet: demo + demo2). Nach Erfolg ist `demo`
|
||||
// Nutzt die lokale Craftvia-DB (geseedet: demo + demo2). Nach Erfolg ist `demo`
|
||||
// wiederhergestellt; bei Fehlschlag ggf. `npx tsx prisma/seed.ts` nachziehen.
|
||||
|
||||
import "dotenv/config";
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// Secrets; der dsgvo_export-Job erzeugt Store-Objekt + signierten Token
|
||||
// mit kurzer TTL (processBackupJob direkt, ohne Redis).
|
||||
//
|
||||
// Lauf: npx tsx scripts/test-backup-portal.ts (nutzt lokale isms-DB, räumt auf)
|
||||
// Lauf: npx tsx scripts/test-backup-portal.ts (nutzt lokale Craftvia-DB, räumt auf)
|
||||
|
||||
import "dotenv/config";
|
||||
import { execFileSync } from "node:child_process";
|
||||
|
||||
@@ -81,7 +81,7 @@ async function main() {
|
||||
cfg({
|
||||
backupTarget: "s3",
|
||||
backupS3Endpoint: "http://minio:9000",
|
||||
backupS3Bucket: "certvia-backups",
|
||||
backupS3Bucket: "craftvia-backups",
|
||||
backupS3AccessKey: "AK",
|
||||
backupS3SecretKey: "SK",
|
||||
}),
|
||||
@@ -134,7 +134,7 @@ async function main() {
|
||||
{
|
||||
const store = resolveBackupStore(cfg({ backupTarget: "local", backupLocalDir: join(tmp, "conn") }));
|
||||
const key = "__connectivity-test__/probe.txt";
|
||||
const payload = Buffer.from("certvia connectivity", "utf8");
|
||||
const payload = Buffer.from("craftvia connectivity", "utf8");
|
||||
await store.put(key, payload);
|
||||
const back = await store.get(key);
|
||||
ok(!!back && back.equals(payload), "put→get liefert identische Bytes");
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// Container) → echter End-to-End-Durchstich.
|
||||
//
|
||||
// S3_ENDPOINT=http://127.0.0.1:3900 S3_ACCESS_KEY=… S3_SECRET_KEY=… \
|
||||
// S3_BUCKET=isms-documents S3_REGION=us-east-1 npx tsx scripts/test-garage-storage.ts
|
||||
// S3_BUCKET=craftvia-documents S3_REGION=us-east-1 npx tsx scripts/test-garage-storage.ts
|
||||
|
||||
import { resolveBackupStore, type BackupTargetConfig } from "../src/server/storage/backup-store";
|
||||
|
||||
@@ -31,7 +31,7 @@ function envCfg(bucketOverride?: string): BackupTargetConfig {
|
||||
backupTarget: "s3",
|
||||
backupLocalDir: null,
|
||||
backupS3Endpoint: process.env.S3_ENDPOINT?.trim() ?? null,
|
||||
backupS3Bucket: bucketOverride ?? process.env.S3_BUCKET?.trim() ?? "isms-documents",
|
||||
backupS3Bucket: bucketOverride ?? process.env.S3_BUCKET?.trim() ?? "craftvia-documents",
|
||||
backupS3Region: process.env.S3_REGION?.trim() || "us-east-1",
|
||||
backupS3AccessKey: process.env.S3_ACCESS_KEY?.trim() ?? null,
|
||||
backupS3SecretKey: process.env.S3_SECRET_KEY?.trim() ?? null,
|
||||
@@ -55,7 +55,7 @@ async function main() {
|
||||
const store = resolveBackupStore(envCfg());
|
||||
const prefix = `__smoketest__/${process.pid}-${Date.now()}/`;
|
||||
const key = `${prefix}garage-probe.bin`;
|
||||
const payload = Buffer.from("certvia · garage smoke test · äöü · 🗄️", "utf8");
|
||||
const payload = Buffer.from("craftvia · garage smoke test · äöü · 🗄️", "utf8");
|
||||
|
||||
await store.put(key, payload);
|
||||
ok(true, "Put gegen Garage erfolgreich");
|
||||
|
||||
@@ -51,7 +51,7 @@ async function main() {
|
||||
|
||||
const inDemo = await authorizeTenantCredentials({ email: "multi@demo.example", password: PW, tenant: "demo" });
|
||||
ok(inDemo?.tenantSlug === "demo", `Slug demo ⇒ aktiver Mandant demo (${inDemo?.tenantSlug})`);
|
||||
ok(inDemo?.roles.includes("user") ?? false, "in demo: Rolle user");
|
||||
ok(inDemo?.roles.includes("technician") ?? false, "in demo: Rolle technician");
|
||||
// Rechte je aktivem Mandant verschieden (tenant-admin demo2 ≠ user demo).
|
||||
ok(
|
||||
JSON.stringify([...(inDemo?.permissions ?? [])].sort()) !== JSON.stringify([...(inDemo2?.permissions ?? [])].sort()),
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// Umzug auf die Identity ist bewusst WS4 (dieser Test darf nach WS4 angepasst werden).
|
||||
//
|
||||
// Lauf: npx tsx scripts/test-identity-schema.ts
|
||||
// Nutzt die lokale Postgres-DB (Container isms-tool-postgres-1); .env liegt im Worktree.
|
||||
// Nutzt die lokale Postgres-DB (Compose-Service postgres); .env liegt im Worktree.
|
||||
// Setzt den Demo-Seed voraus (npx tsx prisma/seed.ts).
|
||||
|
||||
import "dotenv/config";
|
||||
|
||||
@@ -10,7 +10,7 @@ import { closeMailProvider } from "../src/server/mail/provider-smtp";
|
||||
* SEC1 — Abnahmetest der Mail-Strecke (`npx tsx scripts/test-mail.ts`).
|
||||
*
|
||||
* Prüft ohne laufende App:
|
||||
* 1. Alle Templates rendern in de und en, HTML **und** Text, mit Certvia-
|
||||
* 1. Alle Templates rendern in de und en, HTML **und** Text, mit Craftvia-
|
||||
* Branding und Dachmarken-Fußzeile.
|
||||
* 2. Transaktionsmails tragen KEINEN Abmelde-Hinweis, Benachrichtigungen schon.
|
||||
* 3. Ein echter Versand landet im lokalen SMTP (Mailhog/Mailpit) und das
|
||||
@@ -41,7 +41,6 @@ const SAMPLE = {
|
||||
email_changed_notice: { name: "Erika Muster", newEmail: "neu@example.test", when: "heute" },
|
||||
mfa_changed: { name: "Erika Muster", change: "aktiviert", when: "heute" },
|
||||
notification: { name: "Erika Muster", subject: "Neuer Auftrag", body: "Text", actionUrl: "https://example.test/t", eventType: "work_order_assigned" },
|
||||
incident_notification: { name: "Erika Muster", subject: "Neuer Vorfall gemeldet", body: "Text", actionUrl: "https://example.test/i", refNo: "INC-2026-0042" },
|
||||
test: { name: "Erika Muster", when: "heute" },
|
||||
} as const;
|
||||
|
||||
@@ -54,8 +53,8 @@ async function main() {
|
||||
const ok =
|
||||
r.subject.length > 0 &&
|
||||
r.html.includes("<!doctype html>") &&
|
||||
r.html.includes("Certvia") &&
|
||||
r.html.includes("Ein Produkt von GEFIM") &&
|
||||
r.html.includes("Craftvia") &&
|
||||
r.html.includes("Handwerk. Digital auf Kurs.") &&
|
||||
r.text.length > 0 &&
|
||||
!r.text.includes("<");
|
||||
check(`${key}/${locale}`, ok, `subject="${r.subject}"`);
|
||||
|
||||
@@ -33,7 +33,7 @@ async function main() {
|
||||
const demo2 = await resolveActiveMembership(multi.id, inDemo2.id);
|
||||
ok(demo?.tenantSlug === "demo", `demo-Mitgliedschaft → Mandant demo (${demo?.tenantSlug})`);
|
||||
ok(demo2?.tenantSlug === "demo2", `demo2-Mitgliedschaft → Mandant demo2 (${demo2?.tenantSlug})`);
|
||||
ok(demo?.roles.includes("user") ?? false, "in demo: Rolle user");
|
||||
ok(demo?.roles.includes("technician") ?? false, "in demo: Rolle technician");
|
||||
ok(demo2?.roles.includes("tenant-admin") ?? false, "in demo2: Rolle tenant-admin");
|
||||
ok(
|
||||
JSON.stringify([...(demo?.permissions ?? [])].sort()) !== JSON.stringify([...(demo2?.permissions ?? [])].sort()),
|
||||
|
||||
Reference in New Issue
Block a user