diff --git a/docs/architecture/v1.1.md b/docs/architecture/v1.1.md index 16f3bd7..e197f66 100644 --- a/docs/architecture/v1.1.md +++ b/docs/architecture/v1.1.md @@ -32,6 +32,7 @@ Diese Revision setzt die Richtungsentscheidungen der bisherigen Review-Runden um - **🆕 Session Scope Tokens:** Session-gebundene, kurzlebige Delegations-Tokens, mit denen Agenten „im Auftrag von Benutzer X in Session S" lesen dürfen. Siehe Abschnitt 3c. - **🆕 Erster produktiver Rollout:** **eigene kleine Go-DB-App** (`sink:expense-db-app` + `ds:expense-db-app`) als kombinierte Quelle und Senke. SAP folgt später. - **🆕 Begriffsklärung PII-Store:** Der Begriff bezeichnet eine **Rolle im Datenmodell**, kein Produkt. Konkrete Technologie-Wahl und Löschsemantik stehen in Abschnitt 8.4. +- **🆕 Zeilen-Allokationen auf mehrere Projekte:** Reisekostenbelege dürfen pro Zeile prozentual oder absolut auf mehrere Projekte aufgeteilt werden (Schema `expense.canonical` v1.1.0). Policy erzwingt Summenerhalt pro Item. DB-App legt eine zusätzliche Tabelle `expense_item_allocations` an. Details in Abschnitt 7.2a; Schemas unter `schemas/expense/canonical/v1.1.0.json` und `schemas/sink/db/expense/v1.1.0.json`. ## 1. Zielarchitektur @@ -570,6 +571,53 @@ CREATE TABLE sink_decision_log ( Der Adapter prüft bei jeder Lese-Anfrage: Scope-Token signiert durch trust-api, Resource und Filter aus Scope-Token decken Request-Resource und -Filter, `exp` nicht abgelaufen. Danach führt er die Abfrage aus und erzeugt die Query Attestation. +### 7.2a Zeilen-Allokationen auf mehrere Projekte (v1.1.0) + +Für Reisekosten, die anteilig auf mehrere Projekte gebucht werden sollen, nutzen wir ab `expense.canonical` v1.1.0 bzw. `sink.db.expense` v1.1.0 ein Allocation-Modell: + +- Jedes Item in `expense_items[]` trägt ein optionales `allocations[]`. Ohne Allocation gilt das top-level `project_assignment` als Default für dieses Item. +- Allocation-Entry hat `project_code`, `cost_center`, `source_attestation_ref` und einen Modus: + - `mode: "percentage"` + `percentage` (0.00..100.00) — alle Entries desselben Items mit mode=percentage, Summe exakt 100.00. + - `mode: "absolute"` + `amount` — alle Entries desselben Items mit mode=absolute, Summe exakt gleich `item.amount`. +- Mischen von Modi innerhalb eines Items ist unzulässig (OPA-Regel). +- `source_attestation_ref` ist Pflicht — bindet die gewählten Projekte/Kostenstellen an eine Query Attestation von `ds:expense-db-app`. + +**Agent-sink-mapping** löst `percentage`-Allokationen in `absolute` Beträge auf (letzte Allocation absorbiert den Rundungsresiduum, damit die Summe exakt bleibt) und schreibt in die Senke immer absolute Beträge. Die OPA-Policy `proofedmesh.transformations.expense` prüft pro Item `sum(allocations.amount) == item.amount` in Cents (siehe `policies/transformations/expense.rego`). + +**DB-Schema-Erweiterung in der eigenen DB-App:** + +```sql +-- Neu bzw. ergänzend zu 7.2: + +CREATE TABLE expense_items ( + id BIGSERIAL PRIMARY KEY, + workflow_id TEXT NOT NULL REFERENCES expenses(workflow_id) ON DELETE CASCADE, + item_index INT NOT NULL, + item_type TEXT NOT NULL, + amount NUMERIC(12,2) NOT NULL, + incurred_on DATE NOT NULL, + description TEXT, + receipt_ref TEXT, -- "pii://..." Referenz in den PII-Store + UNIQUE (workflow_id, item_index) +); + +CREATE TABLE expense_item_allocations ( + id BIGSERIAL PRIMARY KEY, + expense_item_id BIGINT NOT NULL REFERENCES expense_items(id) ON DELETE CASCADE, + project_code TEXT NOT NULL, + cost_center TEXT NOT NULL, + gl_account TEXT NOT NULL, + amount NUMERIC(12,2) NOT NULL, -- immer absolut + percentage NUMERIC(5,2), -- optional, nur informativ aus canonical mode=percentage + source_attestation_ref TEXT NOT NULL, + UNIQUE (expense_item_id, project_code, cost_center) +); +``` + +Die ursprüngliche Tabelle `expenses` behält `project_code` und `cost_center` als Kompatibilitätsfelder für v1.0.0-Vorgänge (dort gibt es nur ein Projekt pro Vorgang). Für v1.1.0-Vorgänge sind beide Felder in `expenses` NULL und die Zuordnung ergibt sich aus `expense_item_allocations`. + +Beispiel-Payloads: `schemas/expense/canonical/examples/v1.1.0/*.json` und `schemas/sink/db/expense/examples/v1.1.0/split-resolved.json`. + ### 7.3–7.5 Weitere Senken-Typen (HTTP-Webhook, Message-Queue, Dateiablage) — unverändert aus V1.1 Erstfassung. ### 7.6 Welchen Adapter wo deployen? — unverändert.