mega — lass uns den ersten Meilenstein sauber festhalten. Hier ist ein fertiges `.md`, das du direkt in dein Repo legen kannst. Ich gebe dir einen ASCII-Dateinamen (problemlos für Shell/URLs); wenn du magst, kannst du ihn später mit Emojis umbenennen.

## Dateiname (Vorschlag)

`erste_insel_im_nirgendwo_crumbforest.md`

## Inhalt (copy-paste)

```markdown
# 🌲 Erste Insel im Nirgendwo — der Crumbforest atmet

**TL;DR:**  
- **Gitea** läuft und hält alle Markdown-Quellen.  
- **Qdrant** hat die Collection `md_files` (aktuell ~839 Chunks) und zeigt sauber im Dashboard.  
- **Eule (RAG)** fragt Kontext aus Qdrant ab; **LLM** via OpenRouter geht wieder (lokaler Proxy empfohlen).  
- **TTYD** ist erreichbar (Basic-Auth), `.env` wurde gehärtet.  
- **Cron** indiziert regelmäßig; **Snapshots** sichern `md_files`.

---

## 🧭 Was jetzt “steht”

- **Repo (Gitea):** `Crumbforest-Markdowns`  
  → Quelle für alle Texte, die in den Wald gehen.

- **Index-Pfad:** `/opt/gitea-md/repo/**/*.md`  
  → Python-Indexer zerlegt, embeded und **upsertet** in Qdrant → `md_files`.

- **Vektor-DB:** Qdrant 1.12.x  
  - Collection: `md_files`  
  - Vektoren: 384, **COSINE**, HNSW `m=16`, `ef_construct=100`  
  - Web-UI unter: **`https://qdrant.<DEINE-IP>.sslip.io/dashboard/`** (Subdomain + Basic-Auth)

- **Eule (RAG):** `/opt/eule/eule_rag.py`  
  - Embedding-Modell: `all-MiniLM-L6-v2`  
  - Kontext: Top-K Treffer + kurze Auszüge  
  - Optional **LLM** via OpenRouter (lokaler NGINX-Proxy, Key nicht mehr im TTY sichtbar)

---

## 🧩 Architektur in Kurzform

```

Gitea (Markdowns)
└─(git pull)── /opt/gitea-md/repo
└─ index\_md\_qdrant.py ──> Qdrant(md\_files)

Qdrant UI  ⇐ NGINX (qdrant.<ip>.sslip.io, Basic-Auth)
TTYD       ⇐ NGINX (/terminal, Basic-Auth)

Eule RAG ──> Qdrant (Kontext)
──> OpenRouter via 127.0.0.1:8088 (NGINX injiziert Authorization)

````

---

## 🛡️ Security, die wir gezogen haben

- **Kein OpenRouter-Key im TTYD:** stattdessen **lokaler NGINX-Proxy** auf `127.0.0.1:8088`, der den `Authorization`-Header setzt.  
- **Basic-Auth** vor Qdrant-UI und TTYD.  
- **`.env` perms** reduziert, keine Secrets im Repo.  
- **Subdomain-Split**: `qdrant.<ip>.sslip.io` für klare Trennung.

---

## 🔧 Wichtige Kommandos (How-To)

**Indexer jetzt starten (idempotent):**
```bash
/opt/gitea-md/index_md_qdrant.py
````

**Cron läuft alle 30 Minuten:**

```cron
*/30 * * * * /opt/gitea-md/index_md_qdrant.py >>/var/log/eule/index.log 2>&1
```

**Snapshot der Collection ziehen:**

```bash
curl -sX POST http://127.0.0.1:6333/collections/md_files/snapshots | jq
```

**Schnelltest Qdrant:**

```bash
curl -s http://127.0.0.1:6333/collections/md_files | jq '.result.points_count'
```

**RAG-Suche ohne LLM:**

```bash
python /opt/eule/eule_rag.py "Crumbforest Eule" --no-llm
```

**RAG + LLM (wenn Proxy gesetzt):**

```bash
python /opt/eule/eule_rag.py "Was ist der Crumbforest?"
```

---

## 🧯 Stolpersteine & Fixes der letzten Tage

* **DNS/OpenRouter 1016 / NXDOMAIN** → final gelöst über **lokalen OpenRouter-Proxy** (127.0.0.1:8088).
* **Qdrant UI unter Subpfad** → auf Subdomain umgezogen; Assets & `/openapi.json` sauber erreichbar.
* **SSH vs. HTTPS in Gitea** → pragmatischer Fix via `.netrc` (HTTPS).
* **Qdrant-Client Warnung** (1.15 vs. 1.12) → `check_compatibility=False` und **`search()`** statt `query_points` (für diese Version stabiler).
* **CLI-Args** (`--no-llm`) → Argument-Parsing bereinigt.
* **`.env` Newline** → trailing CR/LF gecheckt; Keys neu geladen.

---

## ✅ Fertig-Checks

* `curl https://qdrant.<ip>.sslip.io/collections` → **200 OK**
* Dashboard zeigt `md_files` → **points \~839**
* `python /opt/gitea-md/search_md_qdrant.py "Crumbforest Eule"` → **5 Treffer**
* `python /opt/eule/eule_rag.py "Frage" --no-llm` → **Kontext + Quellen**
* (optional) mit LLM → **knappe Antwort + Quellenlink**

---

## 🎯 Nächste Schritte

* **Role „vector“**: kleine Search-API (Flask/FastAPI) bauen: `/search?q=…` → JSON-Kontext.
* Qdrant-Client auf Server-Minor upgraden (oder Server anheben), dann auf `query_points` wechseln.
* **Rate-Limit** auf OpenRouter-Proxy (nginx `limit_req`), einfache Metriken.
* Wiederkehrende **Snapshots** der Collection + Offsite-Kopie.

---

*#crumbforest #log #qdrant #gitea #ttyd #nginx #eule #rag*

````

---

## So legst du die Datei ins Repo & triggert den Index

```bash
cd /opt/gitea-md/repo
nano erste_insel_im_nirgendwo_crumbforest.md   # Inhalt einfügen & speichern
git add erste_insel_im_nirgendwo_crumbforest.md
git commit -m "Log: Erste Insel im Nirgendwo – Setup & Learnings"
git push
/opt/gitea-md/index_md_qdrant.py
````

Wenn alles passt, solltest du im Qdrant-Dashboard und via `search_md_qdrant.py` bald einen neuen Treffer sehen.
