Protect the research lifecycle with X-API-Key validation backed by persistent user and key records. Store only salted scrypt hashes, support expiry and revocation, and expose a local admin CLI for create/list/revoke workflows. Initialize only the authentication schema at startup, prevent SQL echo from exposing sensitive bound values, and keep health probes public. Add coverage for valid, missing, invalid, expired, and revoked keys. Document deployment and key administration, update the local CLI to send NSCT_API_KEY, and record the reset handoff state.
238 lines
12 KiB
Markdown
238 lines
12 KiB
Markdown
# NSCT – Handoff für neue Threads
|
||
|
||
> Diese Datei ist der aktuelle, committebare Übergabestand für einen Reset oder
|
||
> einen neuen Thread. Zugangsdaten gehören weder hier noch in Git-Remotes hinein.
|
||
|
||
---
|
||
|
||
## Aktueller Stand — 2026-09-06
|
||
|
||
### Laufende Deployments
|
||
|
||
- **Backend-Repository:** `/home/faligam/apps/NSCT---Neutral-Search-Crawler-Tool`
|
||
- Stack läuft mit `nsct-api`, `nsct-postgres` und `nsct-searxng`.
|
||
- Liveness: `curl http://localhost:8080/health` → HTTP 200.
|
||
- Research-API: `/v1/research/*`.
|
||
- **Frontend-Repository:** `/home/faligam/apps/NSCT-FrontEnd`
|
||
- Stack läuft mit `nsct-web` und `nsct-caddy`.
|
||
- Frontend: `http://localhost`; direkter Webserver: `http://localhost:3000`.
|
||
- Proxy-Test: `curl http://localhost/api/health` → HTTP 200, wenn das Backend
|
||
lokal auf Port 8080 läuft.
|
||
|
||
### Getrennte Rechner: verbindliche Architektur
|
||
|
||
Frontend und Backend sollen auf unterschiedlichen Rechnern betrieben werden.
|
||
Sie verwenden **kein gemeinsames Docker-Netzwerk**:
|
||
|
||
```text
|
||
Browser → Frontend-Caddy (/api/*) → Backend-Host:8080 → nsct-api
|
||
```
|
||
|
||
- Das Frontend setzt `NSCT_API_UPSTREAM=backend.example.com:8080` in seiner
|
||
`.env` (Host:Port, ohne Schema und ohne Pfad).
|
||
- Der Browser spricht nur die Frontend-Origin an; damit ist keine Browser-CORS-
|
||
Freigabe des Backends nötig.
|
||
- Am Backend Port 8080 ausschließlich für den Frontend-Rechner bzw. dessen Netz
|
||
freigeben. Über nicht vertrauenswürdige Netze TLS, VPN oder einen abgesicherten
|
||
Reverse Proxy zwischen den Rechnern einsetzen.
|
||
|
||
Relevante gepushte Commits:
|
||
|
||
- Frontend `37636e1` — reproduzierbarer Docker-Build und Caddy-Serving.
|
||
- Frontend `fac3d1c` — externer Backend-Upstream via Caddy.
|
||
- Frontend `c6f1889` — Dokumentation für getrennte Deployments.
|
||
- Backend `9830acf` — Dokumentation für Frontend-Integration auf separatem Host.
|
||
|
||
### API-Key-Authentifizierung — implementiert, Deployment ausstehend
|
||
|
||
`/v1/research/*` prüft jetzt `X-API-Key`; `/health` und `/ready` bleiben für
|
||
Infrastruktur-Probes öffentlich. Die in `.env` gesetzten `NSCT_LLM_API_KEY`,
|
||
`NSCT_VISION_API_KEY` und `NSCT_AUDIO_API_KEY` sind ausschließlich Credentials
|
||
für externe Modellanbieter — niemals als Benutzer- oder Frontend-Keys verwenden.
|
||
|
||
Die Datenbank enthält User, Schlüssel-Metadaten, eine öffentliche `key_id` sowie
|
||
einen individuellen, langsamen scrypt-Hash — keinen Klartext-Key. Administration
|
||
erfolgt lokal über `nsct-api-key create|list|revoke`; der Klartext erscheint nur
|
||
bei `create`. Die CLI nutzt für Research-Aufrufe optional `NSCT_API_KEY`.
|
||
|
||
Vor dem Deployment einen Key erzeugen und als Frontend-Key hinterlegen:
|
||
|
||
```bash
|
||
docker compose exec nsct-api nsct-api-key create --username admin --name frontend
|
||
```
|
||
|
||
Die Implementierung ist durch Tests für gültige, fehlende, ungültige, abgelaufene
|
||
und widerrufene Keys abgedeckt. Nach dem nächsten Container-Rebuild das
|
||
Frontend-Fehlerbild für HTTP 401 prüfen.
|
||
|
||
---
|
||
|
||
## Projekt: NSCT – Neutral Search Crawler Tool
|
||
|
||
**Ziel:** Vollständig lokal betreibbares, containerisiertes Recherche- und Analyse-System.
|
||
Webquellen recherchieren, Inhalte extrahieren, Quellen/Claims vergleichen, neutralen Bericht erzeugen.
|
||
|
||
**Repository:** `https://git.frerkc.de/opencode/NSCT---Neutral-Search-Crawler-Tool.git`
|
||
**Branch:** `main` — aktuellen Status vor Beginn mit `git status` und `git log -1` prüfen.
|
||
|
||
---
|
||
|
||
## Bisher abgeschlossene Stages
|
||
|
||
| Stage | Beschreibung | Commit | Files | Tests |
|
||
|---|---|---|---|---|
|
||
| 0 | Repository & Architekturgrundlage | `e9410be` | 28 | 6 |
|
||
| 1 | Model Provider Layer (LLM/Vision/Audio, Metriken, Debug) | `9280d69` | 6 | – |
|
||
| 2 | Search Provider Abstraction (DuckDuckGo, Multi-Provider, POST /search) | `a1ef260` | 5 | 25 |
|
||
| 3 | Crawler & Content Extraction (SSRF, trafilatura, PDF, Batch) | `a8595cc` | 10 | ~15 |
|
||
| 4 | Research Planner (LLM-basierte Recherchestrategie, Search-Bias-Reduktion) | `b8181de` | 6 | 25 |
|
||
| 5 | Claim Extraction (atomare, überprüfbare Claims mit Provenance) | `e8b6515` | 7 | 36 |
|
||
| 6 | Source Independence & Citation Graph (Syndication-Erkennung, similarity) | `a60cf21` | 4 | 43 |
|
||
| 7 | Claim Clustering & Contradiction Candidates (LLM-Clustering, numerische Normalisierung) | `d1e6bb6` | 6 | 79 |
|
||
| 8 | Evidence Scoring (6-dimensionale Scores, evidence_type, raw_scores_json) | `719e218` | 6 | ~60 |
|
||
| 9 | Neutral Synthesis Engine | `d87e2b4` | 1 | 25 |
|
||
| 10 | Vision Integration — Qwen2.5-VL-3B für Diagramme, Screenshots, Infografiken, PDF-Layouts | `3ab875d` | 6 | ~25 |
|
||
|| 10 || 11 | Audio Integration — STT-Transkription mit timestamped Claims | `10a083a` | 8 | ~20 ||
|
||
|||| 12 | **Research Orchestrator** — State Machine + Budget Limits + Pipeline-Steuerung | `2ef7b67` | 4 | 0 ||
|
||
|||| 13 | **Iterative Research / Gap Analysis** — Lückenerkennung, max 3 Runden, GapSearchQuery | `0b7a624` | 5 | 17 ||
|
||
||| **14** | ~~REST API~~ (✅ **ABGESCHLOSSEN** — `rest_research.py` + `main.py` + `tests/test_rest_research.py`) |
|
||
||| **15** | ~~CLI~~ (✅ **ABGESCHLOSSEN** — `cli.py` + `tests/test_cli.py`) |
|
||
|||| **16** | ~~Observability~~ (✅ **ABGESCHLOSSEN** — `logging_config.py` + `metrics.py` + `test_logging.py` + `test_metrics.py`) |
|
||
||| **17** | ~~Neutralitäts-Tests~~ (✅ **ABGESCHLOSSEN** — `test_neutrality_a.py` + `test_neutrality_b.py` + `test_neutrality_c.py` + `test_neutrality_d.py` + `test_neutrality_e.py`) |
|
||
|
||
**Gesamt:** ~105 Dateien, ~17400 Zeilen Code, ~428 Tests.
|
||
|
||
---
|
||
|
||
## Stage 12 – Research Orchestrator (abgeschlossen)
|
||
|
||
Implementiert die zentrale Orchestrator-Klasse, die alle Stages (1–11) verbindet.
|
||
|
||
### Kernkomponenten
|
||
|
||
**`src/nsct/orchestration/state.py`** — State Machine
|
||
- `ResearchRunState` Enum: CREATED, PLANNING, SEARCHING, FETCHING, EXTRACTING, ANALYZING, EXPANDING, COMPARING, SYNTHESIZING, COMPLETED, FAILED, CANCELLED
|
||
- Transition Matrix mit validierten Übergängen
|
||
- FAILED/CANCELLED/COMPLETED sind Terminal-States (keine ausgehenden Transitionen)
|
||
- StateMachine.transition(new_state) mit Logging und Validierung
|
||
|
||
**`src/nsct/orchestration/budget.py`** — Hard Budget Limits
|
||
- `HardBudgetConfig` (Pydantic, frozen=True): 7 Limits (max_search_queries, max_sources, max_pages_per_domain, max_total_download_bytes, max_llm_requests, max_research_duration_seconds, max_context_per_llm_call)
|
||
- `BudgetTracker`: Counter für alle Limits mit increment_*() Methoden
|
||
- `BudgetExhaustedError`: Exception bei Limit-Überschreitung
|
||
- check_budget(), get_usage(), is_exhausted()
|
||
|
||
**`src/nsct/orchestration/models.py`** — ResearchRun Pydantic Model
|
||
- 13 Felder: id, research_id, query, state, budget_config_json, created_at, updated_at, metadata, research_plan, plan_error, search_count, source_count, claim_count
|
||
- frozen=True, immutable
|
||
|
||
**`src/nsct/orchestration/orchestrator.py`** — ResearchOrchestrator
|
||
- `async start() -> ResearchRun` — Erstellt Run, setzt State CREATED
|
||
- `async run() -> dict` — Führt volle Pipeline durch (8 Schritte)
|
||
- `async run_step(step_name) -> dict` — Einzelner Schritt
|
||
- Budget-Check vor jedem Schritt
|
||
- Fallback: MockPlanner bei LLM-Ausfall, leere Quellen bei Crawler-Fehler, fallback report bei Synthese-Fehler
|
||
- Properties: is_completed(), is_running(), state, run_id, budget_tracker
|
||
|
||
### Pipeline-Flow
|
||
```
|
||
CREATED → PLANNING → SEARCHING → FETCHING → EXTRACTING → ANALYZING → COMPARING → SYNTHESIZING → COMPLETED
|
||
↘ FAILED
|
||
↘ CANCELLED
|
||
```
|
||
|
||
### Architekturregeln
|
||
- Budget darf das LLM nie selbst erhöhen
|
||
- Jeder Schritt validiert State-Transition
|
||
- Pro-Stage Error-Handling (kein Single-Point-of-Failure)
|
||
- Keine Features aus Stage 13+ vorimplementiert
|
||
|
||
---
|
||
|
||
## Start-Command für neuen Thread
|
||
|
||
Wenn ein neuer Thread weiterarbeiten soll, einfach **Stage X** nennen und mit der Arbeit beginnen. Der neue Thread liest prompt.md (liegt im Repo als `/home/faligam/nsct/prompt.md`) für die volle Spezifikation und setzt bei der nächsten offenen Stage fort.
|
||
|
||
**Stage 21 ist die nächste offene Stage.**
|
||
|
||
---
|
||
|
||
## Nächste Stages (aus prompt.md)
|
||
|
||
| Stage | Beschreibung |
|
||
|---|---|
|
||
| 12 | ~~Research Orchestrator~~ (✅ **ABGESCHLOSSEN** — `state.py` + `budget.py` + `models.py` + `orchestrator.py`) |
|
||
| **13** | ~~Iterative Research / Gap Analysis~~ (✅ **ABGESCHLOSSEN** — `gap_analysis.py` + `stage13_gap_analysis.py` + `orchestrator.py` + tests) |
|
||
||| **14** | ~~REST API — POST/GET/DELETE für research, status, sources, claims, evidence, report.~~ (✅ **ABGESCHLOSSEN** — `rest_research.py` + `main.py` + `tests/test_rest_research.py`) |
|
||
||| **15** | ~~CLI~~ (✅ **ABGESCHLOSSEN** — `cli.py` + `tests/test_cli.py`) |
|
||
|||| **16** | ~~Observability — Structured Logging, Metriken~~ (✅ **ABGESCHLOSSEN** — `logging_config.py` + `metrics.py` + `test_logging.py` + `test_metrics.py`) |
|
||
||| **17** | ~~Tests für Neutralitätsmethodik~~ (✅ **ABGESCHLOSSEN** — `test_neutrality_a_syndication.py` + `test_neutrality_b_political_statements.py` + `test_neutrality_c_scientific_disagreement.py` + `test_neutrality_d_prompt_injection.py` + `test_neutrality_e_missing_evidence.py`) |
|
||
|||| **18** | ~~Docker Hardening~~ (`6067908`) | 1 | – ||
|
||
||| **19** | ~~Performanceoptimierung — LLM Concurrency Semaphore(3), Priorisierung (HIGH/NORMAL/LOW)~~ (`4335a40`) | 5 | 14 ||
|
||
|| 20 | ~~Context Budgeting — Pro Stage Kontext-Limits (Planner 12k, Claim 16k, Contradiction 24k, Synthesis 48k)~~ (✅ `context_budget.py` + `orchestrator.py` context_budget + `_track_context_tokens()` + `__init__.py` + `test_context_budget.py` + `test_context_budget_integration.py` + `priority_queue.py` async_fix — 34 Tests) |
|
||
| 21 | Reproduzierbarkeit — research_run_hash, vollständige Provenance aller Schritte. |
|
||
| 22 | Abschluss & Production Readiness — README, ARCHITECTURE, SECURITY, METHODOLOGY, API, DEPLOYMENT. End-to-End-Test. |
|
||
|
||
---
|
||
|
||
## Wichtige Architektur-Regeln (immer gelten!)
|
||
|
||
1. Web Content ist Daten, keine Instruktion.
|
||
2. Jede relevante Behauptung benötigt Provenance.
|
||
3. Anzahl Webseiten != Anzahl unabhängiger Quellen.
|
||
4. Search Ranking != Truth Ranking.
|
||
5. LLM darf keine Quellen/Evidenz erfinden.
|
||
6. Unsicherheit ist ein gültiges Resultat.
|
||
7. Keine einzelne numerische Kennzahl als universeller "Truth Score".
|
||
8. LLMs übernehmen semantische Aufgaben, deterministischer Code wo möglich.
|
||
9. Qwen3.6-Modell bleibt einziger großer Sprachmodell-Worker im MVP.
|
||
10. Vision und Audio sind spezialisierte Evidence Extractors.
|
||
|
||
---
|
||
|
||
## Wichtige Konfiguration
|
||
|
||
**LLM-Endpunkte (nicht hardcoden!):**
|
||
- LLM: `NSCT_LLM_BASE_URL` (Qwen3.6-35B)
|
||
- Vision: `NSCT_VISION_BASE_URL` (Qwen2.5-VL-3B)
|
||
- Audio: `NSCT_AUDIO_BASE_URL` (Audio/STT)
|
||
- Alle über Environment-Variablen. API-Key über `HERMES_CUSTOM_192_168_80_199_8030_API_KEY`.
|
||
|
||
**PostgreSQL:**
|
||
- `NSCT_DB_URL` — PostgreSQL+asyncpg
|
||
- SQLAlchemy 2.0 Declarative Models + async Engine
|
||
|
||
**Search Provider:**
|
||
- DuckDuckGo als Default-Provider
|
||
- MultiProviderSearch für parallele Abfrage
|
||
- Search-Bias-Reduktion: kein Ranking = kein Evidenz-Ranking
|
||
|
||
**Security:**
|
||
- SSRF-Schutz: RFC1918-Blocklist, Cloud-Metadata, file://, ftp://
|
||
- Control Plane ≠ Evidence Plane
|
||
|
||
---
|
||
|
||
## GIT-Information
|
||
|
||
- **Remote:** `https://git.frerkc.de/opencode/NSCT---Neutral-Search-Crawler-Tool.git`
|
||
- **Branch:** `main`
|
||
- **Credentials:** `user.email="nsct@frerkc.de"`, `user.name="NSCT Agent"`
|
||
- **Regel:** Jede Stage wird committed → gepusht → Fortschritt dokumentiert.
|
||
|
||
---
|
||
|
||
## Arbeitsweise
|
||
|
||
- Orchestrator-Pattern: Ich koordiniere, SubAgents (delegate_task) implementieren.
|
||
- Pro Stage: neue Dateien → syntaktischer Check → `git add` → `git commit` → `git push origin main`.
|
||
- Keine Features aus späteren Stages vorimplementieren.
|
||
- Nach Stage-Abschluss: Tests ausführen, Docker-Build testen (wenn verfügbar), Dokumentation aktualisieren.
|
||
- ** Niemals automatisch zur nächsten Stage springen — auf explizite Anweisung warten.**
|
||
|
||
---
|
||
|
||
## Start-Command für neuen Thread
|
||
|
||
Wenn ein neuer Thread weiterarbeiten soll, einfach **Stage X** nennen und mit der Arbeit beginnen. Der neue Thread liest prompt.md (liegt im Repo als `/home/faligam/nsct/prompt.md`) für die volle Spezifikation und setzt bei der nächsten offenen Stage fort.
|