Replace Hetzner references with Coolify. Deployment is now:
- Core + Compliance: Push gitea → Coolify auto-deploys
- Lehrer: stays local on Mac Mini
Updated: CLAUDE.md, MkDocs CI/CD pipeline, MkDocs index.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaced bare imports with safe_import_router pattern — if one sub-router
fails to import (e.g. missing dependency), other routers still load.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
from __future__ import annotations breaks Pydantic BaseModel runtime type
evaluation. Replaced str | None → Optional[str], list[str] → List[str] etc.
in control_generator.py, anchor_finder.py, control_generator_routes.py.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds migration_runner.py that executes pending migrations from
migrations/ directory when backend-compliance starts. Tracks applied
migrations in _migration_history table.
Handles existing databases: detects if tables from migrations 001-045
already exist and seeds the history table accordingly, so only new
migrations (046+) are applied.
Skippable via SKIP_MIGRATIONS=true env var.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Migration 045: Seed 10 controls (AUTH, NET, SUP, LOG, WEB, DATA, CRYP, REL)
with 39 open-source anchors into the database
- Backend: POST/PUT/DELETE endpoints for canonical controls CRUD
- Frontend proxy: PUT and DELETE methods added to canonical route
- Frontend: Control Library with create/edit/delete UI, full form with
open anchor management, scope, requirements, evidence, test procedures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The backend mounts the compliance router at /api/compliance, so canonical
control endpoints are at /api/compliance/v1/canonical/*, not /api/v1/canonical/*.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add phase_security() with 15 documents across 3 sub-phases:
- J1: 7 NIST standards (SP 800-53, 800-218, 800-63, 800-207, 8259A/B, AI RMF)
- J2: 6 OWASP projects (Top 10, API Security, ASVS, MASVS, SAMM, Mobile Top 10)
- J3: 2 ENISA guides (Procurement Hospitals, Cloud Security SMEs)
All documents are commercially licensed (Public Domain / CC BY / CC BY-SA).
Wire up 'security' phase in dispatcher and workflow yaml.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
download_pdf() and extract_gesetz_html() now return 0 on failure and clean up
partial files. This prevents set -euo pipefail from aborting the entire script
when a single download fails (e.g. EUR-Lex timeout, BSI redirect).
Root cause of H2 EU loop only processing 1 document in Run #724: first failed
download_pdf returned 1, triggering set -e script abort.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
docker cp fails when target dir doesn't exist in a created container.
Copy scripts to /workspace_scripts, then cp them at container start.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The runner container can't access host paths directly, so the
deploy dir scripts were always stale. Now uses docker create +
docker cp + docker start to copy the freshly checked-out scripts
into the ingestion container before starting it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The RAG workflow mounts scripts from /opt/breakpilot-compliance/scripts
(deploy dir) but this may not have the latest fixes if CI hasn't
deployed yet. Add explicit git pull before running ingestion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- collection_count() returns 0 (not ?) on failure — fixes arithmetic error
- Pass QDRANT_API_KEY to ingestion container for dedup checks
- Include api-key header in collection_count() and dedup scroll queries
- Lower large-file threshold to 256KB (EGBGB 310KB was timing out)
- More targeted EGBGB XML extraction (Art. 246a + Anlage only)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical bug fix: mandatoryDocuments in Hard-Trigger-Rules used UPPERCASE
names (VVT, TOM, DSE) that never matched lowercase ScopeDocumentType keys
(vvt, tom, dsi). This meant no trigger documents were ever recognized as
mandatory in buildDocumentScope().
- Add normalizeDocType() mapping function with alias support
(DSE→dsi, LOESCHKONZEPT→lf, DSR_PROZESS→betroffenenrechte, etc.)
- Fix buildDocumentScope() to use normalized doc types
- Fix estimateEffort() to use lowercase keys matching ScopeDocumentType
- Add 2 tests for UPPERCASE normalization and alias resolution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extended timeout (15 min) for files > 500KB (BGB is 1.5MB)
- upload_file returns 0 even on failure so set -e doesn't kill script
- Failed uploads are still counted and reported in summary
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The gesetze phase failed because it expects text files created by the
download phase. Now the workflow automatically runs download first for
any phase that depends on it. Also adds git and python3 to the alpine
container for repo cloning and text extraction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- admin-compliance/Dockerfile: mkdir -p public before build
- developer-portal/Dockerfile: mkdir -p public before build
(fixes "failed to calculate checksum /app/public: not found")
- docker-compose.hetzner.yml: Override core-health-check to exit
immediately (Core doesn't run on Hetzner)
- Network override: external:false (auto-create breakpilot-network)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The runner container has Docker socket but no host filesystem access.
docker compose needs to read YAML files, so run build+deploy inside
a helper container that has both Docker socket and the deploy dir mounted.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Problems fixed:
1. Deploy step couldn't access /opt/breakpilot-compliance (host path not
mounted in runner container). Now uses alpine/git helper container with
host bind-mount for git ops, then docker compose with host paths.
2. breakpilot-network was external:true but Core doesn't run on Hetzner.
Override in hetzner.yml creates the network automatically.
3. core-health-check blocks startup waiting for Core. Override in
hetzner.yml makes it exit immediately.
4. RAG ingestion script now respects RAG_URL/QDRANT_URL env vars.
5. RAG workflow discovers network dynamically from running containers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Temporary commit to discover Docker container names and networks
on Hetzner, since breakpilot-network doesn't exist there.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of trying to connect the runner to breakpilot-network,
spawn a new alpine container directly on it via docker run.
Added debug output for network/container visibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Join breakpilot-network so bp-core-rag-service is reachable
- Make RAG_URL/QDRANT_URL in script respect env vars (${VAR:-default})
- Remove complex fallback logic — fail fast if network not available
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The runner container doesn't always have /opt/breakpilot-compliance mounted.
Use the git-cloned workspace (current dir) and add multi-fallback for RAG API
URL (container network → localhost → host.docker.internal).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase H now includes:
- 16 German laws (PAngV, VSBG, ProdHaftG, BDSG, HGB, AO, DDG, TKG, etc.)
- 15 EUR-Lex EU laws (DSGVO, Consumer Rights Dir, Sale of Goods Dir,
E-Commerce Dir, Unfair Terms Dir, DMA, NIS2, Product Liability Dir, etc.)
- 2 NIST frameworks (CSF 2.0, Privacy Framework 1.0)
- 1 HLEG Ethics Guidelines
Updated rag-sources.md with complete inventory of already-ingested vs
new documents, plus Layer 2-5 TODO roadmap.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Runner needs access to /opt/breakpilot-compliance and Docker network
for RAG service (bp-core-rag-service:8097). Falls back to
host.docker.internal if container network unavailable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Split HT-H01 into HT-H01a (B2C/Hybrid mit Verbraucherschutzpflichten) und
HT-H01b (reiner B2B mit Basis-Pflichten). B2B-Webshops bekommen keine
Widerrufsbelehrung/Preisangaben/Fernabsatz mehr.
- Add excludeWhen/requireWhen to HardTriggerRule for conditional trigger logic
- Register 6 neue ScopeDocumentType: widerrufsbelehrung, preisangaben,
fernabsatz_info, streitbeilegung, produktsicherheit, ai_act_doku
- Full DOCUMENT_SCOPE_MATRIX L1-L4 for all new types
- Align HardTriggerRule interface with actual engine field names
- Add Phase H (Verbraucherschutz) to RAG ingestion script:
10 deutsche Gesetze + 4 EU-Verordnungen + HLEG Ethics Guidelines
- Add scripts/rag-sources.md with license documentation
- 9 new tests for B2B/B2C trigger split, all 326 tests pass
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Type alignment (root cause of client-side crash):
- RiskFlag: id/title/description → severity/category/message/recommendation
- ScopeGap: id/title/recommendation/relatedDocuments → gapType/currentState/targetState/effort
- NextAction: id/priority:number/effortDays → actionType/priority:string/estimatedEffort
- ScopeReasoning: details → factors + impact
- TriggeredHardTrigger: {rule: HardTriggerRule} → flat fields (ruleId, description, etc.)
- All UI components updated to match engine output shape
Project isolation:
- Scope localStorage key now includes projectId (prevents data leak between projects)
Optional block progress:
- Blocks with only optional questions now show green checkmark when any question answered
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The auto-save timers (SDK context + backend) were firing after
completeAndSaveProfile(), resetting isComplete back to false.
Fix: skip auto-save when currentStep===99 (completed), cancel pending
timers before completing, and await backend save before updating
SDK context.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Profile data was lost when navigating away because it was only saved
to SDK context on explicit button click (Next/Save). Scope data
persisted because it auto-synced on every change.
Added two debounced auto-save mechanisms:
- SDK context sync (500ms) — survives in-app navigation
- Backend save (2s) — survives page reload/session change
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create reporting_handlers.go with ReportingHandlers struct and 4
endpoint methods (GetExecutiveReport, GetComplianceScore,
GetUpcomingDeadlines, GetRiskOverview) to fix build failure
- Fix gap_analysis/analyzer.py: use Optional[list[str]] instead of
list[str] | None for Python 3.9 compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Gitea Actions CI um deploy-hetzner Job erweitert
- Automatischer Build + Deploy bei Push auf main (nach Tests)
- docker-compose.hetzner.yml Override (amd64 statt arm64)
- Deploy-Dir: /opt/breakpilot-compliance/
- Baut parallel: admin, backend, ai-sdk, developer-portal
- Health Checks nach Deploy
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Profil: Summary-Seite (Step 99) nach Abschluss statt direkter Sprung zu Scope
- Profil: "Dokumente generieren" Block entfernt
- Use Cases Step 1: Branche aus Profil auto-abgeleitet, 21 KI-Kategorien als Kacheln
- Use Cases Step 2: ~60 Datenkategorien in 10 Gruppen als Kacheln (Art. 9 orange)
- Use Cases Step 3: Rechtsgrundlage entfernt (SDK ermittelt), 16 Zweck-Kacheln
- Use Cases Step 4: Automatisierungsgrad als Single-Select-Kacheln
- Use Cases Step 5: Hosting/Region/Modellnutzung als Kacheln statt Dropdowns
- Use Cases Step 6: Transfer-Ziele + Mechanismus als Kacheln statt Checkbox/Dropdown
- Use Cases Step 7: Aufbewahrungsdauer als Kacheln statt Zahlenfeld
- Use Cases Step 8: Compliance-Dokumente als Multi-Select-Kacheln
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The engine used short property names (risk, complexity, assurance, composite) while
the ComplianceScores interface defined (risk_score, complexity_score, assurance_need,
composite_score). Components used yet another convention (riskScore, level, hardTriggers).
The main crash was DEPTH_LEVEL_COLORS[decision.level] where decision.level was undefined
(correct property: decision.determinedLevel).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Step 2 im VVT-Generator: Ja/Nein-Buttons durch expandierbare Kacheln ersetzt.
Pro Abteilung werden typische Datenkategorien als Checkboxen angezeigt (isTypical
vorausgefuellt), Art. 9 Kategorien orange hervorgehoben mit DSGVO-Warnung.
7 neue Wiki-Artikel fuer Datenkategorien pro Geschaeftsbereich (HR, Finanzen,
Vertrieb, Marketing, Support, IT, Produktion).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>