L14 Abrechnungsübersicht: Datenmodell, Migration, Rechte und Modul
Neue Tenant-Tabellen work_order_milestones und billing_records (RLS, TENANT_MODELS, PII-Felder), Partial-Unique-Indizes je Quelle, billing_record_id an time_entries/material_usages. Rechte billing:read/billing:write (Backoffice, Mandantenadmin), Modul billing, Events milestone.*. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -71,6 +71,8 @@ const ENTITY_LABEL: Record<string, string> = {
|
||||
import_job: "Auftragsimport",
|
||||
material_usage: "Material",
|
||||
time_entry: "Arbeitszeit",
|
||||
billing_record: "Abrechnungseintrag",
|
||||
work_order_milestone: "Meilenstein",
|
||||
work_session: "Einsatzzeit",
|
||||
photo: "Foto",
|
||||
voice_note: "Sprachnotiz",
|
||||
|
||||
+5
-1
@@ -23,13 +23,17 @@ export const EVENT_TYPES = [
|
||||
"time.approval_requested",
|
||||
"time.approved",
|
||||
"time.rejected",
|
||||
// L14 Abrechnungsübersicht (Meilensteine)
|
||||
"milestone.reached",
|
||||
"milestone.confirmed",
|
||||
"milestone.rejected",
|
||||
] as const;
|
||||
|
||||
export type EventType = (typeof EVENT_TYPES)[number];
|
||||
|
||||
export type DomainEvent = {
|
||||
type: EventType;
|
||||
entityType: "work_order" | "report" | "import_job" | "sync_operation" | "time_entry";
|
||||
entityType: "work_order" | "report" | "import_job" | "sync_operation" | "time_entry" | "milestone";
|
||||
entityId: string;
|
||||
/** Short, human-readable facts for templates (no PII beyond what the recipient may see). */
|
||||
data?: Record<string, string | number | boolean | null>;
|
||||
|
||||
@@ -28,6 +28,7 @@ export const MODULES = [
|
||||
{ key: "documents", name: "Dokumente", href: "/documents", nav: "documents" },
|
||||
{ key: "notifications", name: "Benachrichtigungen", href: "/notifications", nav: "notifications" },
|
||||
{ key: "lotse", name: "Lotse (KI-Assistent)", href: null, nav: "lotse" },
|
||||
{ key: "billing", name: "Abrechnungsübersicht", href: "/billing", nav: "billing" },
|
||||
] as const satisfies readonly ModuleDef[];
|
||||
|
||||
export type ModuleKey = (typeof MODULES)[number]["key"];
|
||||
|
||||
@@ -72,6 +72,9 @@ export const TENANT_MODELS: readonly string[] = [
|
||||
"Notification",
|
||||
"SyncOperation",
|
||||
"AiGeneration",
|
||||
// L14 Abrechnungsübersicht
|
||||
"WorkOrderMilestone",
|
||||
"BillingRecord",
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -123,6 +123,9 @@ const TENANT_MODELS = new Set<string>([
|
||||
"Notification",
|
||||
"SyncOperation",
|
||||
"AiGeneration",
|
||||
// L14 Abrechnungsübersicht
|
||||
"WorkOrderMilestone",
|
||||
"BillingRecord",
|
||||
// WebAuthnCredential/Identity sind identitäts-global (kein tenant_id) → NICHT hier.
|
||||
// Craftvia-Fachmodelle hier ergänzen — UND in src/server/backup/topology.ts
|
||||
// (TENANT_MODELS) sowie per `SELECT enable_tenant_rls('<table>')` in der Migration
|
||||
|
||||
@@ -48,6 +48,13 @@ export const PII_REFERENCE_FIELDS: readonly PiiReference[] = [
|
||||
{ model: "SyncOperation", field: "userId" },
|
||||
{ model: "SyncOperation", field: "resolvedById" },
|
||||
{ model: "AiGeneration", field: "createdById" },
|
||||
// L14 Abrechnungsübersicht
|
||||
{ model: "WorkOrderMilestone", field: "createdById" },
|
||||
{ model: "WorkOrderMilestone", field: "reachedById" },
|
||||
{ model: "WorkOrderMilestone", field: "confirmedById" },
|
||||
{ model: "WorkOrderMilestone", field: "rejectedById" },
|
||||
{ model: "BillingRecord", field: "billedById" },
|
||||
{ model: "BillingRecord", field: "voidedById" },
|
||||
// Free-text person data of END CUSTOMERS (Customer/Contact/Site/Signature.signerName) is
|
||||
// tenant business data under data processing — not part of the employee subject export.
|
||||
];
|
||||
|
||||
@@ -57,6 +57,9 @@ export const PERMISSIONS = [
|
||||
"settings:templates",
|
||||
// Lotse (KI-Assistent)
|
||||
"lotse:use",
|
||||
// L14 Abrechnungsübersicht (keine Buchhaltung): Übersicht lesen / abgerechnet markieren, stornieren, Meilensteine bestätigen
|
||||
"billing:read",
|
||||
"billing:write",
|
||||
] as const;
|
||||
|
||||
export type Permission = (typeof PERMISSIONS)[number];
|
||||
|
||||
Reference in New Issue
Block a user