# 🗄️ Qdrant Zugriff & Sicherheit

## 🔐 Sicherheits-Status

### ✅ Nach Fix (SICHER)
```yaml
ports:
  - "127.0.0.1:6333:6333"  # Nur localhost
```

**Zugriff:**
- ✅ Lokal (auf Server): `http://localhost:6333`
- ✅ Via Docker Network: `http://qdrant:6333`
- ❌ Von außen: NICHT erreichbar (sicher!)

### ⚠️ Vorher (UNSICHER)
```yaml
ports:
  - "6333:6333"  # Öffentlich!
```

## 🌐 Zugriffsmethoden

### 1. Lokal auf dem Server

```bash
# Dashboard öffnen (wenn auf Server)
open http://localhost:6333/dashboard

# Collections abfragen
curl http://localhost:6333/collections | jq

# Collection Details
curl http://localhost:6333/collections/docs_crumbforest_ | jq
```

### 2. Via Docker Network (FastAPI App)

```python
# app/deps.py - Bereits implementiert
def get_qdrant_client():
    from qdrant_client import QdrantClient
    from config import get_settings
    
    settings = get_settings()
    # Nutzt Docker Network Name: "qdrant"
    return QdrantClient(
        host=settings.qdrant_host,  # "qdrant"
        port=settings.qdrant_port   # 6333
    )
```

**Warum funktioniert das?**
- Container im gleichen Docker Network können sich per Name erreichen
- `qdrant` wird zu interner IP aufgelöst
- Keine externe Exposition nötig!

### 3. Remote Zugriff via SSH Tunnel

```bash
# Von deinem lokalen Rechner zum Server
ssh -L 6333:localhost:6333 user@your-server.com

# Jetzt lokal öffnen
open http://localhost:6333/dashboard

# Oder per API
curl http://localhost:6333/collections | jq
```

**Erklärung:**
- `-L 6333:localhost:6333` = Forward lokaler Port 6333 zu Server Port 6333
- Sicher über SSH encrypted
- Dashboard läuft "lokal" aber zeigt Server-Daten

### 4. Production Setup mit Nginx

```nginx
# /etc/nginx/sites-available/qdrant
server {
    listen 443 ssl;
    server_name qdrant.crumbforest.de;

    ssl_certificate /etc/letsencrypt/live/qdrant.crumbforest.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/qdrant.crumbforest.de/privkey.pem;

    # Basic Auth
    auth_basic "Qdrant Admin";
    auth_basic_user_file /etc/nginx/.htpasswd;

    location / {
        proxy_pass http://localhost:6333;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
```

```bash
# Basic Auth erstellen
sudo htpasswd -c /etc/nginx/.htpasswd admin

# Nginx neu laden
sudo nginx -t && sudo systemctl reload nginx
```

## 🔍 Markdown-Dateien durchsuchen

### Methode 1: Via API (Empfohlen)

```bash
# Alle Dokumente durchsuchen
curl -X GET "http://localhost:8000/api/documents/search?q=docker&limit=10" \
  -H "Cookie: session=YOUR_SESSION_COOKIE"

# Nur Crumbforest Docs
curl -X GET "http://localhost:8000/api/documents/search?q=python&category=crumbforest&limit=5" \
  -H "Cookie: session=YOUR_SESSION_COOKIE"

# Session Cookie bekommen (nach Login)
# Im Browser: DevTools → Application → Cookies → session
```

**Mit Python:**
```python
import requests

# Login
session = requests.Session()
response = session.post(
    "http://localhost:8000/de/login",
    data={
        "email": "admin@crumb.local",
        "password": "admin123",
        "csrf": "..."  # Von Login-Form
    }
)

# Suche
results = session.get(
    "http://localhost:8000/api/documents/search",
    params={"q": "docker", "limit": 10}
).json()

for result in results["results"]:
    print(f"{result['score']:.3f} - {result['title']}")
    print(f"  → {result['content'][:100]}...")
```

### Methode 2: Direkt in Qdrant

```bash
# Collection Stats
curl http://localhost:6333/collections/docs_crumbforest_ | jq '.result | {
  status,
  points_count,
  indexed_vectors_count
}'

# Points durchsuchen (braucht Embedding!)
# Komplexer - besser via API
```

### Methode 3: Database Query (Metadaten)

```bash
# Alle indexierten Dokumente
docker compose exec -T db sh -c 'mariadb -u$MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE -e "
  SELECT 
    post_id,
    collection_name,
    JSON_EXTRACT(metadata, \"$.file_path\") as file_path,
    JSON_EXTRACT(metadata, \"$.category\") as category,
    chunk_count,
    indexed_at
  FROM post_vectors 
  WHERE post_type=\"document\"
  ORDER BY indexed_at DESC
  LIMIT 20;
"'

# Suche nach Dateiname
docker compose exec -T db sh -c 'mariadb -u$MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE -e "
  SELECT 
    JSON_EXTRACT(metadata, \"$.file_path\") as file_path,
    chunk_count
  FROM post_vectors 
  WHERE post_type=\"document\"
    AND JSON_EXTRACT(metadata, \"$.file_path\") LIKE \"%docker%\"
  ORDER BY indexed_at DESC;
"'
```

### Methode 4: Filesystem

```bash
# Alle .md Dateien finden
find docs/ -name "*.md" -type f

# Nach Inhalt suchen
grep -r "docker" docs/ --include="*.md"

# Mit Kontext
grep -r -C 3 "docker compose" docs/ --include="*.md"

# Case-insensitive
grep -ri "python" docs/ --include="*.md"
```

## 📝 Neue Version anmelden

### Szenario: Du hast eine .md Datei aktualisiert

#### Option 1: Automatisch (Empfohlen)

```bash
# 1. Datei bearbeiten
nano docs/crumbforest/my_file.md

# 2. App neu starten (triggert Auto-Indexing)
cd compose
docker compose restart app

# 3. Logs prüfen
docker compose logs app | grep -A 10 "Document Indexing"

# Erwartete Ausgabe:
# ✓ Using provider: openrouter
# 📚 Indexing documents...
# 
# 📁 crumbforest:
#    Files found:    283
#    Indexed:        1      ← Nur geänderte Datei!
#    Unchanged:      282
#    Errors:         0
```

**Wie funktioniert das?**
- File-Hash wird verglichen
- Nur geänderte Dateien werden neu indexiert
- Spart Zeit & API-Kosten!

#### Option 2: Manuell via API

```bash
# Alle Dokumente force re-indexen
curl -X POST "http://localhost:8000/api/documents/index" \
  -H "Content-Type: application/json" \
  -H "Cookie: session=..." \
  -d '{
    "provider": "openrouter",
    "force": true
  }'

# Nur eine Kategorie
curl -X POST "http://localhost:8000/api/documents/index" \
  -H "Content-Type: application/json" \
  -H "Cookie: session=..." \
  -d '{
    "category": "crumbforest",
    "provider": "openrouter",
    "force": true
  }'
```

#### Option 3: Einzelne Datei via Python

```python
# manual_index.py
import sys
sys.path.insert(0, 'app')

from pathlib import Path
from deps import get_db, get_qdrant_client
from config import get_settings
from services.provider_factory import ProviderFactory
from services.document_indexer import DocumentIndexer

# Setup
settings = get_settings()
db_conn = get_db()
qdrant = get_qdrant_client()
provider = ProviderFactory.create_provider("openrouter", settings)

# Indexer
indexer = DocumentIndexer(db_conn, qdrant, provider, "docs")

# Einzelne Datei indexieren
file_path = Path("docs/crumbforest/my_updated_file.md")
result = indexer.index_document(file_path, "crumbforest", force=True)

print(f"Status: {result['status']}")
print(f"Chunks: {result.get('chunks', 0)}")

db_conn.close()
```

## 🔄 Update-Workflow

### Code-Änderungen (Python)

```bash
# 1. Code bearbeiten
nano app/routers/my_feature.py

# 2. Nur App neu starten (schnell!)
docker compose restart app

# 3. Verifizieren
curl http://localhost:8000/health
```

### Dependencies (requirements.txt)

```bash
# 1. requirements.txt bearbeiten
nano app/requirements.txt

# 2. Neu bauen
docker compose up --build -d

# 3. Verifizieren
docker compose exec app pip list | grep new-package
```

### Docker-Compose Änderungen

```bash
# 1. docker-compose.yml bearbeiten
nano compose/docker-compose.yml

# 2. Services neu erstellen
docker compose up -d

# 3. Status prüfen
docker compose ps
```

### Neue .md Dateien

```bash
# 1. Datei hinzufügen
cp new_doc.md docs/crumbforest/

# 2. App neu starten (triggert Auto-Indexing)
docker compose restart app

# 3. Logs prüfen
docker compose logs app | grep "Document Indexing"

# 4. Verifizieren in Qdrant
curl http://localhost:6333/collections/docs_crumbforest_ | \
  jq '.result.points_count'
```

### Database Schema Änderungen

```bash
# 1. SQL Script erstellen
nano compose/init/99_my_migration.sql

# 2. Manuell ausführen (init/ läuft nur bei Erstellung!)
docker compose exec -T db sh -c \
  'mariadb -u$MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE' \
  < compose/init/99_my_migration.sql

# 3. Oder DB neu erstellen (⚠️ Löscht Daten!)
docker compose down -v
docker compose up -d
```

## 🛠️ Quick Reference

```bash
# Qdrant Dashboard (lokal)
open http://localhost:6333/dashboard

# Qdrant via SSH Tunnel
ssh -L 6333:localhost:6333 user@server

# Collections prüfen
curl http://localhost:6333/collections | jq '.result.collections[].name'

# Suche in Docs (braucht Session)
curl "http://localhost:8000/api/documents/search?q=docker" -H "Cookie: session=..."

# Status prüfen
curl http://localhost:8000/api/documents/status -H "Cookie: session=..."

# Force Re-Index
curl -X POST http://localhost:8000/api/documents/index \
  -H "Content-Type: application/json" \
  -H "Cookie: session=..." \
  -d '{"force": true}'

# App neu starten (Auto-Indexing)
docker compose restart app

# Rebuild (bei Code/Dependency Changes)
docker compose up --build -d

# Logs live verfolgen
docker compose logs app -f
```

## 🔒 Production Checklist

- [x] Qdrant nur auf localhost: `127.0.0.1:6333:6333`
- [ ] Nginx Reverse Proxy mit SSL
- [ ] Basic Auth für Qdrant Dashboard
- [ ] Firewall Rules (nur Port 80/443 offen)
- [ ] SSH Key-Based Auth (kein Password)
- [ ] Environment Variables sicher speichern
- [ ] Backup Cron Job einrichten
- [ ] Monitoring (Uptime, Disk Space)
- [ ] Log Rotation
- [ ] Rate Limiting für API

## 💡 Tipps

1. **Immer `restart` statt `up` wenn nur Code geändert**
   ```bash
   docker compose restart app  # Schnell
   # statt
   docker compose up --build   # Langsam
   ```

2. **File-Hash-Tracking nutzen**
   - Nur geänderte Dateien werden neu indexiert
   - Spart API-Kosten!

3. **SSH Tunnel für Remote Admin**
   - Sicherer als VPN
   - Keine Firewall-Änderungen nötig

4. **Logs sind deine Freunde**
   ```bash
   # Errors finden
   docker compose logs app | grep -i error
   
   # Indexing Status
   docker compose logs app | grep "Document Indexing" -A 20
   ```

5. **Session Cookie im Browser**
   - DevTools → Application → Cookies
   - Für API-Tests kopieren

---

**Wuuuuhuuu! Qdrant ist jetzt sicher! 🦉**
