Vier Ebenen (Schema, SQL der 80 Operationen, Payloads der Aufrufer, Ablagen außerhalb von KNOW), jeder Befund am Code nachgeprüft: keine Fremdschlüssel, zwei Kontakt-Schlüsselschemata, zwei Projekt-Kennungen, zu enge/fehlende Eindeutigkeit, Upserts frieren Fachdaten ein, veraltende abgeleitete Werte, nie geschriebene Felder, Kategorie-Vokabulare (Safety-Floor über CAT unerreichbar), uneinheitliche Normalisierung, Schema-Drift, gemeinsamer DB-Zugang, staticData, unverschlüsselte Browser-Sessions, LLM-Aufrufe am PSE-LiteLLM vorbei. Schema-Referenz und Ontologie um fehlende Spalten ergänzt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
# KNOW: Befunde aus der Analyse vom 13.10.2026
|
||||
# KNOW: Befunde zur Datenhaltung (Analyse vom 13.10.2026)
|
||||
|
||||
Grundlage sind die Workflow-Definitionen auf n8n.mindboost.app, nur lesend über die n8n-API abgerufen. Ausgewertet wurde der Code von KNOW, KGW und allen aufrufenden Workflows. Inhalte der Datenbank wurden nicht gelesen. Für `CANCEL - Unsubscribe Link` und `KAN-Learn - Kanbau Pattern Learning` liefert die API keine gespeicherten Ausführungen, ein Nachweis aus der Laufzeit fehlt deshalb.
|
||||
Grundlage sind die Workflow-Definitionen auf n8n.mindboost.app, nur lesend über die n8n-API abgerufen. Ausgewertet wurde der Code von KNOW, KGW und allen aufrufenden Workflows. B11–B30 stammen aus der Vollanalyse in vier Ebenen:
|
||||
1. Schema: Schlüssel, Indizes, Typen, nachträgliche Spalten.
|
||||
2. SQL der 80 Operationen: Was wird geschrieben, was bei Konflikten nicht aktualisiert, was nie befüllt.
|
||||
3. Abgleich mit den Payloads der Aufrufer.
|
||||
4. Datenablagen außerhalb von KNOW: staticData, direkte Verbindungen, LLM-Aufrufe.
|
||||
|
||||
Jeder Befund wurde am Code nachgeprüft, Artefakte der automatischen Auswertung sind aussortiert. Inhalte der Datenbank wurden nicht gelesen. Für `CANCEL - Unsubscribe Link` und `KAN-Learn - Kanbau Pattern Learning` liefert die API keine gespeicherten Ausführungen, ein Nachweis aus der Laufzeit fehlt deshalb.
|
||||
|
||||
- Übersicht der Tabellen: [KNOW-schema.md](KNOW-schema.md)
|
||||
- Interaktive Ansichten (privat):
|
||||
@@ -21,6 +27,26 @@ Status aller Befunde: **offen**. In n8n wurde nichts geändert.
|
||||
| B8 | KGW erlaubt externen Aufrufern eine Lösch-Operation | niedrig |
|
||||
| B9 | Keine Löschfristen für Klartext-Felder | mittel (Datenschutz) |
|
||||
| B10 | Absender-Report zeigt eingefrorene Statistik | mittel |
|
||||
| B11 | Kein einziger Fremdschlüssel; alle Verweise sind freier Text | hoch |
|
||||
| B12 | Zwei Schlüsselschemata für Kontakte → Dubletten, Join findet nichts | hoch |
|
||||
| B13 | Zwei Projekt-Kennungen, `projects` leer, Projekte kommen live aus KanBau | hoch |
|
||||
| B14 | Zu enge Eindeutigkeit: Ereignisse und Prüfungen werden überschrieben bzw. verworfen | hoch |
|
||||
| B15 | Fehlende Eindeutigkeit: jede Extraktion erzeugt eine neue Zeile | mittel |
|
||||
| B16 | Drei Tabellen ohne Primärschlüssel, doppelte Indizes | niedrig |
|
||||
| B17 | Upserts frieren Fachdaten ein (Kontakte, Ankaufsfälle, Falldokumente) | hoch |
|
||||
| B18 | Gespeicherte abgeleitete Werte veralten (`deadline_is_overdue` u. a.) | mittel |
|
||||
| B19 | Felder, die nie geschrieben werden (`confidence`, `confirmed_by`, `verified_at`) | mittel |
|
||||
| B20 | Kategorien in mehreren Vokabularen; Safety-Floor-Kategorien über CAT unerreichbar | hoch |
|
||||
| B21 | Postfach und Absender uneinheitlich normalisiert | mittel |
|
||||
| B22 | Zwei Listen für Dokumenttypen | niedrig |
|
||||
| B23 | Sechs Statusfelder rund um den Ankaufsfall | mittel |
|
||||
| B24 | Schema-Drift: 45 nachgezogene Spalten, Laufzeit-DDL, keine Versionierung | mittel |
|
||||
| B25 | Uneinheitliche Typen und Benennung (Geld als Text, Cent vs. Euro, deutsch/englisch) | niedrig |
|
||||
| B26 | Fehlende Indizes auf Such- und Join-Spalten | niedrig |
|
||||
| B27 | Ein Datenbankzugang für alles, geteilt mit dem Chat-Gedächtnis | mittel |
|
||||
| B28 | Zustand in staticData von 9 Workflows, außerhalb von KNOW | mittel |
|
||||
| B29 | Browser-Sessions (Cookies, Header) unverschlüsselt gespeichert | hoch (Sicherheit) |
|
||||
| B30 | LLM-Aufrufe am PSE-LiteLLM vorbei, u. a. Kaufvertragstexte | hoch (Datenschutz) |
|
||||
|
||||
## B1 – CANCEL protokolliert ins Leere
|
||||
- **Beleg:** `CANCEL - Unsubscribe Link` (aktiv) ruft in 4 Knoten (`KNOW: Log Erfolg`, `… Fehler`, `… Duplikat-Erfolg`, `… Dry Run`) `log_workflow_decision` auf. Diese Operation steht nicht in der Liste von KNOW, KNOW wirft `Nicht erlaubte KNOW operation`. Alle 4 Knoten haben „Continue on Fail“.
|
||||
@@ -96,8 +122,8 @@ Die Abfragen zu Ankaufsfällen über KGW (Hermes) liefern also nur Daten, die ei
|
||||
- `agent_context_documents.content`
|
||||
- `mail_events` (Absender, Betreff)
|
||||
|
||||
`purge_*` gibt es nur für Absender-Beobachtungen und Aliase. Bei `browser_sessions.session_data` ist am Schema nicht erkennbar, ob verschlüsselt wird.
|
||||
- **Vorschlag:** Aufbewahrungsfristen festlegen, z. B. `llm_jobs` nach Abschluss nach 30 Tagen leeren. `browser_sessions` im Code von BSB prüfen.
|
||||
`purge_*` gibt es nur für Absender-Beobachtungen und Aliase. `browser_sessions.session_data` ist unverschlüsselt, siehe B29.
|
||||
- **Vorschlag:** Aufbewahrungsfristen festlegen, z. B. `llm_jobs` nach Abschluss nach 30 Tagen leeren. Zu `browser_sessions` siehe B29.
|
||||
|
||||
## B10 – Absender-Report zeigt eingefrorene Statistik
|
||||
- **Beleg:**
|
||||
@@ -107,3 +133,182 @@ Die Abfragen zu Ankaufsfällen über KGW (Hermes) liefern also nur Daten, die ei
|
||||
- **Folge:** Der Report zeigt für jeden Absender die Werte vom ersten Backfill, auch wenn sich die Lage seitdem geändert hat. Die aktuellen Werte stehen in `sender_observations`, dort schreibt derselbe Backfill per `upsert_sender_observation` mit.
|
||||
- **Ursache (ontologisch):** Das Absender-Profil gehört zur Klasse *Absender*, der Kontakt ist das fachliche Gegenüber. Beide sind über die E-Mail-Adresse verbunden. Liegt die Statistik zusätzlich im Kontakt, entsteht eine zweite Quelle, und die veraltet.
|
||||
- **Vorschlag:** Den Report auf `sender_observations` umstellen und den Kontakt nur noch über `email` dazuholen. Die Statistik aus `upsert_contact` herausnehmen.
|
||||
|
||||
---
|
||||
|
||||
# Vollanalyse: B11–B30
|
||||
|
||||
## A. Integrität und Schlüssel
|
||||
|
||||
### B11 – Keine Fremdschlüssel
|
||||
- **Beleg:** `setup_schema` enthält kein einziges `REFERENCES`.
|
||||
- Alle Verweise (`project_key`, `contact_key`, `case_key`, `message_id`, `kuerzel`, `mac` …) sind freier Text ohne Prüfung.
|
||||
- Auch Löschungen (`purge_*`, `reject_project_alias`) räumen abhängige Zeilen nicht auf.
|
||||
- **Folge:** Verwaiste und ungültige Verweise sind jederzeit möglich, und es fällt nicht auf. Besonders betroffen ist `project_key`: Es wird in 7 Tabellen benutzt, aber `projects` wird nie befüllt (B13). Kein einziger Projektverweis lässt sich gegen eine Projekttabelle prüfen.
|
||||
- **Vorschlag:**
|
||||
- Für die Kernbezüge Fremdschlüssel einführen, zuerst `NOT VALID`, dann nach einer Bereinigung validieren: Falldokument → Ankaufsfall, Alias → Kontakt, Beteiligung → Kontakt und Projekt.
|
||||
- Für `project_key` erst B13 lösen.
|
||||
|
||||
### B12 – Zwei Schlüsselschemata für Kontakte
|
||||
- **Beleg:**
|
||||
- `upsert_contact` bildet den Schlüssel standardmäßig als `normalisierter Name|E-Mail`. Kein Aufrufer übergibt einen eigenen Schlüssel.
|
||||
- `update_sender_relevance` legt Kontakte mit dem Schlüssel `E-Mail` an, mit der E-Mail-Adresse als Anzeigename.
|
||||
- `find_workflow_hints` verknüpft `workflow_hints.pattern_key` (Absenderadresse) mit `contacts.contact_key`.
|
||||
- **Folge:**
|
||||
- Ein Absender kann zweimal als Kontakt existieren.
|
||||
- Der Relevanz-Score landet auf dem Schattenkontakt mit dem E-Mail-Schlüssel.
|
||||
- Die vom Backfill angelegten Kontakte („Name|E-Mail“) findet der Join in `find_workflow_hints` nie.
|
||||
- Ändert sich der Anzeigename, entsteht ein neuer Kontakt.
|
||||
- **Vorschlag:** einen Schlüssel festlegen, z. B. die kleingeschriebene E-Mail für Personen und Absender, Namen nur noch als Attribut bzw. Alias. Bestehende Dubletten über `email` zusammenführen.
|
||||
|
||||
### B13 – Zwei Projekt-Kennungen, `projects` leer
|
||||
- **Beleg:**
|
||||
- Verweise nutzen `project_key`.
|
||||
- Der Ankaufsfall speichert dagegen `selected_project_id`, eine `project_id` aus der KAF-Bestätigung.
|
||||
- `projects` und `project_aliases` führen zusätzlich `kanbau_project_id`.
|
||||
- Keine KNOW-Operation schreibt `projects` (B5a).
|
||||
- `PRO - Project Assignment` fragt Projekte live bei `mygodel.kanbau.com` ab.
|
||||
- **Folge:** Es gibt keine Stelle, an der `project_key` und die KanBau-ID verlässlich zusammengehören. Lesende Abfragen auf `projects` (NEX-Teams-Agent, `find_project_candidates`) finden vermutlich nur Treffer über Aliase.
|
||||
- **Vorschlag:** einen Abgleich KanBau → `projects` anlegen (z. B. nachts, über das vorhandene KAN-Gateway) mit `kanbau_project_id` als festem Schlüssel. `project_key` daraus ableiten oder ersetzen.
|
||||
|
||||
### B14 – Zu enge Eindeutigkeit
|
||||
- **`project_events`:** `UNIQUE(message_id)` mit `ON CONFLICT (message_id) DO UPDATE SET project_key, category, summary …`.
|
||||
- Meldet eine Mail zwei Ereignisse oder betrifft sie zwei Projekte, überschreibt das zweite das erste.
|
||||
- Vorschlag: Schlüssel `(message_id, project_key, category)`.
|
||||
- **`kaf_review_snapshots`:** `UNIQUE(case_key)` mit Aktualisierung nur bei `review_status='pending'`.
|
||||
- Nach einer Freigabe kann für denselben Fall kein neuer Vertragsstand gespeichert werden. Der Insert läuft ohne Fehler ins Leere.
|
||||
- Vorschlag: eine Version pro Prüfung (`case_key, version`).
|
||||
- **`mail_events`:** `UNIQUE(message_id)` ohne Postfach.
|
||||
- Das ist unkritisch, solange die Graph-IDs pro Postfach verschieden sind. Bei Internet-Message-IDs würde eine Mail an zwei Postfächer zu einer Zeile.
|
||||
- Prüfen, welche ID CAT und MPA übergeben.
|
||||
|
||||
### B15 – Fehlende Eindeutigkeit bei Extraktionen
|
||||
- **Beleg:** `document_extractions` hat keinen eindeutigen Schlüssel, `store_document_extraction` macht ein reines `INSERT`.
|
||||
- **Folge:** Jede erneute Verarbeitung desselben Anhangs erzeugt eine weitere Zeile, und es ist nicht festgelegt, welche gilt.
|
||||
- **Vorschlag:** `UNIQUE(message_id, attachment_id)` mit Upsert.
|
||||
|
||||
### B16 – Tabellen ohne Primärschlüssel
|
||||
- **Beleg:** `workflow_hints`, `workflow_hint_config` und `kanbau_method_examples` haben nur `UNIQUE`, keinen `PRIMARY KEY`. Auf `hint_key` und `method_key` liegt zusätzlich ein zweiter, überflüssiger Index.
|
||||
- **Vorschlag:** den eindeutigen Schlüssel zum Primärschlüssel machen und die doppelten Indizes entfernen.
|
||||
|
||||
## B. Aktualität
|
||||
|
||||
### B17 – Upserts frieren Fachdaten ein
|
||||
Bei einem vorhandenen Datensatz aktualisieren mehrere Upserts nur wenige Spalten. Alles andere behält den Wert vom ersten Insert:
|
||||
- **`upsert_contact`:** aktualisiert nur Name, `last_seen_at` und `updated_at`. **E-Mail, Telefon, Website, Steuer-Nr., USt-IdNr., IBAN-Hash, Adresse, Kontakttyp, Qualitätsstatus und Belege** werden nie korrigiert. B10 ist ein Spezialfall davon.
|
||||
- **`upsert_property_development_case`:** aktualisiert nur Name, die drei Statusfelder, `sharepoint_json` und `raw_evidence_json`. **Rund 50 Fachfelder bleiben eingefroren**, darunter Angebotsfrist, Kaufpreis, Fläche, `next_action`, `next_action_due_at`, Risiko, Unterlagen-Flags und Mitschriften.
|
||||
- **`upsert_property_development_document`:** `is_current_version` und `supersedes_document_key` werden nie aktualisiert. Ein altes Dokument bleibt „aktuell“, die **Versionierung funktioniert nicht**. Ebenso bleiben Zusammenfassung, Absender und Dokumentdatum stehen.
|
||||
- **Vorschlag:** In den Upserts alle fachlichen Felder mit `COALESCE(EXCLUDED.x, tabelle.x)` aktualisieren. Felder, die bewusst nur einmal gesetzt werden, im Code kennzeichnen.
|
||||
|
||||
### B18 – Gespeicherte abgeleitete Werte veralten
|
||||
- **Beleg:**
|
||||
- `deadline_is_overdue` ist eine gespeicherte Spalte. `find_cases_by_deadline` liest sie, sie lässt sich aber aus `offer_deadline` und dem heutigen Datum berechnen.
|
||||
- `document_count`, `missing_documents` und `detected_documents` werden nur von `sync_property_development_folder_snapshot` gepflegt, und das ruft niemand auf (B5b).
|
||||
- **Folge:** „Überfällig“ und „fehlende Unterlagen“ zeigen den Stand vom Einfügen.
|
||||
- **Vorschlag:** `deadline_is_overdue` zur Laufzeit berechnen (View oder Ausdruck in der Abfrage). Die Zähler aus `property_development_documents` ableiten.
|
||||
|
||||
### B19 – Felder, die nie geschrieben werden
|
||||
- **`workflow_hints.confidence`:** Keine Operation schreibt das Feld.
|
||||
- CAT sendet die Konfidenz, aber innerhalb von `suggested_action`.
|
||||
- `find_workflow_hints` sortiert nach der Spalte, die immer 0 ist. Die Reihenfolge der Hinweise ist damit zufällig.
|
||||
- **`workflow_hints.confirmed_by`:** `promote_workflow_hint` setzt Status und Zeit, aber nicht die Person. Wer einen Hinweis über den Bestätigungslink freigegeben hat, wird nicht gespeichert.
|
||||
- **`contacts.verified_at`, `project_aliases.verified_at`:** Keine Operation setzt sie. Das Bestätigungsmodell (`quality_status` + `verified_at`) ist nur halb umgesetzt.
|
||||
- **Vorschlag:** `confidence` aus `suggested_action` in die Spalte übernehmen (auch rückwirkend). `confirmed_by` aus dem Bestätigungs-Webhook mitgeben.
|
||||
|
||||
## C. Vokabular und Normalisierung
|
||||
|
||||
### B20 – Kategorien in mehreren Vokabularen
|
||||
- **Beleg:** Dieselbe Idee „Kategorie einer Mail“ existiert in mindestens sechs Listen:
|
||||
- **CAT-Zuordnung:** 8 Werte, darunter `bauvorhaben` und `projekt`.
|
||||
- **`workflow_hint_config.config_key`:** 9 Werte, darunter `mahnung`, `zahlungsaufforderung` und `default`.
|
||||
- **`outlook_category`:** Anzeigenamen in Outlook.
|
||||
- **`sender_observations.dominant_category`:** vom Absender-Backfill vergeben.
|
||||
- **`project_events.category`:** 5 feste Werte.
|
||||
- **`mail_events.category`:** frei. MPA schreibt hier den Workflow-Namen `"MPA"`.
|
||||
- **Folge:**
|
||||
- CAT erzeugt `bauvorhaben` und `projekt`, die Konfiguration kennt sie nicht, also greift `default`.
|
||||
- Umgekehrt erzeugt CAT nie `mahnung` oder `zahlungsaufforderung`. **Die Regeln mit Safety-Floor („immer manuell prüfen“) greifen bei Hinweisen aus CAT nie.**
|
||||
- Auswertungen nach Kategorie mischen fachliche Kategorien mit dem Workflow-Namen „MPA“.
|
||||
- **Vorschlag:**
|
||||
- Ein Vokabular als Tabelle bzw. SKOS-Konzeptschema in der Ontologie, mit Abbildung der Outlook-Namen.
|
||||
- CAT um Mahnung und Zahlungsaufforderung erweitern.
|
||||
- MPA schreibt seinen Status in `workflow_status`, nicht in `category`.
|
||||
|
||||
### B21 – Postfach und Absender uneinheitlich normalisiert
|
||||
- **Postfach:** CAT setzt in `store_mail_event` fest `info@mygodel.de`, im CAT-Code kommt aber auch `r.rapp@mygodel.de` vor. MPA übergibt den `grant_key`. Der Absender-Backfill schreibt das Postfach kleingeschrieben.
|
||||
- **Absender:** CAT schreibt ihn klein, MPA übergibt ihn unverändert. `sender_observations.email` ist immer klein.
|
||||
- **Folge:** Die weichen Bezüge Mail ↔ Absender ↔ Kontakt (Ontologie) treffen nur teilweise. Steht ein falsches Postfach fest im Code, werden Mails dem falschen Postfach zugeordnet.
|
||||
- **Vorschlag:** E-Mail-Adressen und Postfächer **in KNOW** normalisieren (kleinschreiben, Anzeigename abtrennen), nicht in jedem Aufrufer. In CAT das Postfach aus dem Trigger übernehmen.
|
||||
|
||||
### B22 – Zwei Listen für Dokumenttypen
|
||||
- **Beleg:** `property_development_documents.document_type` hat 19 feste Werte. `document_extractions.document_type` ist frei, mit Standardwert `unknown`.
|
||||
- **Vorschlag:** eine gemeinsame Liste (Ontologie-Klasse *Dokumenttyp*).
|
||||
|
||||
### B23 – Sechs Statusfelder rund um den Ankaufsfall
|
||||
- **Beleg:** `status` (alt), `pipeline_status`, `outcome_status`, `review_status`, `confirmation_status` und `quality_status`. Dazu kommt die zweite Bestätigungslogik aus B6, die `quality_status='confirmed'` setzt, während der Token-Ablauf `confirmation_status` nutzt.
|
||||
- **Folge:** Es ist nicht festgelegt, welches Feld „bestätigt“ bzw. „abgeschlossen“ bedeutet.
|
||||
- **Vorschlag:** `status` (alt) aus `pipeline_status` und `outcome_status` ableiten oder entfernen. Eine Bestätigungslogik festlegen.
|
||||
|
||||
## D. Schema-Pflege
|
||||
|
||||
### B24 – Schema-Drift
|
||||
- **Beleg:**
|
||||
- 45 Spalten werden per `ALTER TABLE … ADD COLUMN IF NOT EXISTS` nachgezogen, davon 41 in `property_development_cases`. Bei `kanzlei_field_patterns` doppelt mit unterschiedlichem Standardwert (`'[]'` bzw. `'[]'::jsonb`).
|
||||
- Dazu kommt Laufzeit-DDL in einer Anfrage (B6).
|
||||
- Es gibt keine Schema-Version und keine Migrationshistorie.
|
||||
- **Folge:** Welche Spalten eine Instanz hat, hängt davon ab, wann `setup_schema` zuletzt lief und ob der KAF-Sonderweg je ausgeführt wurde.
|
||||
- **Vorschlag:** versionierte Migrationen (Tabelle `schema_migrations`), `setup_schema` nur noch als Migrationslauf.
|
||||
|
||||
### B25 – Uneinheitliche Typen und Benennung
|
||||
- **Geld:** als Text (`commission_including_vat`, `godel_offer`), Beträge mal in Cent (`amount_cents BIGINT`), mal in Euro (`*_eur NUMERIC`).
|
||||
- **Konfidenz:** mal `NUMERIC`, mal `DOUBLE PRECISION`.
|
||||
- **Spaltennamen:** deutsch und englisch gemischt (`kuerzel`, `gesellschaft`, `quelle`, `bestaetigt`, `baustelle`, `absender_typ`, `mail_art`).
|
||||
- **Zeitstempel:** `updated_at` fehlt u. a. in `project_aliases`, `contact_aliases`, `document_extractions` und `mail_events`.
|
||||
- **Vorschlag:** bei der nächsten Migration vereinheitlichen. Niedrige Priorität, aber Voraussetzung für generierte Schemas (Ontologie → JSON-Schema).
|
||||
|
||||
### B26 – Fehlende Indizes
|
||||
- **Beleg:** Ohne Index sind u. a.:
|
||||
- `contacts.email` (Abgleich mit Absendern)
|
||||
- `mail_events.sender`, `received_at`, `category`, `assigned_project_key` (`find_mail_events` filtert und sortiert danach)
|
||||
- `document_extractions.message_id` und `project_key`
|
||||
- `sender_observations.email` (`get_sender_profile`)
|
||||
- `contact_project_relations`
|
||||
- **Vorschlag:** Indizes auf diese Spalten. Unkritisch, solange die Tabellen klein sind.
|
||||
|
||||
## E. Ablage und Datenfluss außerhalb von KNOW
|
||||
|
||||
### B27 – Ein Datenbankzugang für alles
|
||||
- **Beleg:** KNOW, die direkten SQL-Knoten in CAT und ASP, der Postgres-Healthcheck und der Credentials-Watchdog nutzen dasselbe Credential **„n8n Postgres memory account“**. Darüber läuft auch das Chat-Gedächtnis.
|
||||
- **Folge:** Jeder Workflow mit diesem Credential kann jede Tabelle lesen, ändern und löschen. Die Freigabeliste in KNOW und KGW lässt sich so umgehen (B4 ist ein Beispiel).
|
||||
- **Vorschlag:** eigene DB-Rolle für KNOW mit Rechten nur auf `knowledge`, getrennt vom Chat-Gedächtnis. Direkte SQL-Knoten auf eine Rolle nur mit Leserechten umstellen oder durch KNOW-Operationen ersetzen.
|
||||
|
||||
### B28 – Zustand in staticData
|
||||
- **Beleg:** 9 Workflows speichern Zustand in n8n-staticData:
|
||||
- CANCEL (`successful_unsubscribes`, wegen B1 die **einzige** Aufzeichnung der Abmeldungen)
|
||||
- BEL (`bel_alerts`, `bel_setup_sent`)
|
||||
- KJW (`nextLink`)
|
||||
- TDO (`manual_enrichment`, `etag`)
|
||||
- MCR (`last_reported_sha`)
|
||||
- MPA (Token-Cache, verschlüsselt, in Ordnung)
|
||||
- ASP-Scheduler, KBT und KBJ (inaktiv)
|
||||
- **Folge:** Dieser Zustand ist in KNOW unsichtbar, hat keine Historie und geht bei einem Neuimport des Workflows verloren.
|
||||
- **Vorschlag:** Fachlich relevante Zustände (CANCEL, BEL) nach KNOW verlagern. Technische Cursor (KJW, MCR) dürfen bleiben.
|
||||
|
||||
### B29 – Browser-Sessions unverschlüsselt
|
||||
- **Beleg:** `BSB - Execute Login` speichert `session_data: { cookies, headers }` über `upsert_browser_session` als JSON im Klartext.
|
||||
- **Folge:** Gültige Sitzungs-Cookies (u. a. für KanBau) liegen lesbar in der Datenbank. Jeder mit dem gemeinsamen Credential (B27) kann sie übernehmen. Zum Vergleich: Die Postfach-Tokens sind mit AES-256-GCM verschlüsselt, auch im Cache.
|
||||
- **Vorschlag:** `session_data` genauso verschlüsseln wie `mailbox_grants`. Die Lebensdauer kurz halten (Standard 60 Min. ist gut).
|
||||
|
||||
### B30 – LLM-Aufrufe am PSE-LiteLLM vorbei
|
||||
- **Beleg (direkte HTTP-Aufrufe, sicher am LiteLLM vorbei):**
|
||||
- `KAF - Kaufvertrag Erkennung und Extraktion` (aktiv) schickt den **Kaufvertragstext** (`pdf_text`) direkt an `openrouter.ai`, ohne PSE-Aufruf.
|
||||
- Ebenso direkt gehen `KAN - Kanbau API Gateway` (Intent-Erkennung), `BSB - Discover Session` (Login-Seiten an `api.anthropic.com`), `CDW` (Prüfaufruf) und `KSUM` (inaktiv).
|
||||
- **Nicht entscheidbar:** Die OpenAI-Knoten in ASP, DOC, MAIL, CAT und OR nutzen das Credential `openAiApi`. Ob es auf den LiteLLM mit PSE zeigt, ist ohne Einsicht in das Credential nicht erkennbar. ASP ruft dabei kein PSE auf.
|
||||
- **Folge:** Widerspricht der Vorgabe im Aufbauplan („Starke Modelle nur über den LiteLLM mit PSE“). Kaufverträge enthalten Namen, Anschriften und Preise.
|
||||
- **Vorschlag:** KAF, KAN und BSB auf den LiteLLM mit PSE umstellen. Das Ziel des Credentials `openAiApi` prüfen.
|
||||
|
||||
## Geprüft, ohne Befund
|
||||
- Postfach-Tokens (`mailbox_grants`) und der Token-Cache in MPA sind mit AES-256-GCM verschlüsselt.
|
||||
- KNOW maskiert alle Werte über `sqlString`/`sqlJson`. Bei den Operationen gibt es keine offene String-Verkettung. Die Ausnahme ist der direkte SQL-Knoten in CAT (B4).
|
||||
- KGW prüft HMAC und Zeitfenster und lässt nur eine feste Liste von Operationen zu.
|
||||
- Die vermeintlich fehlende Spalte `workflow_decisions.decided_by` existiert (per `ALTER` ergänzt).
|
||||
|
||||
@@ -5,7 +5,7 @@ Interaktive Ansichten (privat, Freigabe über das Share-Menü):
|
||||
- Datenfluss: https://claude.ai/artifact/GP8FfU8M6Wk9hPRmJuk96h
|
||||
- Ontologie: https://claude.ai/artifact/R7zxBJsCKkkCWdCcztLFUT (als OWL/Turtle: [know-ontology.ttl](know-ontology.ttl))
|
||||
|
||||
Befunde mit Belegen, Folgen und Vorschlägen: [KNOW-befunde.md](KNOW-befunde.md) (B1–B9)
|
||||
Befunde mit Belegen, Folgen und Vorschlägen: [KNOW-befunde.md](KNOW-befunde.md) (B1–B30)
|
||||
|
||||
## Aufbau
|
||||
|
||||
@@ -273,7 +273,7 @@ Ankaufsfälle (~70 Felder).
|
||||
|
||||
<details><summary>73 Spalten</summary>
|
||||
|
||||
`id` BIGSERIAL, `case_key` TEXT, `name` TEXT, `normalized_name` TEXT, `status` TEXT, `pipeline_status` TEXT, `outcome_status` TEXT, `case_code` TEXT, `case_opened_at` DATE, `folder_name` TEXT, `folder_path` TEXT, `folder_status_source` TEXT, `source_channel` TEXT, `location_city` TEXT, `location_district` TEXT, `street_address` TEXT, `assigned_to` TEXT, `asset_type` TEXT, `process_type` TEXT, `notes` TEXT, `property_size_sqm` NUMERIC, `original_purchase_price_eur` NUMERIC, `average_price_per_sqm_eur` NUMERIC, `commission_including_vat` TEXT, `apartment_count` INTEGER, `development_plan_available` BOOLEAN, `godel_internal` BOOLEAN, `contact_broker` TEXT, `start_date` DATE, `offer_deadline` DATE, `offer_submitted_at` DATE, `last_offer_at` DATE, `offer_count` INTEGER, `review_status` TEXT, `review_result` TEXT, `meeting_transcripts` TEXT, `just_one_week_more` BOOLEAN, `deadline_is_overdue` BOOLEAN, `godel_offer` TEXT, `project_lead` TEXT, `planning` TEXT, `nda_present` BOOLEAN, `loi_present` BOOLEAN, `bplan_document_present` BOOLEAN, `wirtschaftlichkeit_present` BOOLEAN, `purchase_offer_present` BOOLEAN, `building_permit_present` BOOLEAN, `risk_summary` TEXT, `missing_documents` JSONB, `next_action` TEXT, `next_action_due_at` DATE, `last_document_at` DATE, `document_count` INTEGER, `case_readiness` TEXT, `detected_documents` JSONB, `risk_level` TEXT, `readiness_json` JSONB, `source_system` TEXT, `sharepoint_json` JSONB, `raw_evidence_json` JSONB, `quality_status` TEXT, `confidence` NUMERIC, `first_seen_at` TIMESTAMPTZ, `last_seen_at` TIMESTAMPTZ, `created_at` TIMESTAMPTZ, `updated_at` TIMESTAMPTZ, `confirmation_token_hash` TEXT, `confirmation_status` TEXT, `confirmation_expires_at` TIMESTAMPTZ, `selected_project_id` TEXT, `created_saleagr_id` TEXT, `created_saleagr_url` TEXT, `confirmation_request_id` TEXT
|
||||
`id` BIGSERIAL, `case_key` TEXT, `name` TEXT, `normalized_name` TEXT, `status` TEXT, `pipeline_status` TEXT, `outcome_status` TEXT, `case_code` TEXT, `case_opened_at` DATE, `folder_name` TEXT, `folder_path` TEXT, `folder_status_source` TEXT, `source_channel` TEXT, `location_city` TEXT, `location_district` TEXT, `street_address` TEXT, `assigned_to` TEXT, `asset_type` TEXT, `process_type` TEXT, `notes` TEXT, `property_size_sqm` NUMERIC, `original_purchase_price_eur` NUMERIC, `average_price_per_sqm_eur` NUMERIC, `commission_including_vat` TEXT, `apartment_count` INTEGER, `development_plan_available` BOOLEAN, `godel_internal` BOOLEAN, `contact_broker` TEXT, `start_date` DATE, `offer_deadline` DATE, `offer_submitted_at` DATE, `last_offer_at` DATE, `offer_count` INTEGER, `review_status` TEXT, `review_result` TEXT, `meeting_transcripts` TEXT, `just_one_week_more` BOOLEAN, `deadline_is_overdue` BOOLEAN, `godel_offer` TEXT, `project_lead` TEXT, `planning` TEXT, `nda_present` BOOLEAN, `loi_present` BOOLEAN, `bplan_document_present` BOOLEAN, `wirtschaftlichkeit_present` BOOLEAN, `purchase_offer_present` BOOLEAN, `building_permit_present` BOOLEAN, `risk_summary` TEXT, `missing_documents` JSONB, `next_action` TEXT, `next_action_due_at` DATE, `last_document_at` DATE, `document_count` INTEGER, `case_readiness` TEXT, `detected_documents` JSONB, `risk_level` TEXT, `readiness_json` JSONB, `source_system` TEXT, `sharepoint_json` JSONB, `raw_evidence_json` JSONB, `quality_status` TEXT, `confidence` NUMERIC, `first_seen_at` TIMESTAMPTZ, `last_seen_at` TIMESTAMPTZ, `created_at` TIMESTAMPTZ, `updated_at` TIMESTAMPTZ, `confirmation_token_hash` TEXT, `confirmation_status` TEXT, `confirmation_expires_at` TIMESTAMPTZ, `selected_project_id` TEXT, `created_saleagr_id` TEXT, `created_saleagr_url` TEXT, `confirmation_request_id` TEXT, `confirmed_by` TEXT (Laufzeit-DDL, B6), `confirmed_at` TIMESTAMPTZ (Laufzeit-DDL, B6)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -386,7 +386,7 @@ Vorschlag vs. tatsächliche Entscheidung.
|
||||
|
||||
<details><summary>13 Spalten</summary>
|
||||
|
||||
`id` BIGSERIAL, `request_id` TEXT, `workflow` TEXT, `reference_type` TEXT, `reference_id` TEXT, `proposed_decision` JSONB, `final_decision` JSONB, `confidence` NUMERIC, `correction_reason` TEXT, `quality_status` TEXT, `created_at` TIMESTAMPTZ, `verified_at` TIMESTAMPTZ, `decision_type` TEXT
|
||||
`id` BIGSERIAL, `request_id` TEXT, `workflow` TEXT, `reference_type` TEXT, `reference_id` TEXT, `proposed_decision` JSONB, `final_decision` JSONB, `confidence` NUMERIC, `correction_reason` TEXT, `quality_status` TEXT, `created_at` TIMESTAMPTZ, `verified_at` TIMESTAMPTZ, `decision_type` TEXT, `decided_by` TEXT, `updated_at` TIMESTAMPTZ
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@@ -650,8 +650,12 @@ know:confirmation_token_hash a owl:DatatypeProperty ;
|
||||
rdfs:range xsd:string .
|
||||
|
||||
know:confirmed_at a owl:DatatypeProperty ;
|
||||
rdfs:domain know:Hinweis ;
|
||||
rdfs:range xsd:dateTime .
|
||||
rdfs:domain [ a owl:Class ; owl:unionOf ( know:Ankaufsfall know:Hinweis ) ] ;
|
||||
rdfs:range xsd:string .
|
||||
|
||||
know:confirmed_by a owl:DatatypeProperty ;
|
||||
rdfs:domain know:Ankaufsfall ;
|
||||
rdfs:range xsd:string .
|
||||
|
||||
know:contact_broker a owl:DatatypeProperty ;
|
||||
rdfs:domain know:Ankaufsfall ;
|
||||
@@ -689,6 +693,10 @@ know:deadline_is_overdue a owl:DatatypeProperty ;
|
||||
rdfs:domain know:Ankaufsfall ;
|
||||
rdfs:range xsd:boolean .
|
||||
|
||||
know:decided_by a owl:DatatypeProperty ;
|
||||
rdfs:domain know:Entscheidung ;
|
||||
rdfs:range xsd:string .
|
||||
|
||||
know:decision_type a owl:DatatypeProperty ;
|
||||
rdfs:domain know:Entscheidung ;
|
||||
rdfs:range xsd:string .
|
||||
|
||||
Reference in New Issue
Block a user