{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://basicstack.de/schemas/sink/db/expense/v1.0.0.json", "title": "Sink Payload: sink:expense-db-app, action expense.post v1.0.0", "description": "Senken-Payload für die eigene DB-App (sink:expense-db-app). Jede Transform-Attestierung von agent-sink-mapping erzeugt dieses Format aus einem expense.canonical-Dokument. Der Senken-Adapter prüft diesen Payload gegen Verification + OPA, legt dann einen Datensatz in der expenses-Tabelle an.", "type": "object", "additionalProperties": false, "required": ["schema", "workflow_id", "approval_id", "decision_id", "verification_ref", "canonical_payload_hash", "expense"], "properties": { "schema": { "type": "object", "additionalProperties": false, "required": ["name", "version"], "properties": { "name": { "const": "sink.db.expense" }, "version": { "const": "1.0.0" } } }, "workflow_id": { "type": "string", "pattern": "^WF-[0-9]{4}-[0-9]{4,}$" }, "approval_id": { "type": "string", "pattern": "^APR-[0-9]{4}-[0-9]{4,}$" }, "decision_id": { "type": "string", "pattern": "^DEC-[0-9]{4}-[0-9]{4,}$" }, "verification_ref": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$", "description": "SHA-256 der Verifikationsantwort vom trust-api." }, "canonical_payload_hash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$", "description": "SHA-256 des originalen expense.canonical-Dokuments, über das die Benutzerfreigabe signiert hat." }, "expense": { "type": "object", "additionalProperties": false, "required": ["employee_id", "project_code", "cost_center", "currency", "total_amount", "trip", "items"], "properties": { "employee_id": { "type": "string", "pattern": "^EMP-[0-9]+$" }, "project_code": { "type": "string", "pattern": "^P-[0-9]+$" }, "cost_center": { "type": "string", "pattern": "^CC-[0-9]+$" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" }, "total_amount": { "type": "string", "pattern": "^-?[0-9]+\\.[0-9]{2}$" }, "trip": { "type": "object", "additionalProperties": false, "required": ["start_date", "end_date", "destination"], "properties": { "start_date": { "type": "string", "format": "date" }, "end_date": { "type": "string", "format": "date" }, "destination": { "type": "string", "maxLength": 200 }, "purpose": { "type": "string", "maxLength": 500 } } }, "items": { "type": "array", "minItems": 1, "maxItems": 200, "items": { "type": "object", "additionalProperties": false, "required": ["type", "amount", "incurred_on", "gl_account"], "properties": { "type": { "type": "string", "enum": ["HOTEL", "MEALS", "TRANSPORT_FLIGHT", "TRANSPORT_RAIL", "TRANSPORT_CAR", "PARKING", "COMMUNICATION", "CONFERENCE_FEE", "OTHER"] }, "amount": { "type": "string", "pattern": "^-?[0-9]+\\.[0-9]{2}$" }, "incurred_on": { "type": "string", "format": "date" }, "description": { "type": "string", "maxLength": 500 }, "gl_account": { "type": "string", "pattern": "^[0-9]{4,6}$", "description": "Sachkonto in unserer DB-App (nicht SAP). Agent-sink-mapping bezieht es aus einer account_assignments-Query, deren Attestierung in der Transform-Attestierung unter read_materials verlinkt sein muss." }, "receipt_ref": { "type": "string", "pattern": "^pii://[A-Za-z0-9/._-]+$" } } } } } } } }