Files
Crumb-Core-v.1/CODE_TOUR.md

218 lines
8.4 KiB
Markdown

# 🌲 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 `<head>`, 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? 🚀