# 🌲 Crumbforest Code Tour Dies ist dein "Reiseführer" durch den Code. Ziel ist es, jede Komponente zu verstehen, damit du sie als solide Basis für zukünftige Projekte nutzen kannst. ## 🗺️ High-Level Architektur (Der Wald von oben) Der CrumbCore basiert auf **FastAPI** (Python) und folgt einer modularen Struktur: * **`app/main.py`**: Der Eingang (Root). Hier startet alles. * **`app/routers/`**: Die Wegweiser. Jede Datei bedient einen URL-Bereich (z.B. `/admin`, `/api`). * **`app/services/`**: Die Arbeiter. Logik für RAG, Übersetzungen, Config-Loading. * **`app/models/`**: Die Datenbank-Struktur (SQLAlchemy / raw SQL Schemas). * **`app/templates/`**: Das Gesicht (Jinja2 HTML Templates) & Design. --- ## 🚀 1. Der Einstieg: `app/main.py` Hier atmet das System. ### Wichtige Konzepte: 1. **FastAPI Instanz**: `app = FastAPI()` ist der Kern. 2. **Middleware**: `SessionMiddleware` (für Login-Cookies) und `CORSMiddleware` (Sicherheit). 3. **Template Engine**: `init_templates(app)` lädt Jinja2. Unsere `render`-Funktion injiziert automatisch User, Sprache und Flash-Nachrichten in jedes Template. 4. **Router Mounting**: Am Ende der Datei werden die Module aus `routers/` eingebunden (`app.include_router(...)`). Das hält `main.py` schlank. ### Code-Lupe: ```python # app/main.py # ... Imports ... # Security Secret (wichtig für Cookies!) SECRET = os.getenv("APP_SECRET", "dev-secret-change-me") app = FastAPI() # 1. Statische Dateien (CSS, Bilder) verfügbar machen app.mount("/static", StaticFiles(directory="static"), name="static") # 2. Session Middleware (Das Gedächtnis des Browsers) app.add_middleware(SessionMiddleware, secret_key=SECRET, ...) # 3. Template Renderer (Unsere "View Engine") def init_templates(app: FastAPI): # ... lädt "templates"-Ordner ... # Definiert die "render"-Funktion, die wir überall nutzen def render(req: Request, template: str, **ctx): # ... Logik für Sprache (lang) und User-Context ... return HTMLResponse(tpl.render(**base_ctx)) # 4. Router einbinden (Modularisierung) app.include_router(home_router, prefix="/{lang}") # Multi-Language Support! # ... ``` --- ## 🚦 2. Das Routing: `app/routers/` Hier entscheidet sich, wohin die Reise geht. * **`home.py`**: Öffentliche Seiten (`/`, `/about`, `/crew`). Lädt Inhalte multiligual. * **`crumbforest_roles.py`**: Das Herzstück Phase 1. Zeigt Rollen-Dashboard und Chat. Prüft `user_group`-Zugriff. * **`auth.py`** (bzw. Login in Hauptdatei/Home): Verwaltet Login/Logout. * **`diary_rag.py`**: API für das Tagebuch-RAG (Vector Search). --- ## 🧠 3. Die Intelligenz: `app/services/` * **`rag_service.py`**: Verbindet Qdrant (Vektordatenbank) mit LLMs. Hier passiert die Magie ("Suche Igel im Wald"). * **`localization.py`**: Lädt `characters.de.json` usw. und merget sie live in die Config. --- ## 💾 4. Die Daten: `crumbforest_config.json` Unsere "Single Source of Truth" für Rollen und Gruppen. Statt Hardcoding in Python definieren wir hier: * Wer darf was sehen? (`group_access`) * Welche Farbe hat der Fuchs? * Welches LLM nutzt die Eule? --- Dies ist der Startpunkt. Welchen Bereich wollen wir als nächstes zerlegen? 🧐 ## 🧠 5. Deep Dive: Der RAG Service (`app/services/rag_service.py`) Hier wird Text zu Wissen. Wenn wir "Wald" sagen, müssen wir nicht nur Keyword-Matches finden, sondern *Bedeutung*. ### Der Indexing-Workflow (`index_post`) Wie kommt ein Blogpost oder Tagebucheintrag in das Gehirn? 1. **Hash-Check**: Wir erstellen einen MD5-Hash des Inhalts. Ist er gleich wie in der DB? Überspringen! (Spart KI-Kosten). 2. **Chunking**: Der Text wird mit `EmbeddingService` in Häppchen geteilt (z.B. 1000 Zeichen). 3. **Embedding**: Jedes Häppchen wird durch ein Embedding-Modell (OpenAI/Jina) geschickt. Das Ergebnis ist ein Vektor (eine Liste von Zahlen, z.B. `[0.1, -0.5, ...]`). 4. **Upsert in Qdrant**: Wir speichern den Vektor + Metadaten (Textinhalt, Titel, Slug) in Qdrant. 5. **Tracking**: In MariaDB (`post_vectors` Tabelle) merken wir uns, welcher Post welche Vektoren hat (für Löschung/Updates). ### Die Suche (`query_with_rag`) Der magische Moment, wenn der User eine Frage stellt: 1. **Embed Query**: Die Frage "Wer wohnt im Wald?" wird ebenfalls in einen Vektor verwandelt. 2. **Vektor-Suche (Semantic Search)**: Wir fragen Qdrant: "Welche Vektoren liegen in der Nähe dieses Frage-Vektors?". Dank Cosine-Similarity findet er Inhalte, die *inhaltlich* passen, auch ohne exakte Worte. 3. **Context Assembly**: Wir nehmen die Top-3 gefundenen Text-Chunks und kleben sie zusammen. 4. **LLM Generation**: Wir bauen einen Prompt für die KI: ```text Context: [Der Igel wohnt im Unterholz...] Frage: Wer wohnt im Wald? Antworte basierend auf dem Context. ``` 5. **Antwort**: Die KI generiert die fertige Antwort. ### Warum `rag_service.py` wichtig ist Er entkoppelt die Logik: * Der *Router* (`diary_rag.py`) weiß nur: "Indexiere dies" oder "Frage das". * Der *Service* kümmert sich um die Details (Qdrant API, Datenbank-Sync, Hash-Prüfung). So bleibt der Controller sauber! 🧹✨ ## 🔐 6. Deep Dive: Sicherheit & Auth (`app/deps.py`) Wie unterscheiden wir Freund von Feind? Das "Dependency Injection" System von FastAPI regelt das elegant. ### Der Wächter: `current_user` In `app/deps.py` definieren wir Funktionen, die FastAPI *vor* jedem Request ausführt. ```python # app/deps.py def current_user(req: Request): # Holt das User-Objekt aus dem signierten Session-Cookie return req.session.get("user") def admin_required(user = Depends(current_user)): # 1. Ist ein User da? if not user: raise HTTPException(status_code=401) # -> Login Page # 2. Ist es ein Admin? if user.get("role") != "admin": raise HTTPException(status_code=403) # -> Verboten! return user ``` ### Die Anwendung in Routern Wir müssen Sicherheitschecks nicht in jede Funktion kopieren. Wir "injizieren" sie einfach: ```python # app/routers/admin.py @router.get("/") def admin_dashboard( user: dict = Depends(admin_required) # <--- Hier passiert der Check! ): # Wenn wir hier sind, IST der User garantiert ein Admin. return render(..., user=user) ``` ### Session Security (in `main.py`) Das Login-System basiert auf `SessionMiddleware`. * **Cookie**: Der Browser bekommt ein Cookie namens `session`. * **Signierung**: Das Cookie ist mit `APP_SECRET` kryptografisch signiert. Der User kann den Inhalt lesen (Base64), aber **nicht verändern**. Wenn er `role: admin` reinschummelt, wird die Signatur ungültig und der Server ignoriert das Cookie. * **HttpOnly**: JavaScript kann das Cookie nicht stehlen. * **SameSite**: Schützt vor CSRF-Attacken. ## 🎨 7. Das Frontend (`app/templates/`) Wir nutzen **Jinja2** (klassisches Server-Side Rendering) gepaart mit **PicoCSS** (minimalistisches CSS Framework). ### Struktur * **`base.html`**: Das Skelett. Enthält ``, Navigation und Footer. Alle anderen Seiten erben hiervon (`{% extends "base.html" %}`). * **`crumbforest/`**: Templates für die Rollen-Ansicht und den Chat. * **`pages/`**: Allgemeine Seiten (Login, Home). ### Datenfluss Wenn ein Router `render(req, "login.html", error="Falsches PW")` aufruft: 1. Jinja2 lädt `login.html`. 2. Es sieht `{% extends "base.html" %}` und lädt erst das Skelett. 3. Es füllt die Blöcke (`{% block content %}`) mit dem Login-Formular. 4. Es injiziert die Variable `error` an der passenden Stelle. ## 💾 8. Die Daten (`app/models/` & SQL) Hier wird es interessant. Wir nutzen **Hybrid-Ansatz**: ### API-Validierung (Pydantic) In `app/models/` liegen Klassen wie `QueryRequest` oder `User`. Das sind **keine** Datenbank-Tabellen! Sie dienen nur der **Validierung** von Input/Output. Wenn jemand JSON an die API schickt, prüft FastAPI automatisch: "Fehlt das Feld 'question'? Ist 'limit' eine Zahl?". ### Datenbank (Raw SQL) Wir nutzen *kein* schwergewichtiges ORM (wie SQLAlchemy) für die Queries, sondern rohes SQL via `pymysql`. Warum? **Performance & Kontrolle**. * Zu sehen in: `app/services/rag_service.py` oder `main.py`. * Codeschnipsel: ```python cur.execute("SELECT * FROM users WHERE email=%s", (email,)) ``` Das macht den Code extrem transparent. SQL ist die Wahrheit. --- 🎉 **Herzlichen Glückwunsch!** Du hast den Wald einmal durchquert. Du kennst jetzt: 1. Den Einstieg (`main.py`) 2. Die Logik (`routers` & `services`) 3. Die Sicherheit (`deps.py`) 4. Das Gesicht (`templates`) 5. Das Gedächtnis (`models` & SQL) Bereit für Phase 2? 🚀