Kansho/docs/architecture/technical/backend_and_api.md
2026-08-29 20:28:59 +02:00

164 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "Kanshō Backend und API"
version: "0.1"
status: "Arbeitsstand"
date: "2026-08-19"
product_family: "Jinkendo"
document_role: "Technical Chapter / Backend / API"
parent_document: "technische_zielarchitektur.md"
---
# Kanshō Backend und API
Kanonisches Home für FastAPI-Struktur, Router-Schnitt und API-Vertrag. Mitai-Referenz: `.claude/rules/ARCHITECTURE.md` §1, `backend/main.py`, `backend/routers/`.
## 1. Prinzipien
Herkunft: Mitai-Architekturregeln, als Rahmen übernommen.
### 1.1 Ein Modul = ein Router
Jedes fachliche Modul besitzt genau eine Router-Datei unter `backend/routers/`. Endpoints liegen nicht in `main.py` außer Health/Status.
Neue Module = neue Datei, Registrierung via `app.include_router(..., prefix="/api")`.
Rahmen-Module (erste erwartbare Dateien, keine vollständige Liste):
- `auth`
- `profiles`
- später: Dialog, Memory, Journal-Handoff, Gateway-Audit-Metadaten, Admin-Diagnose
Domänenrouter für Mitai-Tracking werden nicht angelegt.
### 1.2 API-First
Jede vom UI benötigte Funktion ist zuerst ein Endpoint. Das Frontend spricht ausschließlich diese API (Mitai: `utils/api.js`). Keine fachliche Berechnung, kein Context-Building und kein Privacy-Demasking im Browser.
### 1.3 Fehlerformat
```text
HTTPException → {"detail": "menschenlesbare Meldung"}
```
Keine parallelen Formate (`error`, `success: false`). Herkunft: Mitai.
### 1.4 Auth an der Grenze
Geschützte Routen nutzen `Depends(require_auth)` bzw. `require_admin`. Ressourcenfilter immer über Session-`profile_id`. Siehe `auth_identity_and_roles.md`.
## 2. Schichten im Backend
Bevorzugte innere Trennung, analog Mitai plus Kanshō-spezifische Gateway-Schicht:
```text
routers/ HTTP, Validierung, Auth-Depends
services/ fachliche Orchestrierung (später)
privacy_gateway/ Minimierung, Pseudonymisierung, Egress, Validation
data/ PostgreSQL-Zugriff
```
**Status: bevorzugte Richtung** für Ordnernamen. Kein Zwang, Mitai-Dateibaum 1:1 zu klonen, wenn die Trennlinie Router / Gateway / Persistenz klar bleibt.
Privacy Gateway darf nicht umgangen werden, indem ein Router den Provider direkt aufruft. KI-Ausführung nur über die Prompt-Engine (`platform_extensibility.md`), Callback = Gateway.
## 3. Versionierung
Mitai führt `backend/version.py` mit `APP_VERSION` und `MODULE_VERSIONS`.
**Status: bevorzugte Richtung** gleiches Muster für Kanshō, sobald Code existiert. Semantic Versioning.
## 4. Health und Betrieb
Ein ungeschützter oder schwach geschützter Status-Endpoint für Deploy-Healthchecks analog Mitai `/api/auth/status` bzw. Health nach Container-Start.
Konkreter Pfad: offen, Muster übernommen.
## 5. Entscheidungsstand
| Thema | Stand | Status |
|---|---|---|
| FastAPI + ein Router je Modul | ja | entschieden |
| API-First, keine Business-Logik im Frontend | ja | entschieden |
| Fehlerkörper `{detail}` | ja | entschieden |
| Direktaufruf externer LLMs aus Routern | verboten | entschieden |
| OpenAPI als dokumentierter Vertrag | später | offen |
| Interne service-Schicht vs. fette Router | service-Schicht | bevorzugte Richtung |
## 5.1 Implementierungsstand (MVP-Journal-API)
**Status: Code vorhanden.** Router: `backend/routers/journal.py`, Prefix `/api/journal`. Zusammenhängende Umsetzung: `mvp_implementation.md`.
Produkt-Endpunkte hinter Session-Auth, Isolation über `profile_id`:
- Spaces: `GET/POST /spaces`, `GET/PATCH /spaces/{id}`, `POST /spaces/{id}/days`, `GET /spaces/{id}/entries`, `GET /spaces/{id}/trash`
- Days: `GET /days/{id}` inkl. Conversations, Current Draft, Entries, `consolidation_offer`
- Start: `GET /continuity`
- Dialog: `POST /days/{id}/conversations` (erster Impuls), `POST /conversations/{id}/turn` (ein Modell-Call, bei Erzähler-Fortsetzung einmal Korrektur), `GET /conversations/{id}`, `DELETE /conversations/{id}` (Profil-isoliert; Nachrichten und Derived dieser Conversation gehen mit)
- Status: `GET /egress-status` (Provider bereit / fail-closed)
- Derselbe Zug auch unter `POST /api/dialogue/conversations/{id}/turn`
- Admin-Antwort zusätzlich `decision` und `trace` (Testphase)
- Generate: `POST /days/{id}/generate` nur explizit; optionale `conversation_ids`; `include_existing` nur nach ausdrücklicher UI-Auswahl; ohne Auswahl kein stilles Mergen; optionaler `generation_policy`-Snapshot und `remember_generation_policy`
- Generation Policy: `GET /generation-settings` — profilbezogene Defaults der vier Journal-Ausgabeeinstellungen, nicht Writing Profile. Die Anweisungstexte kommen aus `generation_instruction_fragments`, nicht aus dem Nutzerregler.
- **Additiv 2026-08-27:** Generate sendet `generation_selection` (`transformation_id`, `detail_id`, `voice_id`, `narrative_id`) und `remember_generation_selection` (Default false). `GET /generation-settings` liefert `selection`, aktive `options` ohne Promptanweisung und System-`defaults`. Unbekannte oder nicht aktive IDs: 400 `invalid_generation_selection`. Der gespeicherte Entwurf enthält `generation_snapshot` und `generation_summary`.
- **Additiv 2026-08-28:** Ungültige `generation_selection` bricht vor Detect- und Generate-Provideraufrufen ab. Preview nutzt denselben `compile_selection`-Pfad. Katalog-Publish/Default ändert gespeicherte Profilauswahl nicht.
- **Additiv 2026-08-29:** Voice-Ausprägungen tragen `style_context` (`include_core`, `include_facet`, `include_traits`, `include_style_examples`). `GET /generation-settings` liefert diese Flags an den Journal-Tag, ohne Promptanweisung. Admin `PUT/POST` versioniert Anweisung und Stilkontext gemeinsam. Kein zusätzlicher Generate-Parameter.
- **Additiv 2026-08-29:** Snapshot und Trace führen `cloned_from` der Voice-Ausprägung. Legacy-Vergleichs-IDs sind normale aktive Optionen, nicht Default.
## 5.3 Implementierungsstand (Generierungsrichtlinien)
**Status: Code vorhanden.** Admin-Session. Purpose zunächst `journal_generate`.
- `GET /api/admin/generation-instructions/{purpose}`
- `PUT /api/admin/generation-instructions/{purpose}` — vollständiger Satz, transaktional, ungültige Teilstände werden abgelehnt
- `POST /api/admin/generation-instructions/{purpose}/reset`
- `POST /api/admin/generation-instructions/{purpose}/preview` — lokal, kein Provider, keine persönlichen Quellen
**Additiv 2026-08-27 (benannte Ausprägungen):** Der numerische Katalog-PUT entfällt. Übersicht ohne Promptkörper. Detail, Klon, Draft-Update, Veröffentlichen, Archivieren, Standard und Löschen nur für unverwendete Drafts:
- `GET /api/admin/generation-instructions/{purpose}` — Kartenfelder, keine Anweisungstexte
- `GET /api/admin/generation-instructions/{purpose}/{id}`
- `POST /api/admin/generation-instructions/{purpose}` — neuer Draft
- `PUT /api/admin/generation-instructions/{purpose}/{id}` — nur Draft
- `POST .../{id}/clone|publish|archive|default`
- `DELETE .../{id}` — nur ungenutzter Draft
- `POST .../reset` — neue Seed-Drafts, keine Überschreibung historischer Varianten
- `POST .../preview` — lokal gerenderter Prompt, Dummy-Kontext, kein Provider
UI: `/admin/generation` mit getrennten Dimensionen, Karten und einem Editor nach „Öffnen“. Source Modes eigener Abschnitt. Keine Seed-Dateipfade in der normalen Adminbeschreibung.
**Additiv 2026-08-27 (kein Source Mode):** Preview und Admin-UI verwalten nur die vier Gestaltungsdimensionen. `source_mode` ist kein Request-Feld mehr. Ein Custom-Prompt mit veraltetem Platzhalter: 409 `prompt_contract_incompatible`, kein Provideraufruf, kein Draft.
- Entries: `POST /entries`, `GET /entries/{id}`, Versionen, Versions-Restore, Soft-Delete, `POST /entries/{id}/undelete`, `POST /entries/{id}/purge`. Speichern aus einem Entwurf mit `entry_id` + `origin=accepted_draft` legt eine neue Version desselben Entry an.
- Media: Upload/GET/DELETE; Bilder und einzelne Videos; Position/Unterschrift im Entry-Body als Markdown `![…](kansho-media:<id>)`
- Tagesstichpunkte: `PATCH /days/{id}/scratch` — lokal, nicht Context-Builder
- Writing Profile: `GET /writing-profile`, Import (optional `occurred_at`, `context_hint`), Korpus `GET/POST /writing-profile/corpus`, Rebuild, `PATCH` Governance, Facet-Edit/Lock, Trait-Edit `PATCH /writing-profile/traits/{slug}`, Vorschläge annehmen/verwerfen. Brief ist eine abgeleitete Sicht aus Traits und zeitgestempelten Quellen. Media-Token werden vor dem Brief entfernt. JSON-Export/Restore: `GET /writing-profile/export`, `POST /writing-profile/restore`. Review: `GET /writing-profile/review`, `POST /writing-profile/review/paste`, `POST /writing-profile/review/api`, `POST /writing-profile/review/import`, `POST /writing-profile/review/accept`, `POST /writing-profile/review/reject`. Initial Build: `POST /writing-profile/initial-build/paste`, `POST /writing-profile/initial-build/api`. API und Copy/Paste nutzen denselben Vertrag `kansho.profile_analysis_package` / `kansho.profile_analysis_result` (`mode` `initial_build`\|`review`, `corpus`, `existing_before_new`, `expected_result`). Legacy-`kind` `kansho.profile_review_*` bleibt lesbar. Import erzeugt ein Proposal, kein Current Profile; Übernahme erst nach Accept. Der Current Brief ist kein Import-/Exportformat. **Additiv 2026-08-29:** Fehler von Review/Initial-Build-API tragen `cost_report` und den Providergrund (`code`, `message`, optional `http_status` / `provider_message`); die generische Client-Meldung „Anfrage fehlgeschlagen“ ist nicht mehr der einzige sichtbare Text.
- Interaction Profile: `GET /interaction-profile`, `PATCH` Governance und Präferenzen, Vorschläge annehmen/verwerfen. Keine Ableitung aus Nicht-Widersprechen. Der Slot liegt unter `/api/journal` nur als Settings-Nachbar, nicht als Journal-Artefakt. JSON-Export/Restore: `GET /interaction-profile/export`, `POST /interaction-profile/restore`.
- Beide Profile: `GET /profiles/export`, `POST /profiles/restore` (`kind: kansho.profiles`). Journal-Backup ist `local_backup.py`, nicht dieser Profil-Export.
`/api/dialogue/*` bleibt Low-Level-Source und Admin-Diagnose, nicht die Produkt-IA. Context Builder und Retrieval liegen nicht im Frontend.
## 5.2 Implementierungsstand (Provider-Admin)
**Status: Code vorhanden.** `GET /api/admin/providers`, `PUT /api/admin/providers/{generate|detect}`. Session-Admin. Body darf einen write-only `key` enthalten; die Antwort enthält ihn nicht. Persistenz: URL/Modell/Flags in `provider_settings`, Key in `backend/.env`.
## 5.4 Implementierungsstand (Debug-Persistenz)
**Additiv 2026-08-28.** Session-Admin. Default aus. Nur eigenes Profil in Liste/Export.
- `GET/PUT /api/admin/debug` — Schalter `persist_enabled`
- `GET /api/admin/debug/tree` — Space / Tag / Gespräche / Schritte
- `GET /api/admin/debug/latest?journal_day_id=&purpose=` — letzter passender Lauf
- `GET /api/admin/debug/runs`, `GET/DELETE /api/admin/debug/runs/{id}`, `POST /api/admin/debug/runs/clear`
- `GET /api/admin/debug/export?format=json|markdown` — optional `conversation_id`, `journal_day_id`, `purpose`. `kansho.debug_export` v2
UI: `/admin/debug` (Baum). Im Dialog bei angeschalteter Persistenz: Gesprächs-JSON. Am Journal-Entwurf: sichtbare Testspur und Entwurf-JSON. Kein Gateway-Bypass. Mapping-Labels nicht in der Payload. Keine Live-Testspur unter der Konversation.
## 6. Offene Fragen
1. Internes API für mindnet/Kairo: synchron REST vs. Events? → `integrations_technical.md`
2. Idempotenz-Keys für Offline-Sync-Queue? → `memory_storage_and_offline.md`
3. Rate Limits außer Auth: welche Dialog-Endpoints?
## 7. Querverweise
- Technisch: `auth_identity_and_roles.md`, `privacy_gateway.md`, `runtime_and_deploy.md`
- Mitai: `ARCHITECTURE.md` §1, `INTERNAL_API_REFERENCE.md`