feat(agent): add test frontend and Docker stack

This commit is contained in:
2026-09-16 21:42:05 +02:00
parent aa0bee340f
commit fc656188cf
16 changed files with 1065 additions and 71 deletions
+23
View File
@@ -21,6 +21,7 @@ Aufbewahrung. Ein allgemeiner API-Key allein reicht dafür nicht aus.
| Methode | Pfad | Auth | Zweck |
|---|---|---|---|
| `GET` | `/` | Eingabe im UI | Test-Frontend |
| `POST` | `/v1/ask` | Service-Key | belegte Wissensantwort |
| `GET` | `/v1/health` | öffentlich | Readiness ohne interne Hostdetails |
| `POST` | `/v1/reindex` | Admin-Key | Index nach KB-Änderung neu aufbauen |
@@ -28,6 +29,28 @@ Aufbewahrung. Ein allgemeiner API-Key allein reicht dafür nicht aus.
Die bisherigen Pfade `/ask`, `/health` und `/reindex` bleiben vorläufig als
`deprecated` Kompatibilitätsrouten erhalten und liefern denselben Vertrag.
## Test-Frontend
Das dependency-freie Frontend wird vom API-Prozess same-origin unter `/`
ausgeliefert. Dadurch sind keine CORS-Freigaben nötig. Es zeigt Dienststatus,
Antwort, zitierte Quellen, Quellenkonflikte, Rückfragen und technische
Grounding-Metadaten. Modellantworten werden nur als Text gerendert; HTML aus
einer Antwort wird nicht ausgeführt.
Für den vorgesehenen Tailscale-Host:
```bash
export PV_API_KEY='service-key-aus-secret-store'
python -m agent.cli serve --host 100.103.83.12
```
Danach ist die Oberfläche unter `http://100.103.83.12:8080/` erreichbar. Der
Service-Key wird vom Benutzer im Frontend eingegeben und niemals serverseitig
in HTML oder JavaScript eingebettet. Optional speichert ihn die Oberfläche nur
im `sessionStorage` des aktuellen Browser-Tabs; Chatverlauf und Fragen werden
nicht im Browser gespeichert. Außerhalb eines verschlüsselten Tailnets ist vor
den Dienst ein TLS-Reverse-Proxy zu setzen.
## Authentisierung
```bash
+130
View File
@@ -0,0 +1,130 @@
# Docker-Deployment auf `100.103.83.12`
Der Compose-Stack betreibt Test-Frontend und FastAPI-Agent gemeinsam. Er startet
keinen zweiten Ollama-Container, sondern verbindet sich mit dem vorhandenen
externen Docker-Netz `ollama-default`.
## Voraussetzungen
Auf dem Zielhost müssen vorhanden sein:
- Docker Engine mit Compose-Plugin;
- das externe Netz `ollama-default`;
- ein darin erreichbarer Ollama-Container;
- die Modelle `qwen3.8:27b` und `bge-m3` in dieser Ollama-Instanz;
- `wissensbasis/` und entweder ein vorhandenes `data/index.db` oder genügend
Zeit für den initialen Indexaufbau.
Das Netz und seine Container/Aliase prüfen:
```bash
docker network inspect ollama-default
```
Der Compose-Beispielwert nimmt den DNS-Namen `ollama` und den internen
Ollama-Port `11434` an. Das ist **nicht lokal verifiziert**, weil das Netz nur
auf dem Zielhost existiert. Falls der Container im Netz anders heißt, muss
`OLLAMA_URL` in `.env` entsprechend gesetzt werden, beispielsweise:
```text
OLLAMA_URL=http://tatsaechlicher-containername:11434
```
Die veröffentlichte Host-Portnummer `11435` ist innerhalb des gemeinsamen
Docker-Netzes normalerweise nicht relevant; Container sprechen den internen
Port des Ollama-Containers an.
## Konfiguration
```bash
cp .env.example .env
```
Dann `.env` anpassen:
1. `PV_API_KEY` durch einen starken zufälligen Wert ersetzen;
2. optional einen getrennten `PV_ADMIN_API_KEY` setzen;
3. `OLLAMA_URL` anhand des Netzwerk-Alias prüfen;
4. `PUID`/`PGID` auf den Besitzer von `data/` setzen.
`.env` ist gitignored und darf nicht committed werden. Compose verwendet die
Datei nur zur Interpolation der ausdrücklich in `compose.yaml` aufgelisteten
Variablen; sonstige lokale Secrets werden nicht pauschal in den Container
durchgereicht.
## Start mit vorhandenem Index
```bash
docker compose build
docker compose up -d
docker compose ps
docker compose logs --follow pv-agent
```
Aufruf im Tailscale-Netz:
```text
http://100.103.83.12:8080/
```
Im Frontend denselben Wert wie `PV_API_KEY` als Service-Key eingeben.
## Initialen Index im Container bauen
Falls `data/index.db` auf dem Zielhost noch fehlt:
```bash
mkdir -p data
docker compose run --rm pv-agent python -m agent.cli ingest
```
Der Lauf verwendet `bge-m3` über `OLLAMA_URL` und schreibt den Index in das
Bind-Mount `./data`. Danach den Dienst starten:
```bash
docker compose up -d
```
Der Prozess läuft als `PUID:PGID`. `data/` muss für diese IDs schreibbar sein,
insbesondere wenn `/v1/reindex` verwendet werden soll.
## Smoke-Tests
```bash
curl --fail http://100.103.83.12:8080/v1/health
curl --fail \
-H 'Authorization: Bearer <PV_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{"question":"Wie hoch ist der steuerfreie Tagesgeldsatz?","mode":"knowledge"}' \
http://100.103.83.12:8080/v1/ask
```
`/v1/health` muss `"status":"ok"` liefern. Ein Status `degraded` bedeutet in
der Regel, dass der Index fehlt oder Ollama unter dem konfigurierten
Container-DNS-Namen nicht erreichbar ist.
## Sicherheitsprofil
- Port `8080` wird nur an die Tailscale-Adresse `100.103.83.12` gebunden.
- `PV_API_KEY` ist für den Compose-Start verpflichtend.
- Root-Dateisystem ist read-only; nur `./data` ist schreibbar.
- Alle Linux-Capabilities werden entfernt; `no-new-privileges` ist aktiv.
- `wissensbasis/` wird read-only eingebunden.
- Frontend und API sind same-origin; es ist keine CORS-Freigabe nötig.
- Außerhalb des verschlüsselten Tailnets ist TLS vor dem Dienst erforderlich.
## Aktualisierung
```bash
git pull
docker compose build --pull
docker compose up -d
docker image prune
```
Nach Änderungen an der Wissensbasis:
```bash
docker compose run --rm pv-agent python -m agent.cli ingest
docker compose up -d
```