Kansho/docs/architecture/technical/backend_and_api.md
Lars bef422a429
Some checks failed
Deploy Development / deploy (push) Successful in 53s
Test Suite / pytest-backend (push) Failing after 2m40s
Test Suite / smoke-dev (push) Successful in 0s
Test Suite / frontend-build (push) Successful in 16s
Add selectable LLM profiles and treat LAN Ollama as local.
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>
2026-09-08 12:48:25 +02:00

12 KiB
Raw Permalink Blame History

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):

  • 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

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 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.

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 — 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