TGV · Master-Konzept · First-Trias · 11 Sektionen + §3a · Stand 2026-09-19

Sicherheit & Datenschutz First

„Wie geheim und geschützt sind meine Daten?" — die Frage hat zwei Antworten, die TGV bewusst trennt: WER sieht es (Governance: Rollen × Vertraulichkeits-Stufe, §2–§4) und WIE ist es gesichert (Schutz-Mechanik: RLS-Realität, Guards, EU-Stack, §5–§6 + §11). Diese Seite führt die Tower-erarbeiteten Konzepte zusammen — entschieden wird in den SSOT-Dokumenten (unten verlinkt). Wie TGV VIELE Kunden trägt (Hierarchie · Topologie · M1–M6 · Onboarding · White-Label) steht im Schwester-Konzept 🏢 Multi-Mandant.

„TGV ist so gebaut, dass fremde Augen by-default nie an die Daten eines Mandanten kommen — jede Grenze ist strukturell verriegelt (Schema · RLS · Guard · Modul-Vertrag), jede Ausnahme wird protokolliert. Im Zweifel dicht (fail-closed). Und der Stack ist auf EU-Souveränität ausgelegt."
— Das Bild in einem Satz (SYSTEM#01-AUFBAU) · Governance v1.1 GELOCKT (JC „passt", 28.06.2026)

§1Die Schutz-Grenzen — Landkarte (Defense-in-Depth)

Ein Zugriff muss ALLE Schichten von außen nach innen passieren — jede Schicht ist an einer anderen Ebene strukturell verriegelt. Der interaktive Graph (SYSTEM#01-Baustein, gleiche Karten-Sprache wie der Architektur-Graph) hat zwei Modi: 🛡️ Schutz-Grenzen (Defense-in-Depth) und 🇪🇺 EU-Stack (Datenfluss mit ehrlicher EU/US-Färbung, §11) — jeder Knoten öffnet per Klick sein Detail-Panel mit Regel-Text + SSOT-Verweis:

Fallback-Ansicht: Du siehst die statische Landkarte, weil der interaktive Graph nicht geladen werden konnte (JS/vendor-Libs) — die Schichten oben sind klickbar und führen zu den Detail-Sektionen. Inhaltlich sind beide Ansichten deckungsgleich.

§2Die Rollen (Ebene ① — Wer) — bewusst wenige

RolleWer ist das (Beispiel JC)Reichweite
super_adminTGV-Betreiber (Convis/Kivisai) — im Verwaltet-Modus der Haftungsträgertechnischer Voll-Zugriff, aber protokolliert; im Souverän-Modus zurückgezogen; Break-Glass-Regel s.u.
mandant_adminJC für seinen Mandantenalle Entitäten des Mandanten; setzt Rollen + Status, führt Löschungen aus
entity_memberein C3-MitarbeiterNUR seine Entität (C3), Status-gefiltert; sieht nie Privat/C4
viewerNur-Lese (z.B. Steuerberaterin auf ein Dossier)nur Ansicht, keine Beträge bei vertraulich+, kein Export
externÖffentlichkeitnur Status „öffentlich"
⛔ DIESE TABELLE BESCHREIBT DAS SOLL, NICHT DEN LIVE-STAND — Durchsetzung offen (JC 08.08.: „es sollte im Konzept sichtbar sein, dass dies noch zu machen ist"). Die fünf Rollen sind benannt und in auth_allowed_users speicherbar; was fehlt, ist die Durchsetzung feiner als „Mandant". Gemessen 08.08.: Mig 241 (7-Rang-Leiter) muss alle Gabriel-Stufen auf denselben Rang fesseln und begründet das im Kopf wörtlich mit „ein Rollenmodell für Redaktion/Familie fehlt" — die Leiter kann heute nicht ausdrücken, was diese Tabelle verspricht.
Konkret unbesetzt: redaktionelle und familiäre Kreise (die zwischen mandant_admin und viewer lägen) haben keinen Träger — deshalb sind die Zielränge 1/3/4 in Mig 241 definiert, aber unbelegt. Eine Rolle, die keine Mitgliedschaft kennt, ist ein Wort in einer Tabelle.
⚠️ Bis dahin gilt fail-closed: was sich nicht auf eine Mitgliedschaft auflösen lässt, wird wie streng_vertraulich behandelt — lieber unsichtbar als falsch geöffnet. Das ist kein Provisorium, sondern die richtige Zwischenstufe; sie kostet Sichtbarkeit, nicht Sicherheit.
Break-Glass-Regel (super_admin ist NICHT der Generalschlüssel): super_admin = Ops-Rolle, kein Default-Lesezugriff auf fremde Privat-Mandanten. Zugriff auf einen Mandanten, in dem er nicht Mitglied ist, geschieht nur bewusst + auditiert: der Helper tgv_log_break_glass(uid, mandant, grund) schreibt jeden solchen Zugriff ins Audit (Mig 220 staged, JC-DDL-GO gebündelt). Anlass war real: JCs Setup-Zugriff auf Annas Privat-Mandanten soll nie still sein. · Rollen-Wahrheit — Stand 14.09.2026 (ADMIN#04 #1968, korrigiert): Der Satz „Speicher-SSOT = auth_allowed_users, keine zweite Wahrheit" (Tower#7, 21.06.) gilt nicht mehr: seit Mig 211 (M3, 07.07.) trägt user_mandant_roles.rolle die Rolle je Mandant, und die Mandantenwand (is_super_admin · is_mandant_admin · my_mandant_ids) liest nur dort. auth_allowed_users.role ist die Tür (account-status: „gibt es eine aktive Zeile") und wird zugleich von _is_global_admin und is_global_admin als Rolle gelesen — zwei Tabellen, ein Begriff, keine Provisionierung (gemessen #1940/#1951: zwei Verwalter mit Rechten ohne Tür, vier Testkonten mit Tür ohne Rechten; Wächter check_rollenquellen_stimmen_ueberein.py). Das Mandant-Konzept hatte die Trennung so gemeint („auth_allowed_users bleibt reine Allowlist/Identität"); die Naht dazwischen wurde nie gebaut. ENTSCHIEDEN (JC 03.10.2026 „OK 2", Vorlage 2 / Register #3431) UND GEBAUT (RECHTE#02 #3615, 04.10.2026): die Mitgliedschaft ist die einzige Rollenquelle, die Tür wird rollenlos und entsteht beim Vergeben einer Mitgliedschaft automatisch — die Naht, die hier als „nie gebaut" steht, ist gebaut: assign-mandant-role legt die Türzeile an, revoke-mandant-role zieht sie mit der LETZTEN Mitgliedschaft zu (active=false, kein DELETE — die Zeile trägt die Spur). _is_global_admin liest _user_scope().is_super_admin; ep_account_status fragt die Tür nur noch als Existenz, nicht als Wert. ⭐ Wirkungsneutral, gemessen statt geschlossen (live 04.10., nur SELECT, beide Richtungen über 8 aktive Türzeilen und 9 Mitgliedschaftszeilen): Tür-Global-Admin = Mitgliedschaft-super_admin = {jcbinetti@gmail.com}, dieselbe EINE Person; Türrollen live super_admin 1 · viewer 7 · admin 0. Damit erweitert der Umbau den Owner-Bypass nicht — die Auflage aus JE-200 (#3561). Gegenbeweis vertraulich01_gegenbeweis.py --rollenquelle grün. ⛔⛔ GEBAUT IST NICHT LIVE: der Dienst-Teil ist nicht deployed (Merge = Deploy = JCs Wort) und die Datenbank-Seite ist eine PROPOSED-Datei, nicht gefahren (05_SCHEMA/PROPOSED_rechte02_tuer_ist_keine_rolle.sql: zwei Funktionskörper statt 83 Policy-Texte, dazu DROP DEFAULT auf role). ⛔ Der harte Befund dieser Bahn: auth_allowed_users.role ist NOT NULL DEFAULT ’admin’, und ’admin’ öffnet is_global_admin() — eine wörtlich rollenlose Naht hätte jeden neu zugeordneten Nutzer zum globalen Verwalter gemacht; darum schreibt die Naht den Platzhalter viewer ausdrücklich. ⭐ Und eine Fundstelle in diesem Kasten war selbst überholt: die Migrationsdateien 115/151 sagen role=’admin’, die LIVE-Körper beider Funktionen sagen role IN (’admin’,’super_admin’) — wer die Dateien für den Stand nimmt, schließt „is_global_admin ist für alle tot" (0 admin-Zeilen) und baut auf einem Fehlbefund. Bis Deploy und DDL gilt unverändert: Rechte kommen aus der Mitgliedschaft, nie aus der Tür.

§2aBetreiberzugriff und Verwalterrolle — DEV Override · Support · Break Glass · Audit (konsolidierter JC-Entscheid 04.10.2026)

Quelle: 01_ITERATIONS/CONTROL_TOWER_HANDOFF/JC_ENTSCHEID_TGV_DATENSCHUTZ_DATENHOHEIT_2026-10-04.md (JC, konsolidiert aus Workshop 03.10. und Klärungsrunde) · Kurzform JE-186 bis JE-199 · Register #3550. Arbeitsprinzip: Recht → Produktregel → technische Umsetzung. Dieser Abschnitt trennt strikt IST (gemessen 04.10.2026, live) und SOLL (JC-Entscheid, Paket in Klammern). ⛔ Die Live-Policies und 08_OPS/chat_engine/scope_gate.py bleiben die technische Wahrheit über den IST-Stand.

GegenstandIST (gemessen 04.10.2026)SOLL (JC 04.10.2026)
mandant_adminPolicy-Zweig is_mandant_admin(auth.uid(), mandant_id) öffnet jede Stufe inkl. streng_vertraulich und NULL (documents · prf_contracts · rag_chunks); im Chat hebt app.py _owner_conf_bypass auf streng nur, wenn der Verwalter Mitglied des Instanz-Mandanten ist (descriptor.scope_ref, app.py:3871) — alle sechs Chat-Instanzen zeigen auf jcbinetti, ein c3-Verwalter läuft im Chat mit Decke intern (VERTRAULICH#01 #3560, 04.10.; Korrektur #3565). 2 Personen live.Verwalter des Datenraums und der Vertragsbeziehung, nicht Eigentümer jedes Inhalts (JE-190): verwaltet User, Rollen, Plan, Entitäten, Projekte, Retention — kein automatisches Leserecht auf streng vertraulichen Inhalt (Paket 2).
Owner-BypassIST-Definition: der serverseitig als Owner/Admin erkannte Nutzer wird auf der Vertraulichkeitsachse bis streng_vertraulich geöffnet; Mandant und Entität werden nicht aufgeweitet. Wirkorte: app.py _owner_conf_bypass → scope_gate.build_scope(owner_bypass=) → base_conf = streng.Kein Zielmodell (JE-191): Name und Logik werden nicht übernommen; Ersatz ist die explizite streng-Berechtigung (JE-192). Migration vom Bypass zum Zielmodell = offener Punkt 10. Bis dahin unverändert live. JE-158 (Admin-Rahmen) bleibt davon unberührt.
streng_vertraulich„nur du“ = Ersteller/Hochlader plus Verwalter des Mandanten plus super_admin. Einzelfreigabe (zugriff_freigaben, hat_freigabe()) existiert, reicht nur bis vertraulich (app.py:6151), 0 Zeilen live.Ersteller + ausdrücklich Berechtigte (JE-192, Variante B). Trägt besonders geschützte Unternehmenskreise (Whistleblowing · Betriebsarzt · Ombudsperson · HR) — Unternehmensdaten, keine Privatdaten. Entität = „wo liegt es“, Stufe = „wer darin darf es sehen“ (Paket 2).
Ersteller-Achsenur documents.hochgeladen_von (Spalte live seit 03.10., #2139); Mail-Eingang ohne Hochlader; prf_contracts und rag_chunks folgen dem Quell-Dokument.Ersteller / created_by_user_id: hochgeladen · erstellt · erzeugt · aus KAI gespeichert (JE-189). Erstellerbeziehung ≠ Eigentum am Unternehmensinhalt (Paket 2). Entschieden (JE-200, #3561): ungestuft bleibt streng; Mail-Eingang bekommt keinen künstlichen Ersteller — Adressat (received_for_user_id / heute documents.mail_to) und Intake-/Triage-Rolle erhalten ein befristetes Intake-Recht nur zum Einstufen (NUXING: als zugriff_freigaben-Zeile mit grund=intake, endet mit der Klassifizierung); der Verwalter ist kein Stellvertreter-Ersteller.
super_adminis_super_admin(auth.uid()) ist der erste OR-Zweig jeder der drei Policies — unbedingt, ohne Schalter; 1 Person (JC), 6 Zeilen. Im Dienst: is_super_admin ⇒ keine Decke.DEV Override nur in der Entwicklungs-/Pilotphase auf ausdrücklich bestimmte Testmandanten (Testpersonen informiert) — heißt nicht Break Glass. Nach Marktreife abschaltbar und abgeschaltet: Superadmin = technische Betreiber-/Ops-Rolle, kein regulärer Inhaltsleser (JE-195, Paket 2).
Supportzugriffkein eigener Mechanismus; läuft heute über die super_admin-Rolle.nur mit ① konkretem Supportfall · ② Freigabe · ③ begrenztem Scope · ④ begrenzter Zeit · ⑤ Audit (JE-195, Paket 2).
Break Glasstgv_log_break_glass() existiert live (Mig 220); 0 Aufrufer im Dienst (08_OPS/**/*.py), 0 Break-Glass-Zeilen in audit_events (680 Zeilen gesamt).bleibt in Produktion als außergewöhnlicher Notfallmechanismus (Security-Incident · Wiederherstellung · Kunde kann nicht freigeben · technische Notlage). Pflichtfelder: Operator · Mandant · Grund · Beginn · Ende · Scope · Ressourcen/Aktionen · Audit (JE-195, Paket 2).
Audit des Betreiberzugriffsaudit_events trägt Pipeline-Ereignisse, keine Betreiberzugriffe; privacy_erasure_log 0 Zeilen.Jeder Betreiberzugriff auf Kundendaten wird protokolliert. Sicht: Kivisai vollständig · Mandantenadmin die Zugriffe auf seinen Mandanten · Privatnutzer die auf seinen Privatmandanten. Offen: Aufbewahrungsdauer, Detailtiefe, Business/Privat-Unterschiede, Admin-Sicht (JC §18).
KAI-SichtKAI liest als service_role; die Decke kommt aus _user_scope + build_scope (nur-verengen, fail-closed); Owner-Bypass hebt Verwalter auf streng; Persona nur bei genau einer Entität im Scope. Dokument- und RAG-Pfad weichen voneinander ab (DSGVO_ROLLEN_UND_PFLICHTEN_2026-10-03.md ②/③).KAI = Assistent des Users, kein privilegierter Datenbanknutzer. KAI-Sicht = User-Sicht ∩ aktueller Scope ∩ Session-Verengung; nie erweitern; das LLM bestimmt die Berechtigung nie. Second Brain bleibt scopegebunden (JE-193). Pfad-Unterschiede sind technische Lücken, kein Rollenmodell (Paket 1 messen, Paket 2 schließen).
RollenmodellCHECK user_mandant_roles.rolle = super_admin · mandant_admin · viewer · buchhalter; Beziehung und rechtliche Rolle haben keine Spalte.Drei Ebenen, nie ein Feld (JE-194): technische Rolle (admin · editor · viewer · accountant · contributor) · Beziehung (employee · contractor · tax_adviser · family_member) · rechtliche Rolle (Verantwortlicher · Auftragsverarbeiter · gemeinsam Verantwortliche). Kein Rollenwildwuchs; Collaboration über Scope + Rolle + Vertraulichkeit, keine Sonderarchitektur.
⛔ Widersprüchliche Alt-Aussagen in diesem Kompendium, seit 04.10.2026 als IST zu lesen: §2 Tabelle „mandant_admin: alle Entitäten des Mandanten“ · §3 „streng = NUR DU — aber deine KI nutzt es (Owner-Bypass)“ · §4 Matrix „Eigentümer / mandant_admin: alles (Owner-Bypass)“ und der Anker-Satz „der Eigentümer nutzt ALLE seine Docs aller Stufen“ · §3a ⑧ „Wer hochlädt, ist Eigentümer“ (SOLL: Ersteller ≠ Eigentümer) · §7 Lösch-Stufe ③ „mandant_admin (Verwaltet: super_admin führt aus)“ (SOLL: Verwalter löscht, liest aber streng nicht). Dieselben Stellen im Leitdokument 00_LEITDOKUMENT/KONZEPT_VERTRAULICHKEIT_GEHEIMHALTUNG.md (§0 v1.1-Präzisierung · §1 · §2 streng · §3 Matrix + Owner-Bypass · §4 · §8 Punkt 7) tragen den Vermerk im Text. Nichts davon ist umgebaut — Paket 1 ist Kanon und Nachweis, nicht Code.

§3Die 4 Vertraulichkeits-Stufen (Ebene ② — „wer AUSSER dir sieht es")

v1.1-Kern (relational): Die Stufe sagt, wer außer dir es sieht — NIE, ob du es nutzen darfst. Dir gehören deine Daten; deine KI nutzt sie alle, auch „streng" (Owner-Bypass). Die Stufe steuert nur, was bei ANDEREN ankommt.

öffentlich — „Darf jeder sehen, auch außerhalb von TGV."
Beispiel: veröffentlichte Buchseite, Marketing-Flyer, AGB. → in RAG · Chat · darf extern geteilt werden.
intern — „Normalfall: alle Berechtigten der ENTITÄT, offen im Team."
Beispiel: eine C3-Eingangsrechnung. → das Entität-Team sieht alles inkl. Beträge; andere Entitäten sehen es nicht. Nicht „Projekt" — die Grenze ist die Entität (C3/C4/Privat); der Scope schützt schon (Ingest-Default).
vertraulich — „Sensibel: nur mandant_admin + ausdrücklich Benannte; Beträge für andere maskiert."
Beispiel: Gehalt/Honorar, Vertrag, Strategie. → „für wen?" ist damit beantwortet: der Admin und wen er benennt; entity_member sieht das Doc mit maskierten Beträgen/PII, viewer ohne Beträge.
streng_vertraulich — „Höchst sensibel: NUR DU — aber deine KI nutzt es."
Beispiel: Arztbericht, private Steuererklärung, Vorsorge. → ja, „streng" heißt exakt „nur ich": nie an entity_member/viewer/andere; für andere höchstens „Dokument existiert" (Titel verborgen). Im RAG indexiert, Abruf nur Eigentümer (Owner-Bypass); Schutz = RLS default-deny + Verschlüsselung.
Kontext-Achse (§2a): Das Level ist eine Funktion von (Entität, Doc-Art) — dieselbe „Steuer" ist als FIRMA-Beleg intern (Buchhaltung MUSS prüfen), als Privat-Doc streng. Selbstständige = ein Mandant, mehrere Entitäten („2 Mützen"); Re-Triage verschiebt nur die FREMD-Sichtbarkeit, nie deine eigene Nutzung. · Fail-closed: unbekannter Status = wie streng behandeln — im Code real: rag_conf_rank(NULL) = 6 (Mig 241, live gemessen 19.09.; Mig 221 hatte 3). · RAG-Opt-out („auch meine KI nie") = separater per-Doc-Schalter, nicht Stufe 5.
✅ Anschluss Badge-Dossier — E4 ENTSCHIEDEN (JC 19.07.): Die Geheimhaltungs-Pille trägt die relationalen Wörter öffentlich · Team der Entität · Projekt (BALD-Stufe, E4b) · engster Kreis · nur ich — „Projekt" sitzt zwischen Entität und engstem Kreis (Platz + Farb-Abstufung), heute ausgegraut bis PROJEKT#01-Mitgliedschaften. Das Badge beantwortet „wer außer dir?" wörtlich. → E4-Karte im Dossier.

Einstufung bei Upload/Intake — die vier Regeln (JC 19.07., Register #34)

Wie eine neue Datei ihre Geheimhaltungs-Stufe bekommt — Regeln verankert 19.07. (Tower-Beratung, mit JCs Fragen abgestimmt); Umsetzung = ORCH#01-Kontrakt in der Intake-Pipeline (Bau nach 31.07., Register #34):
a) Ordner-Erbe = Default. Die Datei erbt die Stufe ihres Ordners und darf nur STRENGER sein (bestehender Kanon). Ohne Ordner-Kontext gilt der Arbeits-Default „Team der Entität".
b) ⛔ RAG fail-closed. Bis der ORCH-Vorschlag vorliegt, gilt jede neue Datei im Wissens-RAG als „nur ich": Chunks entstehen sofort, aber die Sichtbarkeit ist gesperrt — erst die gesetzte Stufe öffnet sie.
c) ORCH schlägt vor, mit Konfidenz-% (Gold-Funke) — aus dem DOKUMENT, nicht aus der Mail. ORCH urteilt über Stufe UND Entität auf der vollständigen Extraktion (Bauplan #2094, RAG#01 P1) nach der Stufen-Definition; Ordner-Erbe und Dokument-Typ sind Signale, Mail-Absender und -Empfänger höchstens ein Hinweis, nie die Regel (JC 19.09.: „Die Wahrheit zur Einstufung liegt im Dokument selbst, nicht in der Mail, mit der es versendet wurde"). Nachgeschärft 19.09.2026, Register #2121; vorher standen Absender/Empfänger als gleichrangiges Signal.
d) User entscheidet, nach Klär-Schwelle. Normalfall: still mit Badge (jederzeit änderbar im Steckbrief). 🔒-Kandidaten und gemischte Mehrfach-Uploads → Klärungs-Karte.
⚠️ ÜBERGANGS-STAND (JC-Order 19.07., damit niemand den Alt-Stand als Kanon liest): Die Zuordnung (Entität/Mandant/Vertraulichkeit beim Dokument-Eingang) läuft HEUTE überwiegend in n8n-Workflows (Regel + LLM + Default in der A2-Triage) — das ist NICHT der Zielzustand. JC wörtlich: „KI/Agent-first ODER? — es ist unklug, dass so viele wichtige Zuordnungen in n8n stattfinden." Nach dem ORCH#01-Flip (geplant 01./02.08.) übernimmt der ORCH-Agent die Klassifikation LLM/agent-first; n8n schrumpft zur Transport-Naht. Confidentiality auf documents ist heute eine Lücke (nur die Chunks sind fail-closed) → wird Teil der ORCH-Einstufungs-Pipeline oben (Regeln a–d).

§3aVertraulichkeit in der Praxis — JCs Entscheide vom 18./19.09.2026

Dieser Abschnitt zeigt den Kanon, er ersetzt ihn nicht: Quelle bleibt KONZEPT_VERTRAULICHKEIT_GEHEIMHALTUNG.md (§2, §2a, §2c, §4). Jede Zeile trägt ihren Stand: live · gebaut, Deploy offen · offen / JC · Lücke.

① Entität zuerst, dann die Stufen — am Beispiel „Marie"

Die Entität ist die Basis-Privatsphäre (wer nicht in der C3 ist, sieht keinen C3-Beleg); die Stufe verschärft nur innerhalb. „öffentlich" heißt weltöffentlich. Beispiel von JC (19.09., über TOWER#57): JC ist Verwalter der C3, Marie Mitarbeiterin der C3, dazu die Buchhalterin der C3.

BelegStufeJC (Verwalter)Marie (Mitarbeiterin C3)Buchhalterin C3 (Kreis, E3)Wer sonst
Stromrechnung der C3🔵 intern✓✓✓ mit Beträgenniemand außerhalb der C3
Werkvertrag mit Sonderkondition🟡 vertraulich✓✗✓ mit BeträgenEinzelfreigabe möglich (②)
Gehaltsabrechnung von Marie🟡 vertraulich✓✗ (in der C3 nicht; ihre eigene Kopie wäre ihre Privat-Mütze, ③)✓ mit Beträgen—
Arztbericht (Entität Privat)🔴 streng✓ (Eigentümer)✗✗nur der Eigentümer — auch seine KI nutzt ihn
AGB der C3🟢 öffentlich✓✓✓alle, auch außerhalb von TGV
Stand: die Stufen (fünf, davon Projekt als BALD-Stufe) und die Verwalter-Wand live. Die Buchhalterin als Kreis in Bau (E3, VERTRAULICH#01). Für Nicht-Verwalter gilt heute die Decke intern — Marie sieht Zeile 1 und 5.

② „Ausdrücklich Benannte": Kreise und Einzelfreigabe (E3, JC 19.09.)

FormBeispielWas sie siehtBausteinStand
Kreis: Buchhalter je Entitätdie Buchhalterin der C3heute: alles der Entität C3 bis vertraulich, mit Beträgen; nie streng; kein Schreiben. Die Beschränkung auf Belege und Verträge ist offen (⑩, Register #2150) — der Filter ist gebaut und liegt bereit (#2837)user_mandant_roles mit scope_type='entity' (vorhanden, bisher ungenutzt)Datenseite in Bau
Kreis: Projekt-MitgliedChristian Hauf als externer Projektpartnernur Belege seines Projekts; Projektrolle owner/editor bis vertraulich, commentator/viewer bis internuser_project_roles (vorhanden)Datenseite in Bau
Einzelfreigabeein Gutachter bekommt einen einzelnen Vertrag bis zum 30.11.genau diesen Beleg / Ordner / dieses Projekt, mit Ablaufdatum, protokolliert, widerrufbarerst suchen, dann bauen (keine Freigabe-Tabelle vorhanden, gesucht 19.09.)Datenseite in Bau

Die Flächen und KAI-Befehle dafür baut die Bahn RECHTE-UX#01; VERTRAULICH#01 liefert Endpunkte und Funktionen. Die SQL fährt JC, der Gegenbeweis läuft mit echten Konten.

③ Zwei Mützen: dieselbe Police, zwei Belege (Register #2121)

Zahlt die Firma eine Vorsorge für eine Person, brauchen beide den Beleg. Am echten Fall: dieselbe Datei kam zweimal per Mail.

BelegMützeStufeWarumStand
#8014C3 (Firma zahlt)🟡 vertraulichBuchung und Nachweis, aber nur die ChefsDaten: JC-Hand nach Deploy
#8016Privat / Mandant jcbinetti🔴 strengUnterlage der Person — oder was sie selbst wähltUmbuchung: JC-Hand
Gefunden: #8016 war als Dublette beendet — weil beide Kopien fälschlich in der C3 lagen. Liegen sie in verschiedenen Entitäten, beendet die Dublettenerkennung nichts (duplicate_entity_split); Deduplizierung öffnet nie mandantenübergreifend (RAG-Bauplan §7c). ORCH-Regel „Stufe folgt der getragenen Entität" #2799. Offen bei JC: ORCH erkennt „Firma zahlt, Person profitiert" und schlägt die zweite Mütze als Klärkarte vor — bis dahin entsteht sie nur durch menschliche Wahl.

④ Erst erschließen, dann einstufen — Stufe UND Entität aus dem Dokument

JC: „Die Wahrheit zur Einstufung liegt im Dokument selbst, nicht in der Mail, mit der es versendet wurde." Absender und Empfänger sind höchstens ein Hinweis.

Die Messung, die es entschied (#8279, RAG#01): der Beleg hat 67.261 Zeichen, ORCH sah bisher die ersten 6.000. Mit dem Ausschnitt schlug ORCH vertraulich vor, mit dem Volltext intern — JCs eigene Entscheidung. Der Volltext ändert das Urteil.
ErschließungStufeEntitätMensch
vollständigORCH-Urteil wird gesetzt (nie „öffentlich", nie überschreiben, über der Schwelle)endgültig—
teilweise · fehlgeschlagen · nicht unterstützt · schon gelesen ohne Nachweis · fehltkeine (= streng)gesetzt, aber vorläufig (Vermerk am Beleg)Klärkarte mit Grund

Stand: Erschließen vor dem Einstufen #2798 (RAG#01) · Anwenden auf dem Hauptweg orch_apply.apply #2800. Der n8n-Knoten lief zuletzt am 23.08. — die Naht dort (#2795) ist geschlossen.

⑤ Keine Stufe = streng — überall gleich

Ein Beleg ohne Stufe sieht nur der Eigentümer. Vorher lasen vier Stellen „keine Stufe" verschieden (Liste offen, KAI streng, Datenbank offen).

⛔ Befund 19.09. (Datenabfluss, gemessen mit der echten Sitzung des Zuschauers qa@ auf C3): lesbar waren 182 streng vertrauliche KI-Textstücke im Volltext, 3 strenge Verträge + 153 ohne Stufe und 147 Belege ohne Stufe (14 davon laut ORCH vertraulich/streng). qa@ ist der einzige Nicht-Verwalter — ein fremder Zugriff ist nicht belegt, aber die Wand fehlte.
Geschlossen durch: Dienst + KAI-Werkzeuge + drei Lesewege #2796 · Datenbank-Wand in drei Tabellen SQL bei JC (E1) · Gegenbeweis mit echter Sitzung, Werkzeug in #2796 (heute: 6 Befunde, Soll 0). Eine erste Einstufung, die öffnet, braucht einen Grund (E4) #2796.

⑥ Gleiche Stufen für alle — Auslegung lernt je Mandant (Register #2123)

Die Stufen (fünf, davon Projekt als BALD-Stufe) gelten für jeden Mandanten gleich. Welche Fälle wohin gehören, ist je Mandant verschieden und wächst über den KVP: Zuordnungen, Korrekturen und Klärkarten werden Lernereignisse, aus denen ORCH je Mandant Hinweise präzisiert — oder aufhebt. Feste Regeln (auch „privat + Personenname") sind Startwerte für ORCH, nie Wenn-Dann-Pflicht.

Ehrlich: die Schleife läuft heute nur trocken Lücke — Korrekturen der Stufe landen nicht in learning_events, pattern_rules hat 0 Zeilen, ORCH liest keine Mandanten-Hinweise. Vorschlag mit vorhandenen Bausteinen: sammeln in learning_events → verdichten in pattern_rules (Mandant im scope, Gegenbelege über conflict_count) → ein Hinweis-Block im ORCH-Prompt wie {{supplier_prior}}. Tor: JC

⑧ Wer hochlädt, ist Eigentümer — und darf bis intern öffnen (Register #2139 · #2140, JC 19.09.)

Die Person, die ein Dokument hochlädt, sieht es immer — auch ohne Stufe und bei streng. Die Stufen-Klärkarte geht zuerst an sie, an den Verwalter erst, wenn sie weiterreicht oder nach N Tagen. Sie darf verschärfen und ihr eigenes Dokument bis intern öffnen, mit Pflicht-Grund und Protokoll — nie auf öffentlich.

JCs Beispiel: Eine C3-Mitarbeiterin lädt ein Angebot hoch und stellt es selbst auf intern, Grund „für die Angebotsrunde“. Danach sehen es alle bei C3, niemand bei C4, niemand außerhalb.

Mails haben keinen Hochlader. Der Mail-Eingang läuft ohne Sitzung eines Menschen; ORCH stuft Mail und Anhänge aus dem Inhalt ein (④), die Klärkarte geht an die Verwalter.

Einführung, SQL fährt JC in dieser Reihenfolge: ① Spalte hochgeladen_von + Lesen (#2139) → ② Trigger-Regel mit Hochlader-Zweig (#2140, bricht ohne ① selbst ab) → ③ Hochlader der Altbelege nachtragen (vertraulich01_hochlader_nachtragen.py --apply). Danach Gegenbeweis mit zwei Mitarbeiter-Konten. Kanon: KONZEPT_VERTRAULICHKEIT_GEHEIMHALTUNG.md §4.

⑨ Wo eine Freigabe hängt: an den Ordnern der Projektgliederung, nicht am Speicherpfad (RECHTE-UX#01 mit TOWER#57 · ✅ JC-Entscheid 19.09., JE-175)

JCs Frage (19.09.): Kommt der Nutzer mit einem „Unterprojekt“ klar? Üblich ist die Ordnerstruktur mit Freigabe für Kreise. Er hat recht, und die Ordner gibt es als Konzept schon: die nummerierte Projektgliederung des Dokumentalisten. Vorlage: Projektordner und Rechte (löst Frage 6 der Rechte-Vorlage neu).

Gemessen 19.09.BefundFundstelle
Gliederung A (JC 14.07.)01 Akquise · 02 Anfragen · 03 Angebot · 04 Verträge · 05 Rechnungen · 06 Projekt-Daten; einsortiert vom AGENT-DOKUMENTALIST#01; Default je Mandant anpassbar (#196)GATE_REPORT_DOKUMENTE_ABLAGE.md:97-104
Gliederung B (01.09.)00_RECHERCHE · 01_ANGEBOT · 02_VERTRAEGE · 03_RECHNUNGEN/Jahr · 04_PROJEKTDATEN · PROJEKTMANAGEMENT; 09_ABSCHLUSS offen. Ihr Satz „neu, ohne Vorlage“ war falsch und ist korrigiert.00_LEITDOKUMENT/ABLAGE_KANON.md §2a
Im Codenur ein flacher Projektpfad, kein Dokumentalist-Skill, keine Ordner-Tabelle; Unterprojekt-Feld 0 von 6 benutztcredentials/_ordnung.py:224 · _registry.yaml · 05_SCHEMA
Buchhalter-Kreissieht heute ALLES der Entität bis vertraulich, ohne Filter nach Dokumentart — ② oben sagt denselben Ist-Zustand, die Beschränkung ist offen (⑩)app.py:3426 · :6700
✅ ENTSCHIEDEN (JC 19.09., „bin mit einer Empfehlung alle OK“, JE-175): Gliederung B ist der Standard, „Akquise/Anfragen“ geht in 00_RECHERCHE auf · Rechte hängen an diesen Ordnern · Verschieben warnt, blockt nicht. Offen bleiben aus dem Kanon: 09_ABSCHLUSS und Ordnername (Nummer/Name).
Die entschiedene Empfehlung (abgestimmt mit TOWER#57): EINE Struktur. Der Dokumentalist sortiert in die Projektgliederung, der Nutzer sieht sie, die Rechte hängen an ihr. ① Jeder Ordner der Gliederung ist ein Knoten mit fester Kennung, erzeugt beim Anlegen eines Projekts; der Speicherpfad wird abgeleitet. So bricht das Anpassen der Gliederung je Mandant (#196) keine Rechte. ② Freigabe an Projekt oder Ordner gilt nach unten. ③ Eine Rechnung, zwei Ansichten (Touch-once): Sie liegt einmal im Projektordner und erscheint zusätzlich in der Buchhaltungs-Ansicht (Entität/Jahr/Monat). Sichtbar ist sie, wenn ein Weg es erlaubt (Summe der Wege, RECHTE#01 R3), immer gedeckelt durch die Stufe. ④ Der Buchhalter-Kreis bekommt die Buchhaltungs-Klasse (Klassenmodell des Dokumentalisten, JC 14.07.), nicht den Projektordner. ⑤ Beim Teilen an Externe ist 03_RECHNUNGEN standardmäßig nicht dabei (Beträge). ⑥ Verschieben: Ein Beleg in einem anderen Ordner bekommt dessen Rechte (wie Drive/SharePoint). Umbenennen eines Ordners ändert nichts (feste Kennung), der Speicherort erst recht nicht. Beispiele: Angebot 01_ANGEBOT → 02_VERTRAEGE, ein Externer mit nur 01_ANGEBOT verliert es · 04_PROJEKTDATEN umbenannt, niemand gewinnt oder verliert · Rechnung aus „C3 · Belege“ in 03_RECHNUNGEN, die Buchhaltung sieht sie weiter, das Projektteam neu. Empfehlung: warnen, nicht blocken. Vorher steht da, wer gewinnt und wer verliert. Gewinnt ein Externer Zugriff, braucht es eine Bestätigung mit Grund und Protokoll (wie beim Öffnen einer Stufe, §4 des Kanons). Der Dokumentalist verschiebt allein nur, wenn niemand gewinnt oder verliert; sonst legt er eine Karte vor (JC 14.07.: nie autonom umschichten). ⑦ ✅ JC 19.09. „④–⑥ GO“ (JE-178): alle Belege der Entität, auch die im Projekt. Auflagen: das Merkmal Eingang/Ausgang ist für User UND KAI transparent (Pille/Spalte in den Listen, Filter, KAI-Werkzeug-Feld und Antwort); keine neue Rolle im TGV-Standard: „Projektsteuerung“ ist ein Etikett auf der Projektrolle owner (Vorlage „Verwalter“). Vorher: Gemessen: /dokumente zeigt Projektbelege schon (core_shell.html:9180-9182, Projektfilter nur bei gewähltem Projekt), aber ohne Projekt-Pille. K-44 kennt drei Achsen; die Projekt-Pille ist eine NEUE vierte Achse. ⛔ Korrektur 19.09.: badge_systematik.html:252 kündigt keine Pille an, sondern meint die Stufe „Projekt“ (E4b), die über Projekt-Mitgliedschaften kommt. Empfehlung: Projekt-Pille als vierte Achse (K-44) · die zwei Sorten Projektrechnungen (Eingang: was C3 im Projekt bezahlt · Ausgang: was C3 dem Projektträger stellt) als Merkmal über die vorhandene Richtung party_role (Mig 068), nicht als Unterordner, denn eine Rechnung gehört Projektsteuerung UND Buchhaltung (Touch-once) · Projektsteuerung = Etikett auf der Projektrolle owner (Vorlage „Verwalter“, entschieden statt „Verantwortliche“), sieht die Projektrechnungen mit Beträgen, sonst nichts der Entität; voll wirksam erst mit betrag.sehen (RECHTE#01 §4, S2, noch nicht gebaut).
Aufträge nach JCs OK (über TOWER#57): VERTRAULICH#01: Ordner-Knoten, Ordner am Beleg, Freigabe-Ziel „ordner“, Klassen-Filter für den Buchhalter-Kreis · RECHTE-UX#01: Screens und KAI-Sätze · Dokumentalist: legt Belege in die Knoten (Konzept, noch keine Bahn).
KAI: „Gib Marie Zugriff auf 01_ANGEBOT in Projekt X“ → Karte „Marie · Gast · Projekt X › 01_ANGEBOT · bis Projektende“. „Gib Christian Zugriff auf Projekt X“ → Karte „ohne 03_RECHNUNGEN, mit aufnehmen?“.

⑩ Welche Dokumentarten sieht der Buchhalter-Kreis? (Register #2150 · offen, JC 19.09. geparkt)

Offen (JC 19.09.2026): JC tendiert zu Variante A (mit Kontoauszügen) und will die Frage zusammen mit den Unternehmensrollen klären — intern oder extern, Steuerberater, Personalwesen: „Das betrifft eine interne, entitätsbezogene Mitarbeiter:in, oder? Das wird für heute zu komplex, wenn wir auch noch die Rollen im Unternehmen vertiefen.“ Heute gibt es kein Buchhalter-Konto (gemessen 19.09.), es fließt also nichts ab. Der Klassen-Filter ist gebaut und liegt bereit: Dienst und KAI in #2837 auf Eis, die Wand in 05_SCHEMA/PROPOSED_vertraulich01_buchhalter_klassen.sql (nicht angewandt). Unabhängig davon kommt die Kreis-Decke vertraulich auch in KAIs Werkzeugen an (#2843).

Die Vorlage, über die noch entschieden wird:

Lage. Der Kreis sieht heute alles seiner Entität bis vertraulich; ② sagt denselben Ist-Zustand. Ursprünglich war „Belege und Verträge“ versprochen — die Wand filtert nach keiner Dokumentart — und zwar an zwei Stellen: im Kreis-Zweig selbst, und im allgemeinen Mitglieder-Zweig, der jedem Mitglied des Mandanten alles bis intern zeigt und die Rolle nicht unterscheidet. Ein Filter nur im Kreis würde über den zweiten Zweig umgangen. Gemessen 19.09.: es gibt heute kein Buchhalter-Konto — noch kein Abfluss, aber das Versprechen hat keine Wirkung. Angebote und Protokolle haben heute keine eigene Dokumentart (vorhanden sind 9 Werte, gemessen); sie stehen unter Sonstiges — oder unter einer falschen Art (s. Grenze unten).

Dokumentart (doc_type)Klasse (Dokumentalist)C3 heute, bis vertraulichVariante A (Empfehlung)Variante B (eng)
RechnungBuchhaltungs-relevant247siehtsieht
GutschriftBuchhaltungs-relevant5siehtsieht
ZahlungsbelegBuchhaltungs-relevant4siehtsieht
QuittungBuchhaltungs-relevant19siehtsieht
SteuerBuchhaltungs-relevant0siehtsieht
Vertragjahresübergreifend16siehtsieht
Banking-CSV (Kontoauszüge)Buchhaltungs-relevant18siehtsieht nicht
Sonstiges (Angebot, Protokoll, Korrespondenz)—10sieht nichtsieht nicht
ohne Dokumentart—0sieht nichtsieht nicht
Empfehlung: Variante A. Beispiel: Die Buchhalterin der C3 sieht Rechnung, Gutschrift, Zahlungsbeleg, Quittung, Steuer, Vertrag und die Kontoauszüge; sie sieht kein Angebot, kein Protokoll, nichts unter „Sonstiges“. Die Kontoauszüge gehören dazu, weil sie ohne sie keine Zahlung einer Rechnung zuordnen kann — das ist ihre Arbeit. Variante B hält die Bankdaten beim Verwalter; dann muss er jede Zuordnung selbst machen.
Technik (in beiden Varianten gleich): die Liste steht an einem Ort (buchhalter_doc_typen(), im Dienst gespiegelt und per Test verglichen); der Mitglieder-Zweig schließt reine Buchhalter-Mitgliedschaften aus; der Kreis-Zweig filtert nach Dokumentart — an Belegen, an ihren Textstücken und an Verträgen. SQL: 05_SCHEMA/PROPOSED_vertraulich01_buchhalter_klassen.sql (Gegenbeweis „Buchhalterin C3 sieht kein Angebot/Protokoll“ als zurückgerollter Block). Dienst und KAI folgen im selben Auftrag; dabei wird auch die Lücke geschlossen, dass die Kreis-Decke den KAI-Werkzeugen bisher nicht übergeben wurde.
Grenze, ehrlich: der Filter kennt nur die Dokumentart. Legt ORCH ein Angebot als „Rechnung“ ab, sieht sie es. Die Dokumentart wird damit zu einer Rechte-Frage — Korrekturen daran gehören ins Protokoll.
OK-Frage an JC (geparkt): Buchhalter-Kreis nach Variante A (mit Kontoauszügen) — ja? Zusammen mit den Unternehmensrollen zu klären.

⑦ Stand je Punkt

PunktRegisterStand
ORCH-Stufe am Beleg anwenden (Hauptweg)#2125 · #2800gebaut · Deploy-Naht
Erst erschließen, dann einstufen#2104 · #2798gebaut · Deploy-Naht
Keine Stufe = streng (Dienst, KAI, Lesewege) + E4#2118 · #2796gebaut · Deploy-Naht
Datenbank-Wand (E1)#2118SQL bei JC
Weitere Lesewege ohne Decke (8 Endpunkte)eigene Bahnin Arbeit
ORCH-Prompt „zwei Mützen"#2122 · #2799gebaut · Deploy + SQL im selben Fenster
95 Altbelege nach ORCH-Urteil (E2 = B) + Chunks erben#2118 · #2120Werkzeug bereit · JC nach Deploy
#8014 / #8016 zwei Mützen#2119 · #2121JC-Hand nach Deploy
Kreise + Einzelfreigabe (E3)VERTRAULICH#01 · RECHTE-UX#01in Bau
Hochlader sieht sein Dokument · Klärkarte zuerst an ihn#2139 · #2820live 1.12.179 (Naht 5b) · SQL ① + ③ bei JC
Hochlader öffnet bis intern (nie öffentlich)#2140 · #2817gebaut · Deploy JC-Wort 19.09. · SQL ② bei JC
Projektgliederung B + Rechte an ihren Ordnern + Verschieben warnt (⑨)#2128 · JE-175entschieden 19.09. · Bau: Ordner-Knoten VERTRAULICH#01, Flächen RECHTE-UX#01
Zweite Mütze als ORCH-Klärkarte—JC-Entscheid offen
Buchhalter-Kreis: nur Buchhaltungs-Klassen#2150offen, JC 19.09. geparkt — Tendenz A, mit den Unternehmensrollen zu klären (⑩); Filter vorbereitet (#2837 auf Eis)
Lernschleife je Mandant#2123läuft nur trocken · Tor JC

§4Die Rechte-Matrix — Rolle × Status → Konsequenz

Lesart: was darf diese Rolle mit einem Doc dieses Status, innerhalb der berechtigten Entität? (Governance §3, gekürzt — SSOT hat die volle Matrix inkl. RAG-Abruf-Zeilen.)

öffentlichinternvertraulichstreng_vertr.
Eigentümer / mandant_adminallesallesallesalles (Owner-Bypass)
entity_membersehen + Beträge + KIsehen + Beträge + KIsehen, Beträge maskiertnur „existiert"
viewersehensehen, kein Exportsehen ohne Beträgenichts
externsehen———
Status ändernmandant_adminmandant_admin + Eigentümermandant_adminnur Eigentümer/super_admin

Owner-Bypass (der Eigentümer nutzt ALLE seine Docs aller Stufen — auch in der KI) und fail-closed (Status NULL = wie 🔴 streng für Andere) sind die zwei Anker der Matrix. Wie Änderungen ablaufen (Gates, Audit, Löschen) → §7 Lebenszyklus.

⛔ IST, nicht Zielmodell (JC 04.10.2026, JE-191): die Zeile „Eigentümer / mandant_admin: alles (Owner-Bypass)“ beschreibt den Live-Stand (Policy-Zweig is_mandant_admin, app.py _owner_conf_bypass). SOLL: streng_vertraulich = Ersteller + ausdrücklich Berechtigte (JE-192); der Verwalter ohne Erstellerbezug sieht nur „existiert“; mandant_admin ≠ owner jedes Inhalts (JE-190). IST/SOLL je Gegenstand → §2a.
Abgrenzung Owner-Bypass ↔ Admin-Rahmen (Klärung 17.07., JE-158): Der Owner-Bypass schützt gegen ANDERE — er sagt nie, was DU nutzen darfst. Daneben gibt es die selbst gesetzte Außenkante des Mandanten (Admin-Rahmen / mandant_policy, Mig 223 DO-NOT-APPLY, noch nicht auf master): der Mandant beschränkt sich auditierter Weise selbst, und DIESE Kante darf auch gegen den Owner-Bypass verengen. Kein Widerspruch, zwei Achsen — die Stufe fragt „wer außer dir?", der Rahmen fragt „was hat dieser Mandant sich selbst erlaubt?". Ändern = Policy ändern (auditiert), nie Session-Trick. SSOT-Wortlaut: KONZEPT_VERTRAULICHKEIT_GEHEIMHALTUNG.md §3.

§4bDie Navigations-Matrix — Rolle × Screen (wer sieht welches Menü)

§4 sagt, was eine Rolle mit einem Daten-Stück darf. Diese Matrix beantwortet die andere Frage (JC 10.08.): welche Menüpunkte / Screens eine Rolle überhaupt zu sehen bekommt. Kern-Satz: Ein Externer eines Projekts sieht NICHT das ganze TGV-Menü — er sieht seinen Projekt-Arbeitsraum, sonst nichts. Zwei Achsen, die zusammenspielen: die Sicht-Klasse (dieser §) entscheidet, welche Screens erscheinen; §4 entscheidet, welche Datenzeilen darin sichtbar sind.

⚠️ IST heute (Code-verifiziert, core_shell.html): Das Menü wird deklarativ aus NAV_GROUPS gerendert (:1649, Filter :7144). Die EINZIGE Rollen-Prüfung ist binär super_admin vs. alle (isSuperAdmin() :1618); nur 2 von ~33 Sidebar-Einträgen sind gegatet („Zur Abnahme" :1652, „Konzepte" :1671). Jeder eingeloggte Nicht-super_admin sieht heute alle übrigen ~31 Einträge — inkl. Buchungen, Verträge, Verwaltung/Billing/Audit, Plattform/Skills/System. Der Code sagt es selbst (:1603 „⚠️ UX-Gate, KEINE Autorisierung"). ⇒ JCs Vermutung stimmt: heute würde der Projekt-Externe das ganze Menü sehen. Die folgende Matrix ist der SOLL-Rahmen; die Lücke steht ehrlich in §10.

Fünf Sicht-Klassen — Screens werden NICHT einzeln aufgezählt (eine Liste veraltet beim nächsten SCREEN-COMPOSER-Screen), sondern in wenige Klassen einsortiert. Jeder Screen deklariert seine Klasse (Vertrag); die Shell zeigt ihn nur, wenn die Rolle die Klasse trägt.

Sicht-KlasseWas liegt darin (heutige Menü-Gruppen)Wer trägt sie
T0 · öffentlichLanding · Login · öffentliche Mandant-Seite (Anna)jeder, auch unauth. (extern)
T1 · Projekt-RaumHeute/Todo · Projekt-KAI · Dokumente des Projekts · Finanz-Übersicht mit Rechnungen des Projekts — JCs BeispielProjekt-Mitglied + Projekt-Externer (user_project_roles), OHNE Mandant-Recht
T2 · ArbeitsplatzEingang (Inbox/Sammeltore/Triage/Klärung) · Buchungen · Verträge · Auswertungen · Reisen · Bereiche (Finanz/RKA/Steuer/Projekt)entity_member + mandant_admin (eigene Entität/Mandant)
T3 · VerwaltungVerwaltung (Mitglieder · Module · Aufbewahrung · Audit · Branding · Billing) · Stammdaten (Regeln · Persona)mandant_admin
T4 · BetriebPlattform (Assistent · Wissen · Skills · System) · Konzepte · Zur Abnahme · Cross-Mandantsuper_admin
T0 öffentlichT1 Projekt-RaumT2 ArbeitsplatzT3 VerwaltungT4 Betrieb
super_admin✓✓✓✓✓
mandant_admin✓✓✓✓—
entity_member✓✓ seiner Projekte✓ seiner Entität——
viewer✓✓ nur lesen✓ nur lesen, kein Export——
Projekt-Externer✓✓ NUR sein Projekt-Raum———
extern / unauth.✓————

Die gezeigten Menüpunkte = Vereinigung der Klassen, die die Mitgliedschaften des Aufrufers tragen. Ein Nutzer mit nur einer Projekt-Rolle (kein Mandant-Recht) bekommt allein T1 — der Rest des Menüs entsteht gar nicht. Default-Deny: trägt die Rolle die Klasse nicht, wird der Eintrag NICHT gerendert (nicht nur ausgegraut).

⭐ REGEL, keine Liste (zukunfts-fest gegen SCREEN-COMPOSER): Neue Screens entstehen künftig laufend durch den SCREEN-COMPOSER-Agent. Eine feste Menü-Liste wäre beim nächsten Screen veraltet. Deshalb ist die Sichtbarkeit eine Deklaration am Screen, kein zentrales Verzeichnis:
① Jeder Nav-Eintrag / jedes Modul trägt eine min_klasse (T0–T4) — genau wie heute schon show:()=>isSuperAdmin() (core_shell.html:1652), nur generalisiert von „binär" auf „5 Klassen".
② Die Shell filtert NAV_GROUPS gegen authorizedKlassen(rolle, scope) — analog zum bestehenden authorizedScopes()-Muster (MODULE_CONTRACT.md §2/§7).
③ Default-Deny bei Unterlassung: deklariert ein neuer Screen KEINE Klasse, gilt er als T4 (nur super_admin) — ein neuer Screen leakt nie durch Vergessen. Der SCREEN-COMPOSER-Vertrag (screen_factory_contracts.json) macht min_klasse zum Pflichtfeld (Guard check_screen_factory_contracts.py).
So ist die Matrix eine Regel, die jeder künftige Screen automatisch erbt — nicht eine Liste, die jemand nachpflegen muss.
JCs Leitfall — der Projekt-Externe: „Mitarbeiter an einem Projekt + Externe" bekommen einen Projekt-Arbeitsraum als einzige TGV-Sicht: Heute/Todo · Dokumente des Projekts · Projekt-KAI · Finanz-Übersicht mit Rechnungen des Projekts. Technischer Anker existiert bereits: user_project_roles (Mig 113 — owner/editor/author/commentator/viewer) mit scope_type='project'. Der Externe = eine Projekt-Zeile OHNE user_mandant_roles-Eintrag ⇒ trägt nur T1. Die Daten im Raum sind zusätzlich §4-gefiltert (nur Belege seines Projekts, Vertraulichkeit greift). Menü-Klasse (dieser §) + Daten-Matrix (§4) = Voll-Isolation. Offene Entscheide für JC stehen in jc_entscheide.html (Zuschnitt T2↔T3 für Stammdaten/Regeln; ob „viewer" mandant-weit oder entitäts-gebunden; ob entity_member als DB-Rolle real wird — heute nur Konzept, §2).
Die Verwaltungs-Sicht — ein Kanon für sieben Gegenstände (ADMIN#04, 14.09.2026, #1967/#1968): Die Gruppe „Verwaltung" ist heute an die Sicht-Klasse T3 (mandant_admin und höher) gebunden; /verwaltung ist EINE Route mit Parameter, das Menü führt neun Türen — fünf echte Flächen (members · rechte · audit · skills · regeln), vier Platzhalter (modules · retention · branding · billing), dazu konzepte (super_admin) und /prompts. Gemessen (#1967): verwaltbar sind Mandant (an/aus, Regel-Verweise), Mitgliedschafts-Rolle und das Orchestrator-Modell (eine Setzstelle); nur lesbar Rechte, Skills, Prompts; gar nicht Agenten, die Tür-Rolle, llm_aufgaben und tunable_params. Der Kanon, der daraus folgt — eine Fläche /verwaltung/<gegenstand> je Gegenstand, immer dieselben vier Teile: ① Liste (K-33-Tabelle, Sicht = Mitgliedschaft des Aufrufers, nie Default) · ② Steckbrief (Detail-Panel mit Herkunft: gemessen / angemeldet / widerspricht, wie secFaehigkeiten) · ③ Schreibweg mit Freigabe (der Endpunkt entscheidet das Recht, die Fläche verbirgt nur; jede Änderung als neue Fassung mit Rückweg auf den ausgelieferten Stand, #1267) · ④ Spur (jede Änderung in agent_events, sichtbar unter /verwaltung/audit). Jede Fläche trägt Kanon-Zeile + Contract (#974, GATE_A_VERWALTUNG.md) und einen qa@-Gegenbeweis (viewer sieht nichts Fremdes, mandant_admin nur seinen Mandanten). Reihenfolge nach JCs Schmerz: Rechte/Rollen (setzt den Rollen-Entscheid in §2 voraus) → Skills → Prompts → Modelle → Agenten. Solange ein Gegenstand keinen Schreibweg hat, sagt seine Fläche das — „liest nur" ist ein Befund, kein Etikett.

§5Geschützte Tabellen — die RLS-Realität (Umsetzungswahrheit)

Nicht „RLS ist an" als Behauptung, sondern je Kern-Tabelle der Code-verifizierte Stand (Migrationen in 05_SCHEMA/). Grundnetz seit Mig 037: RLS wird auf JEDER public-Tabelle erzwungen (dynamischer Loop) — seither wird das grobe Netz Tabelle für Tabelle durch schärfere Policies ersetzt:

TabelleInhaltPolicy heute (Code-verifiziert)MigrationStadium
mandanten · entities · user_mandant_rolesMandanten-Struktur + RollenRLS on (live ad-hoc, dokumentiert) + M3-Policies: Self-Read · super_admin-Bypass · Mandant-Scoping209 · 211✅ LIVE (M1–M3)
documentsBelege & DokumenteStand 19.09.2026 (live gemessen, pg_policy): Mitglieder des Mandanten bis intern, Verwalter alles; keine Stufe = streng (E1, #2118). Dazu die Zweige Buchhalter-Kreis bis vertraulich (E3, #2132), Projekt über can_user_see_confidentiality(), Einzelfreigabe (hat_freigabe) und Hochlader (#2139). Vorher (gemessen 05.09., §5b) prüfte der Mitglieder-Ast die Stufe nicht — geschlossen durch E1. Offen: der Mitglieder-Ast wertet die Rolle nicht aus (my_mandant_ids, Grenze #2134, s. §3a ⑩).142 → 212 · E1/E3 · 05_SCHEMA/PROPOSED_vertraulich01_hochlader_sieht_sein_dokument.sql:52✅ LIVE
rag_chunksdas KI-GedächtnisDieselben Zweige wie documents (Stand 19.09.2026, live gemessen); Projekt, Einzelfreigabe und Hochlader über den Quell-Beleg. Der Chat-Pfad läuft zusätzlich durch die gegatete Retrieval-RPC (§6). Seit 19.09. zieht bei jeder Beleg-Änderung ein Trigger Mandant und Stufe der Chunks nach (Trigger trg_documents_chunk_folgt_beleg, #2146; Wächter check_wand_am_chunk.py --live ③; der Altbestand — 18 Belege Mandant, 4 Stufe — ist dort als bekannt geführt).029 → 212 · 221 · 05_SCHEMA/PROPOSED_vertraulich01_hochlader_sieht_sein_dokument.sql:85✅ LIVE
txn_masterBank-Transaktionenadmin-only (txn_master_admin_all, is_global_admin) — eine von 34 Finanz-Tabellen, denen Mig 157 die role-blinde Blanket-Policy entzog037 → 157✅ LIVE
tax_filingsSteuer-Vorgängeadmin-only (in der 34er-Liste von Mig 157)027 → 157✅ LIVE
prf_contractsVerträgeMandanten-Wand wie documents (Stand 19.09.2026, live gemessen): Mitglieder bis intern, Verwalter alles, Buchhalter-Kreis bis vertraulich, Einzelfreigabe und Hochlader über den Beleg. anon-Zugriff DENIED.157 · 201 · 05_SCHEMA/PROPOSED_vertraulich01_hochlader_sieht_sein_dokument.sql:69✅ LIVE
auth_allowed_usersder Rollen-Speicher (SSOT)RLS on; wird nie roh von App-Code gelesen — nur account-status (server-seitig) + RLS-Helper037✅ LIVE
Ehrlichkeits-Fußnote (Repo ≠ Live): Die M-Migrationen 211/212/220 tragen im Repo bewusst ein ⛔ STAGED — DO NOT APPLY-Banner: Apply passiert NUR per JC-DDL-GO im Supabase-SQL-Editor, nach Negativ/Positiv-Test mit echtem Mandant-JWT. Lane-Stand: M1–M4b sind LIVE; Mig 221 ist mit Apply-Vermerk + Gate-Beweis dokumentiert (✅ APPLIED 2026-07-13, r5_gate_proof.py --live alle PASS). Die Live-DB ist autoritativ, nicht das Repo — genau dafür existiert das Prüf-Ritual im Mig-Kopf (pg_policies-Queries vor Apply).

§5aDie DREI Sichtbarkeits-Achsen — gemessen, nicht behauptet

SICHERHEIT#05 hat am 05.09.2026 alle pg_policies der laufenden DB gelesen (nicht die 05_SCHEMA/*.sql-Dateien) und jede Tabelle einer Achse zugeordnet. Anlass: das Konzept nannte für documents zwei Wege (Mandant ODER Projekt-Gast) — die Frage war, ob eine dritte Achse fehlt. Antwort: die dritte Achse ist konzipiert, aber live auf NULL Tabellen.

AchsePrädikatTabellen liveVertraulichkeit geprüft?Stand
MANDANTmandant_id = ANY(my_mandant_ids(auth.uid()))23NEINLIVE
PROJEKTproject_id = ANY(get_project_ids_for_user(...)) AND can_user_see_confidentiality(...)28JALIVE
ENTITÄTentity = ANY(my_entities(auth.uid()))0—NUR DATEI, nicht angewandt
ADMIN/SELFis_global_admin() · is_super_admin() · user_id = auth.uid()75—LIVE
OFFEN (qual=true)keines — jeder Angemeldete9NEIN3 davon kritisch, s.u.

Regale, über die diese Liste gilt (R-193): ① pg_policies + pg_class.relrowsecurity der laufenden Supabase-DB, gelesen über 08_OPS/db_query.py · ② 05_SCHEMA/*.sql (271 Dateien) · ③ public.tgv_migrations. NICHT gelesen: Views und deren security_invoker-Flag · Trigger und Funktionen ausserhalb der genannten RLS-Helfer · n8n-Workflows · Endpoint-Guards der App-Schicht (die als service_role laufen und RLS per Design umgehen, s. §6). Eine Aussage über diese vier Regale ist hier NICHT enthalten.

Grundnetz bestätigt: 141 von 141 public-Tabellen haben RLS aktiv, keine einzige mit RLS aus; eine Tabelle hat RLS an und null Policies (= vollständig zu, fail-closed).

⭐ Warum die Entitäts-Achse selbst im Zielbild wenig trägt: my_entities(u) ist definiert als die Slugs der entities, deren mandant_id in my_mandant_ids(u) liegt (05_SCHEMA/213_sicherheit01_entity_rls_membership.sql:48). Sie ist damit aus der Mandanten-Achse abgeleitet, nicht unabhängig. Live gemessen: 6 Mandanten, 6 Entitäten, 1:1, kein mandant_id IS NULL ⇒ beide Achsen erzeugen heute dieselbe Menge. Ein Schutz entsteht erst, wenn ein Mandant mehrere Entitäten trägt UND die Rolle an eine Entität gebunden wird (entity_member, §2 — heute nur Konzept).
⛔ Warum die Datei nicht live ist (Befund 05.09.): 05_SCHEMA/213_sicherheit01_entity_rls_membership.sql trägt die Nummer 213 — in tgv_migrations ist num='213' seit 2026-07-07 von 213_prf_contracts_mandant_fk_rls belegt. Nummernraum-Kollision: die Migration kann unter dieser Nummer nicht laufen. Von ihren vier Ziel-Tabellen tragen drei (debtor_invoices · debtor_customers · invoice_number_sequences) inzwischen eine Mandanten-Achse und sind zu; outbound_mails blieb als einzige offen.
⛔⛔ ZWEI ENTITÄTS-VOKABULARE — warum die Achse nicht überall anwendbar ist (gemessen 05.09.): Die vier Tabellen der Migration 213 speichern entity als Text und würden gegen entities.slug verglichen. Nachgezählt, wie viele Werte kein gültiger Slug sind:
outbound_mails 49 Zeilen → 0 ungültig · debtor_invoices 25 → 25 · debtor_customers 9 → 9 · invoice_number_sequences 6 → 6.
Die Vokabulare: entities.slug führt c3-convis-gmbh · c4-convis-sarl · privat · kivisai · gabriel · anna-leonenko, das Rechnungswesen führt c3 · c4 · priv.
⇒ entity = ANY(my_entities()) träfe auf den drei Rechnungs-Tabellen auf keine einzige Zeile zu — kein Schutz, sondern ein vollständiger Ausfall (40 Zeilen für jeden unsichtbar, fail-closed). ⭐ Und sie sind heute nicht offen: sie tragen bereits die Mandanten-Achse. Die Entitäts-Achse würde dort funktionierenden Schutz durch einen Ausfall ersetzen. Vorbedingung ist deshalb die Vokabular-Brücke (entSameScope()-Klasse), nicht die Policy. Bei outbound_mails — dem einzigen echten Loch der vier — trägt die Achse sofort.

Die Naht — wo zwei richtige Regeln eine Menge erzeugen, die keiner hat

🔥 documents: die Vertraulichkeitsstufe hängt nur an EINEM der zwei Äste. Volltext der Live-Policy documents_select_mandant_or_project:
is_super_admin(uid) OR mandant_id = ANY(my_mandant_ids(uid)) OR (project_id IS NOT NULL AND project_id = ANY(get_project_ids_for_user(uid)) AND can_user_see_confidentiality(uid, project_id, confidentiality_level))
⇒ Ast A (Mandant) prüft die Vertraulichkeit nicht. Ast B prüft sie.
Und die zwei Äste haben verschiedene Vokabulare. can_user_see_confidentiality() kennt nur die Memoir-Wörter (excluded · private_gabriel_jc · editorial_team · family_close · publishable_book · NULL), alles andere fällt in ELSE false. Das Geschäfts-Vokabular ist ein anderes: intern 416 · streng_vertraulich 30 · vertraulich 4 = 450 Dokumente — und diese 450 haben ausnahmslos project_id IS NULL (gemessen). Sie sind also nur über Ast A erreichbar, wo nicht geprüft wird.
⭐ Folge: streng_vertraulich wird nirgends durchgesetzt. Die Stufe existiert als Datum (§3) und als Doku — aber nicht als Regel. Auf Ast B träfe sie default deny; Ast B wird für sie nie betreten.
Dazu die Rolle: my_mandant_ids(u) = SELECT DISTINCT mandant_id FROM user_mandant_roles WHERE user_id=u — die Spalte rolle kommt darin nicht vor. Für Ast A ist viewer identisch mit mandant_admin. Gegenbeweis live: qa@startact.ai hat rolle='viewer' auf c3 und liest damit 316 intern + 10 streng_vertraulich Dokumente von c3. Lesend — der Schreibweg ist zu (documents_write_mandant_admin verlangt is_mandant_admin()).
Abgrenzung zur Narbe 22.07.: damals fiel die Mandanten-Wand (qa@ sah C4 und Privat). Die steht heute — qa@ sieht nur c3. Was fehlt, ist die zweite Wand innerhalb des Mandanten. Die Narbe hat einen zweiten Boden.
🔥 Offene Tabellen (qual=true für authenticated) — gemessen 05.09.:
outbound_mails — einzige authenticated-Policy outbound_mails_authenticated_all, cmd=ALL, qual=true, with_check=true. Inhalt: 49 Zeilen über 4 Entitäten in 4 Mandanten (c3 27 · c4 14 · privat 6 · kivisai 2). Gegenbeweis: qa@startact.ai und binetti@convis.com sind Mitglied in genau einem Mandanten (c3) und lesen dennoch 22 fremde Zeilen — und dürfen sie wegen cmd=ALL auch schreiben und löschen. ⛔ ungefixt
document_supplier_overrides — qual=true, 7 Zeilen über 2 Mandanten (via documents.mandant_id). Abgeleitetes Objekt, das den Schlüssel seines Trägers nicht erbt. ⛔ ungefixt
mail_templates — qual=true, obwohl die Tabelle eine mandant_id-Spalte hat; heute 2 Zeilen, beide mandant_id IS NULL. Strukturell offen, inhaltlich noch leer — die erste mandantenbezogene Vorlage leckt. ⚠ Zeitbombe
kb_km_satz (2) · kb_orte_alias (141) · rka_trip_segments (0) — keine Scope-Spalte, echte Referenzdaten; Geheimhaltung unkritisch. Aber cmd=ALL, with_check=true ⇒ jeder Angemeldete darf sie überschreiben. Integrität, nicht Vertraulichkeit.
components · llm_models · taxonomies — qual=true, aber nur SELECT auf Referenzdaten. Unkritisch.
Reparatur-Vorschläge (SICHERHEIT#05 war rein lesend — kein Apply, keine DDL):
① Sofort, klein, ohne Entscheid: outbound_mails · document_supplier_overrides · mail_templates bekommen dieselbe Mandanten-Achse wie ihre drei Schwestern (*_select_mandant + *_write_mandant_admin + *_no_anon). Nicht die Entitäts-Achse — die ist aus der Mandanten-Achse abgeleitet und trägt heute keinen zusätzlichen Schutz (s.o.). document_supplier_overrides braucht dafür den Weg über documents.mandant_id.
② Braucht JC-Entscheid: die Vertraulichkeitsprüfung gehört vor die Klammer statt in Ast B. Dafür muss can_user_see_confidentiality() erst (a) das Geschäfts-Vokabular intern/vertraulich/streng_vertraulich kennen und (b) Rollen aus user_mandant_roles.rolle lesen, nicht nur aus user_project_roles. Das ist ein Entwurf, kein Handgriff — der Zuschnitt (sieht mandant_admin ein streng_vertraulich? §3 sagt „nur ich") ist Geschäfts-Arbitrage.
③ Nummer: 05_SCHEMA/213_sicherheit01_entity_rls_membership.sql braucht eine freie Nummer, sonst kollidiert ihr Schluss-INSERT.

§6Sicherheits-Mechanismen — WIE jede Grenze strukturell gebunden ist

Analog zur Seitenbau-Lehre („Kanon strukturell binden, nie ans Gedächtnis"): jeder Mechanismus nennt die Ebene, an der er verriegelt ist — Schema, RLS, Guard am Wirkort oder Modul-Vertrag. Das ist die Antwort auf „WIE ist es gesichert?":

MechanismusWas er leistetGebunden anStand
Default-Deny-StandardSensible Tabellen: RLS on, nichts sichtbar ohne explizite Policy — nie viewer, nie cross-mandantSchema + RLS (Identity-RLS-SSOT §4, durable Regel)LIVE Standard
fail-closedUnbekannt = dicht: NULL-Status zählt wie streng; User ohne Tabellen-Zeile → 403RLS-Prädikat + Funktion (rag_conf_rank(NULL)=3)LIVE
ctx = Object.freezeJedes Shell-Modul bekommt seinen Scope EINGEFROREN — es gibt keinen Setter; ein Modul kann seinen Scope nie selbst erweiternModul-Vertrag (MODULE_CONTRACT.md: „ctx ist Object.freeze'd, ctx.scope ebenso")LIVE Kanon
RLS-Helperis_super_admin() · my_mandant_ids() · is_mandant_admin() — SECURITY DEFINER über die EINE Rollen-Quelle; alle Policies rechnen damitRLS (Mig 211), Quelle = auth_allowed_users/user_mandant_roles✅ LIVE
service_role-Grenzen8n/Skills laufen als service_role = RLS-bypassed BY DESIGN → die App-Schicht MUSS scopen („Skills scopen selbst") — deshalb sitzen Gates am Wirkort, nicht nur in der DBGuard am Wirkort (Endpoint/Skill)⚠ teils — Endpoint-Scope-Guard erst 2/57 (§10)
Retrieval-RPC-GateDer Chat ruft das KI-Gedächtnis NUR durch search_knowledge_scoped: Mandant ∈ erlaubter Menge + Entität + Vertraulichkeits-Decke, fail-closed; Owner-Bypass = der AUFRUFER setzt conf_max (aus scope_gate), NIE das LLMFunktion (DEFINER-RPC) — das Gate sitzt IN der RPC, weil service_role RLS bypasst✅ APPLIED 13.07. + Gate-bewiesen (alle PASS)
Break-Glass-Audittgv_log_break_glass(): super_admin-Zugriff auf fremden Privat-Mandanten wird protokolliert — bewusst, nie still (§2)Audit (agent_events.mandant_id, Mig 218)staged (Mig 220, JC-DDL-GO)
Datei-Wand (Bucket je Mandant)Jede Entität hat ihren Hetzner-Bucket mit eigenem Schlüssel und eigener Policy; der Dienst liest je Bucket mit DESSEN Schlüssel (_storage.config_fuer_bucket, fail-closed). Wer eine Datei sehen darf, entscheidet aber die ZEILE, nicht der Bucket: file-url und die drei Schwester-Endpunkte lösen zuerst documents über RLS (mandant_id, JWT des Aufrufers) plus _user_scope auf (app.py:5455ff) und presignen erst danach.
⛔ WARNUNG für jeden künftigen Export- oder Listen-Bau: Ein Objekt kann im Bucket einer anderen Entität liegen als seine Zeile sagt (gemessen 19.09.: 16 Belege, z. B. ein C4-Beleg im C3-Bucket, drei C3-Belege im privaten; Register #2171). Heute liest das kein Mensch, weil kein Weg einen Bucket aufzählt. Ein Export „alles aus Bucket X“ oder ein LIST über einen Mandanten-Bucket würde diese Belege an den falschen Mandanten ausliefern. ⇒ Exporte und Listen laufen immer über documents-Zeilen (mandant_id + Stufe), nie über das Aufzählen eines Buckets.
Hetzner-Policies (Kreuzprobe 08_OPS/pruefe_mandanten_wand.py) + Lese-Chokepoint _supa_get_document✅ LIVE — Kreuzprobe 0/56 (19.09.) · 16 Objekte im fremden Bucket, Heilung JC-Ball (#1278/#1630)
Encryption-at-restGespeicherte Daten verschlüsselt — Pflichtteil des streng-SchutzesInfrastruktur (Supabase-Basis)Basis · streng-Härtung folgt
Grant-Verify-RitualSupabase-Falle (beim 221-Apply real erlebt): neue public-Funktion bekommt AUTO-EXECUTE für anon+authenticated; REVOKE FROM PUBLIC genügt NICHT → bei DEFINER-RPCs anon/authenticated explizit revoken + Grant-Verify (EXECUTE nur service_role+postgres)Ops-Ritual, im Mig-File verankertgelernt + verankert

Lesewege × Decke × Wache — jeder Weg, auf dem ein Inhalt den Dienst verlässt (Register #2179, Stand 19.09.2026)

Die EINE Liste für alle Bahnen (VERTRAULICH#01 pflegt sie; die rag_chunks-Wege hat RAG#01 gegen master nachgeschlagen, Bauplan #2094 P3). Ein Weg ohne Wache ist ein Befund, keine Zeile zum Weglassen. „CI ㊵“ = Schritt ㊵ in .github/workflows/konformitaets-guards.yml, „skipped“ gilt dort als rot.

WegEingangliestScope ausStufen-DeckeWache (Test)läuft
KAI-Chat/api/skill/core-chat → WerkzeugeBelege, Verträge, Mails, Textstücke_user_scope → build_scope (Mitgliedschaft, Kreis-Decke #2156, Aufrufer #2139)_conf_or_filter · RPC-Gate search_knowledge_scoped07_TESTS/agent_chat01/test_aufrufer_id_durchreich_2139.py · 07_TESTS/agent_chat01/test_kreis_decke_durchreich_2156.py · 07_TESTS/agent_chat01/test_hochlader_sieht_sein_dokument_2139.pyCI ㊵
ORCH-Plan/api/skills/orch/planKlassifikation, Entität, Anbieter eines Belegsnur S2S (api_key) oder Global-Admin (_is_global_admin) — alle anderen 403—07_TESTS/agent_chat01/test_lesewege_decke_2118.pyCI ㊵
Klärungen/api/skill/klaerung list_pendingVolltext offener Belege_listen_deckeDecke aus der Rolle07_TESTS/agent_chat01/test_lesewege_decke_2118.pyCI ㊵
Versand an Buchhaltung/api/skill/accountant-send · presend-report · ustva-reportPakete mit Beträgenverwaltete EntitätenVerwalter / Decke07_TESTS/agent_chat01/test_lesewege_decke_2118.py · 07_TESTS/agent_chat01/test_lesewege_decke_p3_2129.pyCI ㊵
Fach-Skillscontract-extract · vat-currency-determine · source-to-fiche · rag-ingest(-project)Beleg-Inhalt, SchreibenSchreibrolle im Ziel-Mandanten_conf_allows07_TESTS/agent_chat01/test_lesewege_decke_p3_2129.pyCI ㊵
Ablage-Sicht/api/skills/ablage · /api/skills/wartetAnbieter, Dateiname, Beträge_user_scope (mandant_id)_ueber_decke_weg07_TESTS/agent_chat01/test_lesewege_decke_p3_2129.pyCI ㊵
Datei öffnen/api/skill/file-url(s)die Datei selbstRLS mit dem Nutzer-JWT bzw. _user_scope_conf_allows + Hochlader + hat_freigabe07_TESTS/agent_chat01/test_hochlader_sieht_sein_dokument_2139.py · 07_TESTS/agent_chat01/test_e3_kreise_und_freigabe_2132.pyCI ㊵
Direkt über die DatenbankPostgREST mit Nutzer-JWTdocuments · prf_contracts · rag_chunksRLS-Policies (§5)E1/E3/Freigabe/Hochlader in der Policy07_TESTS/schema01/gegenbeweis_debtor_rls.sql · 08_OPS/vertraulich01_gegenbeweis.py (echte Sitzung)Hand
Chunk-Wand beim Schreibenfünf Schreiber von rag_chunks—rag_wand.stempel_wandclassify_chunk_visibility07_TESTS/sicherheit05/test_wand_am_chunk.pyCI Suiten
Chunk folgt BelegTrigger trg_documents_chunk_folgt_beleg (#2146)—Beleg-Mandantrag_chunk_soll_stufe08_OPS/check_wand_am_chunk.py --live ③Hand
KAI-VektorsucheRPC search_knowledge_scoped (DEFINER, nur service_role) · executors_rag.py:359 · Mig 263:216Textstücke_user_scope + user_project_roles; leere Menge = nichtsrag_conf_rank ≤ Decke (scope_gate.py); Entität: p_entities in der RPC, vor dem LIMIT (#2183, SQL bei JC — bis dahin keine Entitäts-Wand, heute latent)07_TESTS/agent_chat01/test_rag_executor.py · 07_TESTS/agent_chat01/test_mandant_kein_default.py · 07_TESTS/agent_chat01/test_chatpath_conf_failclosed.pyCI Suiten
KAI-WortsucheRPC search_knowledge_lexical (DEFINER) · executors_rag.py:686 · Mig 263:282Textstückewie die Vektorsuchedasselbe Prädikat; Entität: dasselbe p_entities (#2183)dieselben Tests + 07_TESTS/agent_chat01/test_7e_kai_rechte_2182.py · 07_TESTS/agent_chat01/test_rag_entitaets_wand_2183.pyCI Suiten
Erinnerungs-Suche (Gabriel)/api/skill/memory-search-chat (+ prompt-preview) · app.py:3252Textstücke per REST, service_role_require_project_member (app.py:6552); api_key und Global-Admin passierenNachfilter can_user_see_confidentiality07_TESTS/agent_chat01/test_lesewege_memory_search_2180.py (RAG#01, #2180, PR #2884): Tor und Nachfilter, beide RichtungenCI ㊵ nach Merge #2884
MCP-Server (lokal)alle Werkzeuge in TGV -App files/tgv_mcp_server.py, z. B. lookup_pipeline_doc → RPC lookup_user_docsalles, was die Werkzeuge lesen und schreiben; lookup_user_docs selbst nur die 6 Pipeline-Handbücher (source_type=user_doc, Stufe intern)keiner — service_role, ohne Mandant, Stufe und Aufruferkeinetragbar nur als JCs lokales Einnutzer-Werkzeug über stdio — bewacht von 07_TESTS/agent_chat01/test_mcp_nur_lokal_2181.py (rot bei anderem Transport, HTTP/SSE-App, Host/Port oder .mcp.json per URL)CI ㊵
n8n-Suche (alt)Webhook tgv-skill-rag-search → rag_search_chunksTextstückekeine (anonym)keineWorkflow live inaktiv (gemessen 19.09. von RAG#01); Löschung der Funktion liegt als PROPOSED bei JCinaktiv

§7Lebenszyklus (Ebene ③) — ändern, vergessen, löschen

Status ändern mit Leitplanken: Hochstufen jederzeit („im Zweifel strenger") · Runterstufen nur Admin/Eigentümer mit Bestätigungs-Dialog + Audit · der KI-Dokumentalist schlägt vor, entscheidet NIE · jede Änderung zeigt sofort die Konsequenz („wer verliert/gewinnt Zugriff"). Vor Runterstufen/Löschen steht die Awareness-Session als menschliches Gate (§8).

Lösch-StufeWas passiertReversibel?Stand
① KI vergisstChunks raus aus dem KI-Gedächtnis (RAG) — das Dokument bleibt in der Ablageja (Re-Index)Modell GELOCKT
② Papierkorb30 Tage Aufbewahrung, dann automatische Endlöschung — Schutz vor Versehenja (30 Tage)Modell GELOCKT
③ Endgültig (DSGVO Art. 17)Doc + Chunks + Roh-Datei + Spuren — protokolliert (Audit hält nur DASS gelöscht wurde, nie den Inhalt)neinVorbedingung offen: Erasure-fähiges FK-Design (FK-409) — Pflicht BEVOR Art. 17 versprochen wird; Backup-Erasure = Phase 2

§7 löscht ein Dokument. Wenn eine Person verlangt, dass ihre Daten gelöscht werden, gilt §7a: Sie steht an vielen Orten, und jeder Ort hat eine eigene Regel.

§7aPersonen löschen (DSGVO Art. 17) — Kontakte, Betroffene, User (Register #2145, 19.09.2026)

⛔ Offene Vorfrage (JC-Ball, Register #2241): „Löschen" heißt heute zweierlei — endgültig (02.09.) oder umkehrbar markiert (05.09.), und beide Formen sind schon benutzt worden. Welche davon Hausform wird, entscheidet JC in der Vorlage „Löschen — welche Form?" (Anlass: die Test-Uploads, JE-182). Bis dahin gilt für Personen weiter die Stufenfolge aus §7.

Ziel (JC 19.09.): Kontakte und User können ihre Daten löschen lassen. Das gilt in jedem Mandanten und auch in einer gesamten Kontakt-Datenbank; die Mandanten bleiben dabei getrennt. Schon entschieden, hier nur angewandt: das Regime je Kontakt-Klasse (GATE_A_KONTAKTE.md §6 · §9.2(c)), die Felder rechtsgrundlage + loesch_regime je Zeile (Mig 251:61-62), die Lösch-Stufen ①②③ (§7), das Lösch-Audit „dass · was · wann · wer · Rechtsgrund, nie der Inhalt“ (KONZEPT_VERTRAULICHKEIT §5), der Fristen-Kanon (08_OPS/aufbewahrung_kanon.yaml, JC 03.09.) und „Vorschau → apply nur mit freigegeben_von“ (mail_versand.senden).

① Was wir müssen — die Pflichten (Quellen abgerufen am 19.09.2026)

NormPflichtFolge für TGV
Art. 17 (1)Löschen, wenn der Zweck entfällt, die Einwilligung widerrufen wird, jemand widerspricht oder die Verarbeitung unrechtmäßig istWerbe-Kontakt (oeffentlichkeit) nach Widerruf: löschen
Art. 17 (3) b · eAusnahme: eine gesetzliche Aufbewahrungspflicht oder RechtsansprücheBeleg-Bezug ⇒ sperren bis Fristende, dann löschen
Art. 18 · § 35 (3) BDSGEinschränken statt löschen, solange eine Frist läuftgesperrt heißt: nur gespeichert. Nicht im KI-Gedächtnis, nicht in der Suche, nicht in Mailings.
Art. 12 (3) · (6)Unverzüglich, spätestens nach 1 Monat; bis zu +2 Monate mit Begründung. Bei Zweifeln die Identität prüfen.Die Uhr läuft ab Eingang, frist_bis steht im Löschprotokoll
Art. 19Empfänger der Daten über die Löschung informierenPflicht bei Weitergabe (Steuerberater, Buchhalter-Versand): Das Protokoll führt die Art des Empfängers, keine Adresse
Art. 7 (1) · 21 (3)Die Einwilligung nachweisen können; nach einem Widerspruch nie wieder WerbungMinimal-Nachweis ohne Freitext ins Protokoll, Sperrliste gegen Wiederanlage
Art. 28 (3) e · gDer Auftragsverarbeiter unterstützt bei Anfragen, der Verantwortliche entscheidet. Bei Vertragsende löschen oder zurückgeben.Rollen siehe ②, AVV siehe Vorlage E2
Art. 30 (1) fDie Löschfristen stehen im Verzeichnis der VerarbeitungstätigkeitenDie Matrix ④ ist die Vorlage dafür (Register #909)
DE Fristen§ 257 HGB / § 147 AO: Bücher + Abschlüsse 10 J. · Buchungsbelege 8 J. (seit 01.01.2025, BEG IV) · Handelsbriefe 6 J. — Beginn jeweils Ende des KalenderjahresDie Zahlen liest der Löschweg aus aufbewahrung_kanon.yaml. Hier wird keine eigene Tabelle geführt.
FR FristenCode de commerce L123-22: Buchhaltung + Belege 10 J. · LPF L102 B: 6 J. (Steuer) · CNIL: Interessenten 3 J. ab letztem KontaktC4 (SARL) rechnet mit FR-Fristen, C3 (GmbH) mit DE-Fristen

Quellen: DSGVO · § 257 HGB · § 147 AO · § 35 BDSG · L123-22 · L102 B LPF · CNIL Referenzrahmen · EDPB-Bericht Löschrecht 2025 · SDM-Baustein 60. ⛔ Keine Rechtsberatung: Die Fristen testiert der Steuerberater (C3) bzw. der expert-comptable (C4), wie im Kanon vermerkt (testiert_von ist leer).

② Wer entscheidet — Verantwortlicher je Zeile

DatenVerantwortlich (entscheidet)TGV-Betreiber
Kontakte, Belege, Mails eines Mandantender Mandant (sein mandant_admin), nur für seine ZeilenAuftragsverarbeiter: sucht, schlägt vor und führt nach Freigabe aus, entscheidet nie
TGV-Konto (Login, Rollen, Gesprächsverlauf)der Betreiber selbst (Nutzungsverhältnis)Verantwortlicher
Modus Verwaltet (§8)mandant_admin gibt freisuper_admin führt aus, protokolliert

③ Der Ablauf — fünf Schritte, einer davon ist menschlich

SchrittWas passiertWer
1 · AnfrageEingang per Mail, Formular, KAI oder Abmeldelink. Das Löschprotokoll legt eingang_am und frist_bis (+1 Monat) an; bei Zweifel wird die Identität geprüft (Art. 12 (6)).jeder Mitarbeitende nimmt an
2 · VorschauFindet die Person nur in den Mandanten des Aufrufers und zeigt jedes Fundstück mit Ort, Menge und Vorschlag: löschen, pseudonymisieren oder sperren bis Datum. Die Frist kommt aus dem Kanon. Nichts wird geschrieben.Skill person-loeschen (Vorschau)
3 · FreigabeEin Mensch prüft die Vorschau und gibt sie frei (freigegeben_von). apply läuft nur, wenn der Plan identisch zur Vorschau ist (vorschau_hash).mandant_admin (im Modus Verwaltet: JC)
4 · AusführenIn dieser Reihenfolge: ① Einwilligungs-Nachweis ins Protokoll, ② Sperrliste setzen, ③ KI-Gedächtnis (Chunks) entfernen, ④ löschen bzw. pseudonymisieren bzw. sperren, ⑤ Storage-Objekte entfernen, ⑥ Empfänger informieren (Art. 19).Skill (apply)
5 · BestätigungAntwort an die Person: was gelöscht ist und was bis wann gesperrt bleibt, mit Rechtsgrund. Das Protokoll setzt bestaetigt_am.Mail-Naht mail_bauen()

⛔ Das „Wie“ ist EIN Wert, kein Code-Zweig: Ob ein Fundstück markiert oder endgültig gelöscht wird, liest die Vorschau an genau einer Stelle aus der Konfig-Fläche (tunable_params.dsgvo01_hausform). Bis JC die Vorfrage beantwortet (Vorlage #2241 „Löschen — welche Form?", liegt JC vor; der Link folgt mit ihrem Merge) steht dort offen, und jedes Fundstück sagt: was geschehen soll, steht fest — wie, noch nicht. Damit wird JCs Antwort eine Zeile in der Konfig und kein Umbau.

④ Wo die Person steht — Datenart × Entscheid (Aufbau nach DIN 66398 / SDM-Baustein 60)

Ort (Fundstelle)EntscheidStartzeitpunkt der Frist
contacts · channels · roles · tags · segment_members (Mig 251)ohne Beleg-Bezug: löschen · mit Beleg-Bezug: Name wird pseudonymisiert, Kanäle gelöscht, active=falsesofort
contact_consents (251:207)Minimal-Nachweis (Zweck, Daten, Art des Belegs) ins Protokoll, dann löschenNachweis-Frist: Vorlage E3
documents · Storage-Objekt (Rechnung, Vertrag, Brief)sperren bis zum Fristende laut Kanon, danach Stufe ③ (§7). ⛔ Die Datei hängt an keinem Fremdschlüssel: storage_bucket und storage_url sind nur Text (Mig 148:12-13). Wer die Zeile löscht, löscht die Datei nicht mit — und vernichtet zugleich den einzigen Zeiger auf sie. Also erst die Liste einfrieren (doc_id · Bucket · Schlüssel · Mandant), dann Zeile, dann Objekt (_storage.py:49), dann Gegenprobe. Vorprüfung: rka_belege.document_id steht auf RESTRICT (136:133) und bricht eine Lösch-Reihe sonst mitten drin ab.Ende des Kalenderjahres des Belegs
debtor_customers · debtor_invoices (Mig 247)sperren (Buchungsbeleg 8 J. DE / 10 J. FR)Ende des Kalenderjahres
rag_chunks (028)sofort entfernen, auch wenn das Dokument gesperrt bleibt, denn gesperrte Daten verarbeitet keine KI (Stufe ①)sofort
outbound_mails (077)Geschäftsmail = Handelsbrief: sperren 6 J. · Werbemail: löschenEnde des Kalenderjahres des Versands
agent_events · llm_entscheidungen (Freitext)Treffer schwärzen (Kanal-Wert und Name ersetzen)sofort
chat_sessions · chat_messages (203)Kontakt-Löschung: Treffer schwärzen (gezählt, nie zitiert; nur in Sitzungen der eigenen Mandanten) · Konto-Löschung: Vorlage E1sofort
TGV-User (auth, user_mandant_roles, persona_profiles, learning_events)Konto löschen; Lernsignal bleibt ohne Person (user_id auf NULL)sofort nach Konto-Ende
BackupsHeute gibt es keines (Free Tier). Mit dem ersten Backup wird Pflicht: nach jeder Wiederherstellung die Löschungen aus dem Protokoll erneut anwenden (SDM M60.P08).—
⛔ Die Grenze, die wir bewusst ziehen (P1c): Eine Person steht in Gesprächen auf zwei Arten — ihr gehört die Unterhaltung, oder sie wird in der Unterhaltung eines anderen erwähnt. Den zweiten Fall zu finden hieße, die Gespräche aller Nutzer zu durchsuchen. Das verbietet der Kanon: „Mandanten-Wand und Vertraulichkeitsstufe gelten auch beim SUCHEN und in KAI-Antworten, nicht nur beim Anzeigen." ⭐ Eine Vorschau, die gegen die Wand verstößt, um Datenschutz zu erfüllen, ist ihr eigener Widerspruch. Deshalb: gesucht wird nur in Sitzungen der eigenen Mandanten, Treffer werden gezählt und verortet, nie zitiert. ⛔ Die Folge, offen benannt: Eine Erwähnung in der Sitzung eines fremden Mandanten bleibt unsichtbar. Bei einer Auskunft nach Art. 15 ist das eine Unvollständigkeit mit Ansage — nicht falsch, aber auch nicht das, was ein Betroffener erwartet. Sie steht in jeder Antwort unter „nicht durchsucht", und ihre Bewertung ist ein JC-Ball: „Wir finden nicht jede Erwähnung — und wir wollen sie auch nicht finden dürfen."

⑤ Mandanten-Wand — dieselbe Person in mehreren Mandanten

Ein Mensch, der bei C3 und bei C4 bekannt ist, steht dort in zwei getrennten Zeilen (contacts.mandant_id NOT NULL, 251:52). Es gibt keine gemeinsame Sammlung. Jeder Mandant löscht nur seine Zeilen. Die Suche der Vorschau läuft nur über die Mandanten, in denen der Aufrufer eine Rolle hat (my_mandant_ids aus user_mandant_roles), Default-Deny. Die Ergebnisse stehen je Mandant getrennt und werden je Mandant entschieden, denn die Fristen sind verschieden (DE ≠ FR). Betrifft eine Anfrage mehrere Mandanten, leitet der Betreiber sie an jeden Verantwortlichen weiter; er löscht nicht über die Wand hinweg. Gegenbeweis (Pflicht vor Merge): Ein Viewer auf c3 sucht eine E-Mail, die nur in c4 steht, und bekommt 0 Treffer und keinen Hinweis, dass es sie woanders gibt.

⑥ Sperrliste — damit eine gelöschte Person nicht zurückkommt

Ohne Sperrliste legt der nächste Signatur-Vorschlag oder Import die Person wieder an (Modelle: HubSpot sperrt die Adresse nach der DSGVO-Löschung, Brevo und Mailchimp ebenso). contact_suppressions hält je Mandant nur einen HMAC des Kanal-Werts mit einem eigenen Schlüssel je Mandant, keinen Klartext und keinen Namen (CNIL „liste repoussoir“). Getrennte Schlüssel bedeuten: Dieselbe Adresse hat in c3 und c4 verschiedene Werte, die Sperrliste kann also kein mandantenübergreifender Personen-Index werden. Wirkt in contact-propose (Signatur und Import laufen beide dort durch) und vor jedem Werbe-Versand. Wirkt nicht auf Korrespondenz (Rechnung, Vertrag). ⛔ Eine Sperre hat zwei mögliche Wirkungen, und sie zu vermischen wäre teuer: werbung heißt „die Person will keine Werbung" (Art. 21 (3)) — Rechnungen gehen weiter raus. zustellung heißt „der Versand-Anbieter nimmt die Adresse nicht mehr an" — dann kommt auch die Rechnung nicht an, sie sieht bei uns nur so aus. Brevo führt eine solche Liste und wendet sie auch auf Transaktionsmails an (MAIL#02 §V10e ② · §X5b, über KONTAKTE#01 21.09.); sie wird als grund='anbieter_sperre' gespiegelt und trägt zwingend wirkung='zustellung'. ⭐ Sonst beantwortet eine Zeile zwei Fragen — „darf ich werben?" ist eine Rechtsfrage, „kommt es an?" eine Tatsache, und eine unzustellbare Rechnung fällt niemandem auf, bis jemand mahnt. Solange der Kontakt existiert, ist contact_consents die Wahrheit. Die Sperrliste ist das, was die Löschung überlebt. Deshalb schreibt eine Abmeldung oder Beschwerde in einem Schritt beides: eine neue Consent-Zeile widerrufen (MAIL#02 §J5 V1) und den Sperreintrag. Bei der Löschung verschwindet die Consent-Zeile, der Sperreintrag bleibt. Die Sperrliste des Versand-Anbieters wird hier gespiegelt (MAIL_VERSAND_CONCEPT §V10e ②). Ein Hard-Bounce ist kein Sperrgrund: Er setzt den Kanal auf veraltet (§J5 V3) und hält dort jeden Versand auf. Gesperrt wird nur Werbung (Mail-Klasse 4, §J2); Korrespondenz, Buchhalter-Versand und Systempost prüfen die Sperrliste nicht.

⑦ KAI: „Lösche alle Daten von Person X“

KAI ruft person-loeschen als Vorschau auf und zeigt die Fundstücke je Mandant als EINE Tabelle (K-33) mit Entscheid und Frist je Zeile. Darunter steht ein Knopf „Löschung freigeben“, der dem Menschen gehört. KAI sagt nie „gelöscht“, bevor apply gelaufen ist, und nie „es gibt nichts“, ohne die geprüften Orte zu nennen (R-193). Gesperrte Stücke erscheinen mit Grund und Datum: „Rechnung 2024 bleibt gesperrt bis 31.12.2032, § 147 AO“.

⑧ Bauplan in Paketen

PaketInhaltStand
P0 · Konzept + DDLdieser Abschnitt · 05_SCHEMA/PROPOSED_dsgvo01_personen_loeschen.sql: Consents RESTRICT, learning_events SET NULL, Sperrliste, Löschprotokollauf master (#2826) · SQL bei JC
P1 · Skill person-loeschen (Vorschau, Kontakt-Stamm)Fundstücke je Mandant über my_mandant_ids, Entscheid je Stück aus Kanon + loesch_regime. Gegenbeweis-Test c3/c4, auf dem alten Stand rot.GO TOWER#57 · in Bau
P1b · Vorschau über Belegedocuments (Absender/Empfänger) · rag_chunks je Beleg · outbound_mails · debtor_customers. ⛔ Die Dokument-Hälfte rechnet der DIENST (_person_dokument_haelfte, app.py), denn die Decke lebt, wo sie gemessen wurde (_ueber_decke_weg/_conf_allows, E3-Kreis, ohne Stufe = streng). Der Skill bekommt die Treffer gereicht und bewertet sie nur — eine zweite Dokument-Decke im Skill wäre eine zweite Wahrheit über dieselbe Frage. Beide Hälften antworten unter EINER ausgewiesenen Reichweite.gebaut
P1c · Gespräche und Protokollechat_messages (nur in Sitzungen der eigenen Mandanten) · agent_events · llm_entscheidungen. ⛔ Die Wand steht VOR der Suche: gesucht wird nur in Sitzungen, deren scope_json einen Mandanten des Aufrufers nennt. Treffer werden gezählt und verortet, nie zitiert; der Entscheid heißt schwärzen, nie löschen — ein Gespräch gehört dem, der es geführt hat, ein Protokoll ist die Spur eines Vorgangs.gebaut
P2 · applynur mit freigegeben_von + gleichem vorschau_hash; Reihenfolge aus ③; schreibt das Löschprotokollnach DDL-Apply
P3 · Sperrlisten-Riegelin contact-propose (Signatur, Import); vor Werbe-Versand in senden() (mail_versand.py, neben der Freigabe-Sperre; nicht in mail_bauen(), sonst sperrt es die Vorschau statt des Versands — MAIL#02)nach P2
P4 · KAI-Werkzeug + KarteVorschau-Tabelle + Freigabe-Knopf, Bestätigungsmailnach P2
P5 · Backup-Replaymit dem ersten Backup (Register #907)wartet auf Backup

⑨ Workshop DSGVO/AVV — nach dem Funktions-Gate (JC 19.09.)

JC 19.09. (über TOWER#57): E1–E3 sind „gute Fragen, die wir in einem extra Workshop alle klären sollten. Es ist komplex und soll vollständig gelöst werden. Aber erst muss TGV überhaupt funktionieren und das Gate vorbereitet sein.“ ⇒ Nicht entschieden, bewusst vertagt. Die drei Vorlagen unten sind der Eingang des Workshops; dazu gehört die Einwilligung beim Zugang (§7b). Termin: Roadmap (TOWER#57).
E1 · Gesprächsverlauf mit KAI: „nie löschen“?
Lage: chat_sessions ist als „nie löschen“ angelegt (Mig 203:19), ohne mandant_id-Spalte, user_id ohne FK. Ein gelöschtes Konto hinterlässt damit seine Gespräche.
Variante A (Empfehlung): Der Verlauf folgt dem Konto. Konto weg ⇒ Verlauf weg. Kontakt gelöscht ⇒ Treffer im Verlauf geschwärzt. Zusätzlich Löschvorschlag nach 24 Monaten ohne Aktivität (wie PROPOSED_docweg01).
Variante B: „nie löschen“ bleibt, nur schwärzen. Einfacher, verstößt aber gegen die Speicherbegrenzung (Art. 5 (1) e).
OK-Frage: Variante A?
E2 · TGV als Auftragsverarbeiter mit AVV
Lage: Für eigene Firmen (C3, C4, privat) ist der Betreiber praktisch derselbe. Mit anna (souverän) und jedem künftigen Kunden ist TGV Auftragsverarbeiter (Art. 28). Ein AVV-Muster fehlt, Register #909 führt es als Punkt.
Variante A (Empfehlung): EIN AVV-Muster für alle fremden Mandanten, mit festen Zusagen: Hilfe bei Betroffenen-Anfragen binnen 5 Werktagen, der Mandant entscheidet, Löschung oder Rückgabe 30 Tage nach Vertragsende. Pflicht vor dem ersten externen Kunden.
Variante B: AVV je Kunde einzeln verhandeln. Das ist flexibler, aber jede Zusage muss im Löschweg einzeln abgebildet werden.
OK-Frage: Variante A, und die Zahlen 5 Werktage / 30 Tage?
E3 · Wie lange bleibt der Einwilligungs-Nachweis nach der Löschung?
Lage: Nach der Löschung bleibt nur der Minimal-Nachweis: Zweck, Datum der Erteilung, Datum des Widerrufs, Art des Belegs. Er dient der Abwehr eines Vorwurfs „ohne Einwilligung angeschrieben“ (Art. 17 (3) e).
Variante A (Empfehlung): 3 Jahre ab Ende des Jahres des Widerrufs (regelmäßige Verjährung, § 195/§ 199 BGB; die CNIL nennt für die Sperrliste mindestens 3 J.). Danach wird der Nachweis gelöscht, der Sperrlisten-Eintrag bleibt.
Variante B: Nachweis und Sperre unbegrenzt. Die Beweislage ist sicherer, aber es wird mehr gespeichert als nötig.
OK-Frage: Variante A?

§7bEinwilligung beim Zugang — ein Bildschirm für alle Neuen (Register #2153, JC 19.09.2026)

JCs Ziel (sinngemäß): Wer neu in TGV kommt oder Dokumente erhält, hakt beim ersten Zugang alles auf einmal ab: Datenschutz, Nutzungsbedingungen, Widerruf und die Einwilligung, vom Mandanten Werbung zu erhalten. Das soll konform, transparent, extrem einfach und zeitsparend sein, damit TGV und die Mandanten ihr Geschäft entwickeln können. JCs Wunsch dabei: „niemanden reinlassen, der nicht eingewilligt hat, Werbung zu erhalten“.

① Die ehrliche Antwort: Den Zugang an die Werbe-Einwilligung zu binden, ist nicht erlaubt

Kopplungsverbot (Art. 7 (4) DSGVO, ErwG 43). Werbung ist für den Zugang zu einem Projekt oder Dokument nicht erforderlich. Eine Einwilligung, ohne die es keinen Zugang gibt, gilt als nicht freiwillig und ist damit unwirksam. Sie wäre also nicht nur riskant, sondern als Beleg wertlos. Das sagen der EDPB (Leitlinien 05/2020 Rn. 26–41, Beispiel 6: „Bank verweigert Leistung ohne Marketing-Einwilligung“ = unwirksam; Rn. 39–41 „Cookie-Wall“), die DSK (OH Werbung 2/2022 Ziff. 3.4) und die CNIL. Das OLG Frankfurt (6 U 6/19) erlaubte eine Kopplung nur beim freiwilligen Gewinnspiel; auf Arbeitsdokumente lässt sich das nicht übertragen. Dazu kommen: Ein vorangekreuztes Kästchen ist nie eine Einwilligung (EuGH C-673/17 Planet49). Es braucht ein Kästchen je Zweck und je Mandant, mit Namen (EDPB Rn. 42–44, 65). Die Werbe-Einwilligung darf nicht mit demselben Klick wie die AGB erteilt werden (Rn. 81).

Was stattdessen geht und JCs Ziel am nächsten kommt: EIN Bildschirm und EIN Klick auf „Weiter“. Pflicht ist nur, was für den Zugang wirklich nötig ist. Die Werbung wird so angeboten, dass möglichst viele freiwillig Ja sagen. Wo das Recht ein Opt-out erlaubt, wird es genutzt.

② Die Maske: was Pflicht ist, was freiwillig, was nur ein Link

ElementFormWarum soProtokoll
Nutzungsbedingungen TGVPflicht-Kästchen, leer, mit LinkVertrag über die Nutzung (§ 305 (2) BGB: Hinweis, Kenntnisnahme, Einverständnis; bei Unternehmern reicht nach § 310 (1) ein erkennbarer Verweis — das Kästchen erfüllt beides)Zustimmungs-Protokoll des Betreibers: Version + Hash des Texts, Zeitpunkt
Datenschutzerklärung (TGV + Mandant)nur Link, kein KästchenDas ist eine Information nach Art. 13, keine Einwilligung. Ein Pflicht-Kästchen würde eine Wahl vortäuschen (DSK).„angezeigt“ mit Version
Werbung je Mandantfreiwilliges Kästchen, leer, eines je Mandant mit seinem Rechtsnamen aus entity_signatures.legal_name (nie ein Kürzel wie C3/C4) und dem ThemaEinwilligung nach § 7 (2) Nr. 2 UWG / L34-5 CPCE. Der Zugang funktioniert auch ohne.contact_consents purpose werbung, evidence formular:zugang@<version>
WiderrufSatz unter dem Kästchen: „jederzeit mit einem Klick, in jeder Mail“Art. 7 (3): so leicht wie die Erteilung. Kein Verbraucher-Widerrufsrecht nach § 355 BGB, weil die Eingeladenen nichts kaufen und beruflich handeln.Abmeldung = neue Zeile widerrufen + Sperreintrag (§7a ⑥)
FR · Fachleute (B2B)Hinweis mit Kästchen „Nein, danke“ (Opt-out)L34-5 CPCE: berufsbezogene Werbung an Firmenadressen ist ohne Opt-in erlaubt, wenn bei der Erhebung informiert wird und jede Mail einen Widerspruchsweg hatevidence b2b_info:zugang@<version> (Konvention KONTAKTE#01)

Ist eine Bestätigungsmail (Double-Opt-in) nötig? Das Double-Opt-in beweist, dass der Inhaber der Adresse selbst eingewilligt hat (BGH I ZR 164/09, DSK Ziff. 3.3). Bei TGV kommt jeder über einen Magic-Link an genau diese Adresse herein (core_shell.html doMagicLink, shouldCreateUser:false). Das Kästchen wird also in einer Sitzung angehakt, die den Besitz der Adresse schon bewiesen hat. ⇒ Empfehlung: keine zweite Mail — mit einer Grenze (MAIL#02): Das gilt nur, wenn die Einwilligung (a) für genau die Login-Adresse erteilt wird und (b) diese Adresse bestätigt ist, also email_confirmed_at gesetzt ist oder die Sitzung per Magic-Link/Code zustande kam. AUTH #2110 baut auch eine Passwort-Anmeldung, und wer so angemeldet ist, hat den Besitz des Postfachs in dieser Sitzung nicht gezeigt. Für eine andere Adresse und für unbestätigte Adressen gilt das Double-Opt-in. Der Login ist sonst die Bestätigung, protokolliert mit Sitzung, Anmeldeart und Zeitpunkt. ⛔ Das ist eine Wertung und kein Urteil; ein Anwalt prüft beide Fälle vor dem Bau.

③ Wo die Maske erscheint — EIN Tor für alle Wege

Gemessen am 19.09. (Zeilen gemessen an origin/master 19.09. abends):

⇒ Jeder Weg führt über den Login. Das Tor sitzt deshalb an EINER Stelle: in onAuth, vor H.onSession. Fehlt die Zustimmung zur aktuellen Fassung der Nutzungsbedingungen, erscheint die Maske. Sonst gibt es keinen Zugang, auch nicht zu einem geteilten Dokument. Ändert sich die Fassung, erscheint die Maske noch einmal, nur mit den Änderungen. Die Maske zeigt Werbe-Kästchen nur für die Mandanten, in denen die Person eine Rolle hat (my_mandant_ids). Die Namen anderer Mandanten sieht sie nie.

④ Das Vertragswerk — wer mit wem, welches Papier

PapierzwischenWirkt in der Maske alsStand
Nutzungsbedingungen TGVBetreiber ↔ jede Person mit Zugang (auch Externe)Pflicht-Kästchenfehlt · #909
Datenschutzerklärung TGVBetreiber (für Konto, Login, Protokolle)Linkfehlt · #909
Datenschutzhinweis je MandantMandant als Verantwortlicher (für seine Kontakte, Projekte, Werbung)Link je Mandant neben seinem Werbe-Kästchenfehlt · je Mandant
AVV (Art. 28)Mandant ↔ Betreibernicht sichtbar für die PersonWorkshop (§7a ⑨ E2)
Werbe-EinwilligungPerson → Mandantfreiwilliges KästchenKonvention steht (contact_consents, #2141)
ImpressumBetreiberLink im Fußfehlt

Vorbild im Haus für Kästchen mit Zeitstempel-Protokoll und Rechtstext-Gerüst: 00_LEITDOKUMENT/KONZEPT_WEBSITE_FACTORY.md:14,19 (drei Pflicht-Kästchen, Skill website-legal mit Jurist-Gate). ⛔ Die Texte selbst schreibt ein Anwalt (DE + FR); TGV baut nur die Form.

⑤ Bildschirm-Vorschau (Empfehlung A · rechts Variante B für einen FR-Mandanten)

PC · Variante A · erster Login

Willkommen bei TGV

Einmal bestätigen, dann geht es los.

Wie wir und die legal_name Ihre Daten verarbeiten: Datenschutz TGV · Datenschutz legal_name

Weiter

* nötig für den Zugang. Alles andere ist freiwillig; Sie kommen auch ohne Ja hinein.

Handy · Variante B · FR-Mandant

Bienvenue

Données personnelles · désinscription en un clic dans chaque e-mail

Continuer

legal_name ist ein Platzhalter: Das Tor gilt je Mandant, der Name kommt aus entity_signatures.legal_name. Beispiel C3: „CONVIS Consult & Marketing GmbH“, C4: „CONVIS Consult & Marketing SARL“. Ein Kürzel steht nie in einer Einwilligung, denn dort muss der Verantwortliche mit seinem Rechtsnamen genannt sein (EDPB Rn. 65). Die Form ist dieselbe wie auf der Login-Karte (#loginView), in derselben Sprache wie der Login-Schalter DE/FR/EN. Auf dem Handy liegen die Kästchen untereinander, die Trefferfläche ist die ganze Zeile. Den Knopf „Weiter“ gibt es EINMAL. Er ist aktiv, sobald das Pflicht-Kästchen gesetzt ist; die freiwilligen Kästchen ändern daran nichts.

⑥ Bauplan (nach JC-Wort und Rechtstexten)

PaketInhaltVoraussetzung
Z0 · Konzeptdieser Abschnitt + Registerzeile #2153geliefert
Z1 · RechtstexteNutzungsbedingungen, Datenschutz TGV + Muster je Mandant, Impressum; DE + FR, AnwaltJC · #909
Z2 · Protokoll (DDL)Zustimmungs-Protokoll des Betreibers (Person, Dokument, Version, Hash, Zeitpunkt, Oberfläche) — getrennt von contact_consents, denn die Nutzungsbedingungen sind ein Vertrag mit dem Betreiber, keine Einwilligung gegenüber einem MandantenPROPOSED, JC fährt
Z3 · Tor im LoginMaske in onAuth + Endpunkt; Werbe-Kästchen schreiben über contact-propose (Person noch kein Kontakt ⇒ Vorschlag mit Consent-Zeile)Z1 + Z2 + Schreibweg für Einwilligungen in contact-propose: heute legt er nur Kontakt und Kanäle an, keine Consent-Zeile. Nötig ist ein optionaler Parameter consents, append-only, evidence Pflicht, nie widerrufen. Das baut KONTAKTE#01 auf Signal.
Z4 · Abmelden mit einem KlickAbmeldelink + List-Unsubscribe-Post (RFC 8058) in jeder Werbe-MailMAIL#02 §J5 V1
Z5 · Einladungs-MailTGV-Text in der Supabase-Vorlage „Invite user“: wer lädt ein, wofür, Hinweis auf die Maske. Keine zweite Mail über die Mail-Naht, sonst ginge sie doppelt raus. Absender vorerst nur @convis.fr, später je Mandant (JE-177).AUTH #2110 (mehrsprachige Auth-Vorlagen)

⑦ Entscheidungsvorlage an JC

E4 · Werbung beim Zugang: wie nah an „alle willigen ein“?
Lage: Den Zugang an die Werbe-Einwilligung zu koppeln, ist nicht erlaubt; eine so eingeholte Einwilligung wäre unwirksam (①).
Variante A (Empfehlung für den Start): In allen Mandanten gibt es ein freiwilliges Ja-Kästchen je Mandant. Die Maske ist so einfach, dass Ja ein Klick ist. Keine Bestätigungsmail, weil der Login die Adresse schon bestätigt hat (②).
Variante B: wie A, zusätzlich für C4 (FR) gegenüber Fachleuten ein Opt-out-Hinweis „Non merci“. So erreicht C4 alle, die nicht widersprechen. Einzuschalten erst nach dem Wort eines FR-Anwalts.
OK-Frage: A jetzt, B für C4 nach dem Anwalt?
E5 · Nutzungsbedingungen als einziges Pflicht-Kästchen — für alle, auch Externe?
Lage: Heute kommt jeder ohne Rechtstext hinein.
Empfehlung: ja, für alle das eine Pflicht-Kästchen „Nutzungsbedingungen TGV“, Datenschutz nur als Link. Die Texte schreibt der Anwalt (#909). Bis sie da sind, wird das Tor gebaut, bleibt aber aus.
OK-Frage: einverstanden? Und gehört das mit E1–E3 in den Workshop nach dem Funktions-Gate?

Quellen (abgerufen am 19.09.2026): EDPB 05/2020 · DSK OH Werbung · CNIL Prospection · § 7 UWG · § 305 BGB · § 310 BGB · OLG Frankfurt 6 U 6/19 · Google Absender-Regeln (One-Click). Weitere Rechtslage zum Anschreiben von Kontakten: Datenfluss §7b. ⛔ Keine Rechtsberatung.

§7cDatenhoheit — Export und Löschung aus demselben Inventar · Data Governance Contract · Paketplan (konsolidierter JC-Entscheid 04.10.2026)

Produktversprechen (JE-196): Der Mandant muss TGV verlassen können und seine Daten vollständig, verständlich und weiterverwendbar zurückerhalten. Geschäftsdaten und im Auftrag erzeugte Ergebnisse gehören zum Datenbestand des Mandanten; Betroffenenrechte bleiben unberührt; Kivisai erzeugt keine künstliche Datenbindung. Quelle: JC_ENTSCHEID_TGV_DATENSCHUTZ_DATENHOHEIT_2026-10-04.md §19–§22, §27–§30.

BausteinSOLL (JC 04.10.2026)IST (gemessen 04.10.2026)
Exportmindestens Originaldateien · Metadaten · Entitäten · Projekte · Verträge · strukturierte Businessdaten · gespeicherte KAI-Ergebnisse · relevante Chat-/Entscheidungsartefakte · Beziehungen. Chunks/Embeddings sind Ableitungen, kein Pflicht-Primärexport.kein allgemeiner Export-Endpunkt; Datei-Download nur über file-url; accountant-send ist der einzige Versandweg (Verwalter).
Gemeinsames DateninventarWas TGV exportieren kann, muss TGV auch finden und kontrolliert löschen können. Inventar: DB-Datensätze · Dateien/Buckets · RAG-Chunks · Embeddings · KAI-Artefakte · Chats · Second Brain/Persona · Mail · Audit · Backups.kein Inventar als Liste; §7a ④ (Datenart × Entscheid, Personen) und person-loeschen (Vorschau) sind der Anfang für die Personen-Achse.
HartlöschungInventar einfrieren → DB-Beziehungen prüfen → RAG/Embeddings entfernen → Storage-Datei löschen → DB-Zeilen entfernen/anonymisieren → Derivate entfernen → Gegenprobe → Erasure-Audit.kein Lösch-Endpunkt für Belege; privacy_erasure_log 0 Zeilen; Erasure-FK-Design offen (§10). Backup existiert nicht (§6a Härtungs-Reihe).
Retention-Matrixje Datenart: Zweck → Rechtsgrund → Standardfrist → Startpunkt → Löschstrategie → Exportstrategie. TGV-Kanon → zulässiger Mandanten-Override → konkrete Frist. Keine verstreuten Retention-Regeln im Code.08_OPS/aufbewahrung_kanon.yaml (ein Kanon), tunable_params, loeschsperren, mandanten.telemetrie_retention_tage — Bausteine ohne gemeinsame Matrix.
Data Governance Contractjede neue persistente Datenart beantwortet vor Produktivgang: ① Scope ② Zugriff ③ Vertraulichkeit ④ KAI ⑤ Retention ⑥ Export ⑦ Erasure (JE-197). Langfristig maschinenlesbare Data Registry als Basis für Guard-Tests, Export, Löschung, TOM, VVT.nicht vorhanden; die bestehenden Schema-Wächter des Hauses stellen keine dieser sieben Fragen.
NUXING und Paketplan (JE-199) — keine Vollbremsung, kein Neubau um des Neubaus willen. „Wir haben sehr viel bereits gebaut. Nicht neu erfinden. Verdrahten, vereinheitlichen, absichern und TGV rund machen.“
Paket 1 · Kanon & Nachweis (jetzt, wenig Code): Kompendium korrigieren · IST/SOLL trennen · Owner-Bypass markieren · Policies messen · KAI-Sicht messen · fehlende Policy-Coverage dokumentieren. Kanon-Teil erledigt 04.10.2026 (dieser Abschnitt, §2a, Leitdokumente, JE-186–199); Messteil → Register #3551.
Paket 2 · Kritische Launch-Sicherheit (vor breitem produktivem Einsatz): streng-Zielmodell · DEV Override abschaltbar · Supportzugriff · Break Glass + Audit · KAI-Rechteparität · Dateninventar für Export/Löschung.
Paket 3 · Produktisierung: kostenlose Gastkonten · Upgrade Gast → Mandant ohne Loginwechsel · Privat Free · PERSO-KAI · verständliche Privacy-/Scope-UX.
Paket 4 · Governance-Automatisierung: Data Registry · Retention Engine · Export/Offboarding Engine · Erasure Engine · automatische Policy-/Guard-Prüfung · DE/FR-Skalierung.
⛔ Keine großen Umbauten, keine DDL-Läufe, bevor Diff und Umsetzungsplan vorliegen. Zehn offene Punkte (JC §33) sind Restarbeit im Zielmodell: geschützte Kreise rechtlich · Beschäftigtendatenschutz · Externe (AVV/Verantwortlicher/gemeinsam) · Werbeeinwilligung · DE/FR-Fristen · AVV/TOM/Subprozessoren · Projekt Typ B · Export-/Offboarding-Zusagen · Audit-Fristen · Migration vom Owner-Bypass. Vertragspartner zunächst die deutsche Gesellschaft (Kivisai), Brücken für FR offen (JE-198).

§8Haftung & Betriebsmodi — Verwaltet vs. Souverän

Der Haftungs-Hebel der Vermarktung (AVV/Auftragsverarbeitung): zwei Betriebsmodi, die Awareness-Session ist das menschliche Gate vor Runterstufen/Löschen. Struktur, Fahrplan (M1–M6) und Onboarding → 🏢 Multi-Mandant.

ModusWer steuert Status/Regeln/LöschungHaftung
Verwaltet (Default-Start)Convis/Kivisai kuratiert — der Mandant kann wenig falsch machenHaftungsschutz beim Betreiber (AVV)
Souveränder Mandant selbst (nach Security-Awareness-Session als Gate)mehr Kontrolle = mehr Eigenverantwortung (vertraglich abgegrenzt)

AVV + Lösch-Garantie (§7) sind Verkaufsargument UND Haftungs-Pflicht — beide hängen an diesem Modell. Grundpfeiler: Default-Deny · fail-closed · vollständiges Audit · „im Zweifel strenger". Sub-Processor-Transparenz (wer verarbeitet was, wo) lebt in der Security-Baseline (TGV_CORE_V1_SECURITY_PRIVACY_BASELINE.md).

§9Wie es FIRST entsteht & dauerhaft bleibt — die Sicherheits-Lernschleife

„First" heißt: die Grenze entsteht mit dem Schema, nicht nachträglich. Analog zur Seitenbau-Lernschleife hat Sicherheit ihre eigene Kette — jede Stufe bindet strukturell (Anti-Amnesie), nichts hängt am Gedächtnis:

StufePrinzipLive-Beispiel (bewiesen, nicht behauptet)
1 · SchemaDefault-Deny entsteht MIT der Tabelle — neue sensible Tabelle = RLS on ab Mig 1 (Standard-Prädikat als Vorlage im SSOT)STEUER#02 bekam das Trias-Prädikat „beim ersten Apply korrekt" statt Nachrüstung
2 · Guard am WirkortWeil service_role RLS bypasst: jeder Read scoped — das Gate sitzt DORT, wo gelesen wird (RPC/Endpoint), nicht nur in der DBsearch_knowledge_scoped: conf-Decke + Mandant-Menge IN der Funktion (Mig 221)
3 · Audit jeder AusnahmeOwner-Bypass und Break-Glass sind erlaubt — aber NIE stilltgv_log_break_glass für JCs anna-Setup-Zugriff (Mig 220)
4 · Awareness-GateDer Mensch bleibt Gate vor Runterstufen/Löschen (Human First §2)Security-Awareness-Session als Souverän-Modus-Voraussetzung
5 · Guard für immerJeder Vorfall wird zum verankerten Ritual/Guard — nicht zur toten Doku-Regel. Guard-First (17.07.): fertig ist erst, was ein Guard sichert — und ein Guard, den niemand absichtlich gebrochen hat, ist kein Guard (Negativ-Test-Pflicht; „Guard grün" heißt nur „Guard lief")Grant-Gotcha beim 221-Apply → Grant-Verify-Ritual im Mig-Kopf; Gate-Beweis als Skript (r5_gate_proof.py) wiederholbar = gelebter Negativ/Positiv-Test · Guard-First

§10⚠️ Ehrliche Lücken-Landkarte (Stadium-ehrlich)

„Dauerhaft gesichert" ist nur ehrlich mit den offenen Punkten sichtbar — jede Lücke hat eine Owner-Lane. (Früher stand hier auch das rag_chunks-Retrieval-Gate — seit 13.07. gebaut + Gate-bewiesen, §6.)

LückeWarum sie zähltOwnerStand
Endpoint-Scope-Guard 2/57Nur 2 von 57 Skill-Endpoints validieren den Scope server-seitig; service_role bypasst RLS ⇒ Scope ist heute faktisch Client-Erlaubnis. DIE strukturelle Lücke vor Mehr-NutzerMANDANT#01🔴 größte offene Flanke
documents-RLS-HärtungMig 208 v4 geparkt; kein akutes Leck im Solo-Betrieb, aber Pflicht vor Mehr-NutzerMANDANT#01 / PLATgeparkt
Test/Prod-IsolationBR#04-Incident: E2E-Test schrieb 4 Testbelege in Prod-documents (1 bank-abgeglichen) — Wurzel: kein is_test-Flag + Konsumenten-FilterORCH / PlattformFix definiert, offen
account-status.mandant hardcodedDer Endpoint liefert heute fest "jcbinetti" (Code-verifiziert im SSOT) — Multi-Mandant braucht die echte Mitgliedschafts-AuflösungMANDANT#01offen (Identitäts-Naht)
Menü nicht rollen-/projekt-scopedcore_shell rendert ~31 der ~33 Sidebar-Einträge für JEDEN eingeloggten User; nur super_admin ist gegatet (§4b IST). Ein Projekt-Externer sähe heute das ganze Menü. Sicht-Klassen T0–T4 + min_klasse-Deklaration = SOLL, noch nicht gebautSICHTBARKEIT#01 / SHELLKonzept steht (§4b), Bau + entity_member/extern als DB-Rolle offen
Erasure-FK-DesignDSGVO-Art.-17-Endlöschung scheitert heute an FK-Abhängigkeiten (FK-409) — Vorbedingung der Lösch-Garantie (§7). Für Personen (§7a) gemessen 19.09.: contact_consents CASCADE löscht den Nachweis mit (251:209), learning_events.user_id blockiert das Löschen eines Users (050:19), chat_sessions.user_id hat kein FK (203:14)Plattform · DSGVO#01offen · Personen-Teil als PROPOSED bei JC (#2145)
gabriel-Stufen-MappingGabriels Eigen-Levels sind noch nicht auf die CORE-Leiter gemappt — fail-closed fängt es ab (unbekannt = streng), aber sauber ist andersRAG#01 / Gabrieloffen (fail-closed gedeckt)
Supabase-Region unbestätigtDie Security-Baseline selbst sagt: „konkrete Region bestätigen" — für die EU-Garantie (§11) Pflicht-Verifikat, nicht ratenJC / Tower1 Blick ins Supabase-Dashboard
Gabriel-Embeddings = OpenAIEU-Bruch im Neben-Pfad: CORE embeddet Mistral (EU), Gabriel noch OpenAIRAG#01nachziehen

§11Der EU-souveräne Stack — von der DB bis Mistral

Die Garantie an Mandanten (Ziel-Satz): „Ihre Daten gehen NICHT an US-Firmen und werden nicht zum Training genutzt." Das ist Wettbewerbsvorteil, kein Detail — und darf erst versprochen werden, wenn jede Zeile hier grün ist. Grafisch: §1-Graph, Modus 🇪🇺 EU-Stack (Datenfluss mit EU/US-Färbung). Ehrlicher Stand je Komponente:

KomponenteAnbieter / LösungStandortStand (ehrlich)
EmbeddingsMistral mistral-embed (1024)EU (FR)✅ CORE live · ⚠ Gabriel noch OpenAI
OCR / Visionheute docling on-box · Ziel: Mistral OCR (self-host Container)on-box / EUdocling ✅ · ⚠ letzter US-Vision-Call für Bilder
Rerankermxbai-rerank-large-v2 (mixedbread, self-host, Apache-2.0)Berlin / self-host✅ EU
Chat / Generierungheute Anthropic Claude · Swap-Ziel mistral-large (E1-Naht provider-agnostisch)US ⚠⚠ DER Kern-Bruch — „Ziel EU, heute US"
DatenbankSupabase / Postgres (alle persistenten TGV-Daten)Projekt-Region bei Anlage gewählt⚠ Region VERIFIZIEREN (Baseline-Prüfpunkt, §10)
Datei-StorageMigration Drive → Hetzner (nbg1), mandanten-getrennt, provider-flexibel (Resolver-Abstraktion Mig 147)Nürnberg (EU)Kurs ✅ · Migration ROT (STORAGE#01)
Provider-GovernanceLLM-Provider per Mandant + Skill konfigurierbar + Cost-Telemetrie—⬜ Ziel — heute hardcoded
Ehrlicher Kern-Bruch (nicht beschönigen): Der US-Chat-LLM ist heute DER offene Punkt der EU-Souveränität — identisch offen markiert in Chatbot First (Facette 1). Due-Diligence VOR der Mandanten-Garantie: Mistral-DPA, EU-Residenz und No-Training zitierfähig verifizieren. Bis dahin lautet der ehrliche Satz: „EU-Kurs gesetzt, Chat-LLM noch US."
SSOT-Verweise (dort wird entschieden): 00_LEITDOKUMENT/KONZEPT_VERTRAULICHKEIT_GEHEIMHALTUNG.md (v1.1 GELOCKT — Governance, Matrix, Lösch-Stufen, 10 gelockte Entscheidungen) · 01_ITERATIONS/PLAT_09_CORE_FRONTEND_APPSHELL/IDENTITY_RLS_SSOT_DECISION.md (Rollen-Trias, Default-Deny-Standard, Standard-Prädikat) + MODULE_CONTRACT.md (ctx-freeze) · 00_LEITDOKUMENT/KONZEPT_MANDANT_FIRST_CLASS.md (Datenmodell, M1–M6) · AUTH_USER_MANAGEMENT_KONZEPT.md (Login/Rollen) · TGV_CORE_V1_SECURITY_PRIVACY_BASELINE.md (Sub-Processors/Region) · 05_SCHEMA (Mig 037·142·157·196·209–212·220·221 = die Code-Wahrheit). Diese Seite ist die Mensch-Synthese der Familie; bei Widerspruch gilt das SSOT. Verwandt: Multi-Mandant (Betrieb) · Dokumente (Vertraulichkeit in der Ablage) · Regelwerk R-50/R-51/R-52 · Badge-Dossier (wie die Stufen am Objekt AUSSEHEN). §1-Graph = SYSTEM#01-Baustein security_layers_graph.js (geliefert 14.07., Retrieval-Knoten auf Mig-221-Stand nachgezogen).