Saved presets keep URL and model per stage so detect can switch to Ollama without re-entering settings or sending plaintext to OpenRouter. Co-authored-by: Cursor <cursoragent@cursor.com>
12 KiB
| title | version | status | date | product_family | document_role | parent_document |
|---|---|---|---|---|---|---|
| Kanshō – Backend und API | 0.1 | Arbeitsstand | 2026-08-19 | Jinkendo | Technical Chapter / Backend / API | 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):
authprofiles- 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
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:
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
decisionundtrace(Testphase) - Generate:
POST /days/{id}/generatenur explizit; optionaleconversation_ids;include_existingnur nach ausdrücklicher UI-Auswahl; ohne Auswahl kein stilles Mergen; optionalergeneration_policy-Snapshot undremember_generation_policy - Generation Policy:
GET /generation-settings— profilbezogene Defaults der vier Journal-Ausgabeeinstellungen, nicht Writing Profile. Die Anweisungstexte kommen ausgeneration_instruction_fragments, nicht aus dem Nutzerregler. - Additiv 2026-08-27: Generate sendet
generation_selection(transformation_id,detail_id,voice_id,narrative_id) undremember_generation_selection(Default false).GET /generation-settingsliefertselection, aktiveoptionsohne Promptanweisung und System-defaults. Unbekannte oder nicht aktive IDs: 400invalid_generation_selection. Der gespeicherte Entwurf enthältgeneration_snapshotundgeneration_summary. - Additiv 2026-08-28: Ungültige
generation_selectionbricht vor Detect- und Generate-Provideraufrufen ab. Preview nutzt denselbencompile_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-settingsliefert diese Flags an den Journal-Tag, ohne Promptanweisung. AdminPUT/POSTversioniert Anweisung und Stilkontext gemeinsam. Kein zusätzlicher Generate-Parameter. - Additiv 2026-08-29: Snapshot und Trace führen
cloned_fromder 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 abgelehntPOST /api/admin/generation-instructions/{purpose}/resetPOST /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 AnweisungstexteGET /api/admin/generation-instructions/{purpose}/{id}POST /api/admin/generation-instructions/{purpose}— neuer DraftPUT /api/admin/generation-instructions/{purpose}/{id}— nur DraftPOST .../{id}/clone|publish|archive|defaultDELETE .../{id}— nur ungenutzter DraftPOST .../reset— neue Seed-Drafts, keine Überschreibung historischer VariantenPOST .../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 mitentry_id+origin=accepted_draftlegt eine neue Version desselben Entry an. - Media: Upload/GET/DELETE; Bilder und einzelne Videos; Position/Unterschrift im Entry-Body als Markdown
 - Tagesstichpunkte:
PATCH /days/{id}/scratch— lokal, nicht Context-Builder - Writing Profile:
GET /writing-profile, Import (optionaloccurred_at,context_hint), KorpusGET/POST /writing-profile/corpus, Rebuild,PATCHGovernance, Facet-Edit/Lock, Trait-EditPATCH /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 Vertragkansho.profile_analysis_package/kansho.profile_analysis_result(modeinitial_build|review,corpus,existing_before_new,expected_result). Legacy-kindkansho.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 tragencost_reportund den Providergrund (code,message, optionalhttp_status/provider_message); die generische Client-Meldung „Anfrage fehlgeschlagen“ ist nicht mehr der einzige sichtbare Text. - Interaction Profile:
GET /interaction-profile,PATCHGovernance und Präferenzen, Vorschläge annehmen/verwerfen. Keine Ableitung aus Nicht-Widersprechen. Der Slot liegt unter/api/journalnur 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 istlocal_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.
Additiv 2026-09-08: llm_profiles. POST /api/admin/providers/{role}/activate, CRUD unter /api/admin/llm-profiles. Keys weiterhin nicht in der DB.
5.4 Implementierungsstand (Debug-Persistenz)
Additiv 2026-08-28. Session-Admin. Default aus. Nur eigenes Profil in Liste/Export.
GET/PUT /api/admin/debug— Schalterpersist_enabledGET /api/admin/debug/tree— Space / Tag / Gespräche / SchritteGET /api/admin/debug/latest?journal_day_id=&purpose=— letzter passender LaufGET /api/admin/debug/runs,GET/DELETE /api/admin/debug/runs/{id},POST /api/admin/debug/runs/clearGET /api/admin/debug/export?format=json|markdown— optionalconversation_id,journal_day_id,purpose.kansho.debug_exportv2
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
- Internes API für mindnet/Kairo: synchron REST vs. Events? →
integrations_technical.md - Idempotenz-Keys für Offline-Sync-Queue? →
memory_storage_and_offline.md - 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