spec(#124): printers.yaml weg, Drucker in DB + /admin/printers Admin-UI [DRAFT]#125
spec(#124): printers.yaml weg, Drucker in DB + /admin/printers Admin-UI [DRAFT]#125strausmann wants to merge 8 commits into
Conversation
Draft-Spec fuer Hub #124 nach Brainstorming-Session mit User am 2026-06-14. Erfasst die finalen User-Entscheidungen: - KEIN env bootstrap, nur Admin-UI (User hat HUB_PRINTERS_JSON explizit verworfen). - ID-Pattern: derive_printer_id erweitert um created_at fuer Kollisionsfreiheit bei IP-Wechsel/Re-Provisionierung. - Bestandsdrucker behalten ihre alten UUIDs (created_at war damals nicht im Salt) — keine Daten-Migration noetig. - UI-Edit nur fuer name/connection/enabled — slug/model/backend/id bleiben immutable nach Create. - Plugin-Architektur unangetastet, nur Drucker-Instanzen wandern. - printers_audit-Tabelle analog Hangar layouts_audit. - Hangar konsumiert weiter GET /api/printers — kein Hangar-Change. Closes-Spec-of #124 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a design specification for transitioning the printer management system from a file-based configuration to a database-driven model. By removing the dependency on 'printers.yaml' and implementing a dedicated Admin UI, the system gains more flexibility and improved management capabilities for printer instances. The changes focus on streamlining the operational workflow while maintaining compatibility with existing Hangar services. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a design specification for migrating printer configurations from printers.yaml to a database-backed system with a dedicated Admin UI. The review feedback highlights privacy violations in the document, specifically the use of real domains (print-hub.strausmann.cloud and hangar.strausmann.cloud) in the smoke-test section, which should be replaced with neutral placeholders like example.com to comply with the repository's privacy guidelines.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
|
||
| 1. PR merge → CI green | ||
| 2. Dockhand: `down_stack(hangar-print-hub)` → Volume-Mount `printers.yaml` entfernen via `update_stack_compose` → `start_stack` | ||
| 3. Browser: `https://print-hub.strausmann.cloud/admin/printers` → Liste der 2 Bestandsdrucker |
There was a problem hiding this comment.
Gemäß den Datenschutzrichtlinien des Repositories (Priorität 1) und den allgemeinen Regeln dürfen keine echten Hostnamen, Domains oder LAN-IPs in der Dokumentation oder im Code verwendet werden. Bitte ersetzen Sie print-hub.strausmann.cloud durch eine neutrale Dokumentations-Domain wie print-hub.example.com.
Vorschlag:
3. Browser: https://print-hub.example.com/admin/printers` → Liste der 2 Bestandsdrucker`
References
- Datenschutzverletzungen. Markieren Sie alle fest einprogrammierten LAN-IPs, echten Hostnamen, echten Domains, echten Token oder personenbezogenen Daten (PII). Das Netzwerk des Maintainers darf aus diesem Repository nicht ableitbar sein. (link)
- Use RFC 5737 documentation IPs and 'example.com' placeholders instead of real LAN IPs, hostnames, or domains in documentation and code to maintain privacy.
| 3. Browser: `https://print-hub.strausmann.cloud/admin/printers` → Liste der 2 Bestandsdrucker | ||
| 4. Edit `brother-p750w` → ändere Hostname testweise auf `192.0.2.1` → Save → Reload → Wert übernommen | ||
| 5. Edit zurück auf echten Hostnamen | ||
| 6. Hangar `/admin/layouts/` → unverändert, `https://hangar.strausmann.cloud/` Print-Buttons funktionieren |
There was a problem hiding this comment.
Gemäß den Datenschutzrichtlinien des Repositories (Priorität 1) und den allgemeinen Regeln dürfen keine echten Hostnamen, Domains oder LAN-IPs in der Dokumentation oder im Code verwendet werden. Bitte ersetzen Sie hangar.strausmann.cloud durch eine neutrale Dokumentations-Domain wie hangar.example.com.
Vorschlag:
6. Hangar /admin/layouts/→ unverändert,https://hangar.example.com/` Print-Buttons funktionieren`
References
- Datenschutzverletzungen. Markieren Sie alle fest einprogrammierten LAN-IPs, echten Hostnamen, echten Domains, echten Token oder personenbezogenen Daten (PII). Das Netzwerk des Maintainers darf aus diesem Repository nicht ableitbar sein. (link)
- Use RFC 5737 documentation IPs and 'example.com' placeholders instead of real LAN IPs, hostnames, or domains in documentation and code to maintain privacy.
Spec-Review: network-TeamStatus: NEEDS_FIXES FindingsCRITICALC1 — Pangolin Remote-User Header: exakter Name fehlt im Spec Spec sagt Aktion: Pangolin-Dashboard → Org → Einstellungen → Header-Name notieren und im Spec exakt benennen. Wahrscheinlich C2 — JSON-API hinter Pangolin SSO oder nicht? Spec listet JSON-API ( Wenn die JSON-API hinter derselben Pangolin-Resource wie die HTML-UI läuft: Tooling und Ansible-Aufrufe kommen nicht durch ohne den Header-Auth-Bypass ( Explizit klären: Laufen HTML-UI und JSON-API auf derselben Pangolin-Resource? Wenn ja: Header-Auth-Bypass ist Pflicht und braucht einen eigenen Schritt im Plan (Blueprint-Label + Vaultwarden-Item). HIGHH1 — CSRF-Schutz für HTML-Form-POSTs fehlt im Spec Spec definiert Aktion: CSRF-Token-Mechanismus (z.B. H2 — Pangolin-Resource-Standard: Bestandsresource braucht Header-Auth-Bypass-Update Die Resource Aktion: Prüfen ob die Bestandsresource bereits MEDIUMM1 — LAN-Routing Hub → Drucker: Spec macht keine Aussage Drucker liegen im LAN ( Aktion: Bestätigen dass hhdocker02/03 → Drucker-VLAN geroutet ist (UniFi-Firewall-Regel). Falls nicht, braucht der Hub ein zweites Netzwerk oder eine Host-Route. Kein neues VLAN nötig, aber die Annahme muss explizit im Spec stehen. M2 — Hangar → Hub-Kommunikation: Domain oder intern? Spec sagt Hangar Aktion: URL für Hangar→Hub-Aufruf im Spec explizit benennen. LOWL1 — Healthcheck-Path für bestehende Pangolin-Resource prüfen Spec entfernt den Volume-Mount |
Spec-Review: ops-TeamStatus: NEEDS_FIXES FindingsHIGH (sollte fixed werden)1. Env-Var-Entfernung: Merge-Pflicht nicht adressiert Abschnitt "Migration für Bestand, Phase 2" sagt: «printers.yaml Volume-Mount entfernen» und «PRINTER_CONFIG_PATH Env-Variable entfernen». Die Spec beschreibt nur das Entfernen aus dem Compose-Block, nicht den notwendigen Stack-Env-Update-Pfad. Problem: Korrekter Migrations-Pfad muss explizit in der Spec stehen: Hinweis: 2. Pre-Deploy-DB-Snapshot fehlt Abschnitt «Migration für Bestand» sagt «Snapshot DB-Inhalt sichern» ohne konkreten Befehl. Bei einem Fresh-Deploy auf leerer DB (z.B. nach versehentlichem Empfehlung: Konkrete Pre-Deploy-Anweisung ergänzen, z.B.: docker exec hangar-print-hub-db-1 pg_dump -U hub hub -t printers > printers-backup.sqlAlternativ: Explizit festhalten, dass das PBS-Tagesbackup als Rollback ausreicht (wenn das stimmt). MEDIUM (Discussion)3. Watchtower-Timing während Migration Der Smoke-Test-Pfad (Abschnitt «Smoke-Test Production», Schritt 2) lässt Watchtower aktiv. Watchtower auf hhdocker03 läuft mit Scope Optionen: Watchtower kurz pausieren während Migration, oder klarstellen warum das Fenster unkritisch ist. 4. Health-Endpoints nicht adressiert Die Spec führt Admin-UI-Routen mit DB-Operationen ein, nennt aber keinen Health-Endpoint für Uptime-Kuma/Prometheus-Alerting bei 500-Fehlern oder DB-Verbindungsabbruch im laufenden Betrieb. Nicht blockierend für #124, aber als Follow-up-Issue empfohlen. 5. Audit-Tabelle: Retention-Strategie fehlt Abschnitt «Audit-Tabelle printers_audit» hat LOW / Suggestions6. Compose-Validation-Reihenfolge Dockhand validiert beim Was gut ist
|
Spec-Review: storage-TeamStatus: NEEDS_FIXES FindingsCRITICAL[C1] JSONB in SQLite existiert nicht Sowohl Aktion: Spec-Kommentar in Schema-Abschnitt ergänzen: "SQLite speichert JSONB als TEXT, keine JSON-Constraints". Alembic-Migration entsprechend mit HIGH[H1] Credentials in Der Delete-Flow speichert Aktion: Spec muss entscheiden: (a) [H2] Update- und Delete-Flow zeigen Aktion: Spec muss beschreiben wie Concurrent-Write-Protection tatsächlich implementiert wird: MEDIUM[M1] Pre-Deploy-Snapshot nicht spezifiziert Spec sagt "Snapshot DB-Inhalt sichern" (Phase 1) ohne konkreten Mechanismus. PBS-Snapshot der VM läuft regulär, aber der Zeitpunkt ist nicht garantiert frisch. Empfehlung: Expliziten [M2] Transaktions-Atomicity nicht explizit dokumentiert Spec zeigt Create/Update/Delete-Flows mit implicit LOW[L1] Indexe bei <1000 Rows redundant aber harmlos Zwei Indexe auf storage-team review — 2026-06-14 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #125 +/- ##
=======================================
Coverage 89.30% 89.30%
=======================================
Files 91 91
Lines 4263 4263
Branches 368 368
=======================================
Hits 3807 3807
Misses 358 358
Partials 98 98
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
Spec-Review: code-quality / ArchitekturStatus: NEEDS_FIXES FindingsCRITICALC1 — Die Spec erweitert die Signatur auf Die Spec behandelt das als "Bestandsdrucker behalten ihre alte UUID — Migration berechnet sie NICHT neu" — macht aber keine Aussage darüber, wann/wo die 4-arg-Variante statt der 3-arg-Variante aufgerufen wird. Wird Pflicht: Spec muss explizit benennen: "Die bestehende 3-arg-Funktion wird durch eine überlastete/neue 4-arg-Variante ersetzt; alle Test-Aufruf-Stellen in C2 — FK-Kaskade: DELETE blockiert oder zerstört Job-History
Die Spec adressiert das im Delete-Flow nicht — sie schreibt nur "Operator-Verantwortung" für Hangar-Layouts (Abschnitt "Implikation für Hangar"). Auch Pflicht: Spec muss entscheiden: (a) Soft-Delete ( HIGHH1 — Pydantic-Schemas undefiniert Spec nennt
Pflicht: Spec ergänzen mit zumindest den Validator-Regeln und dem Update-Subset. Implementer soll keine Schema-Entscheidungen treffen müssen. H2 — Immutable Fields: Service-seitige Durchsetzung fehlt Abschnitt "Update-Flow" Step 5c: Bei der JSON-API ( Pflicht: Ein Satz in "Komponenten → PrinterAdminService": "Felder MEDIUMM1 — Test-Coverage-Schwellen fehlen (test-coverage-pflicht.md) Spec listet Test-Kategorien, aber keine Coverage-Schwellen. Laut Aktuell fehlt in der Test-Sektion: (a) DB-Error-Pfad (z.B. Session rollback bei IntegrityError), (b) Network/Timeout-Pfad für den Audit-Write (was wenn printers_audit INSERT fehlschlägt — rolled back der gesamte Printer-Write?). Die Spec muss diese Szenarien explizit benennen. M2 — Spec Abschnitt Create-Flow Step 5a: Pflicht: Spec muss schreiben: M3 — Plugin-Registry-Kopplung nicht diskutiert Spec Abschnitt 4: "Quelle: Alternative (robuster): Jedes Backend-Plugin exportiert selbst eine LOWL1 — Audit-Tabelle: kein FK auf
L2 — i18n-Politik Spec Abschnitt "Out of Scope": "Mehrsprachigkeit der Admin-UI (deutsch only)" — gut. Spec sollte ergänzen ob Error-Messages aus Pydantic (422 responses) ebenfalls auf Deutsch übersetzt werden oder englisch bleiben. Aktuell unklar für Implementer. Was gut ist
|
…6 HIGH + 6 MED + LOW)
Folgendes wurde im Spec aus den Reviews der 4 Fachteams eingearbeitet:
CRITICAL
- C1 Pangolin Remote-User Header: Sektion "Authentifizierung" mit
exakten Header-Namen (Remote-User, X-Pangolin-Token, Legacy
X-Pangolin-User) aus app/auth/dependencies.py.
- C2 JSON-API Auth-Pfad: hinter selber Pangolin-Resource wie
HTML-UI (User-Entscheidung). Header-Auth-Bypass via Compose-Label
fuer claude-automation.
- C3 SQLite-only, sa.JSON() statt JSONB: Hub-DB ist
sqlite+aiosqlite:////data/printer-hub.db. Dialect-Matrix entfaellt.
- C4 derive_printer_id 4-arg: kein Backwards-Compat (lifespan-Aufrufer
wird komplett entfernt, 3 Test-Files migriert/geloescht).
- C5 DELETE-Strategie: Soft-Delete via enabled=false (User-Entscheidung).
FK-Constraints zu jobs/print_batches/presets/printer_state bleiben
intakt. UI-Aktionen sind disable/enable statt delete.
HIGH
- H1 env-merge-Pflicht: PRINTER_CONFIG_PATH entfernen via
get_stack_env + filter + update_stack_env (PUT-Replace-Semantik).
- H2 down_stack+start_stack statt restart_stack (Volume-Mount-Change).
- H3 CSRF-Schutz: Starlette-CSRF Middleware fuer alle HTML-Form-POSTs,
SameSite=Strict Cookie. JSON-API CSRF-frei mit Basic-Auth/API-Key.
- H4 SNMP-Community im Audit redacted via redact_secrets-Helper.
- H5 SELECT FOR UPDATE → BEGIN IMMEDIATE (SQLite-konform).
- H6 PrinterCreatePayload/UpdatePayload mit allen Feldern + Validatoren
(slug-regex, port-range, snmp-cross-field-validation, deutsche
Error-Messages).
MEDIUM
- M1 sqlite3 .backup vor Deploy (statt pg_dump).
- M2 Immutable-Fields silent ignore (analog Hangar).
- M3 Coverage-Schwellen pro Modul (85% Mutation, 75% Helper).
- M4 created_at_utc Pflicht timezone-aware (naive → ValueError).
- M5 Plugin-Registry-Kopplung als akzeptiertes Risiko markiert.
- M6 async with session.begin() fuer atomare Transaktionen.
LOW
- Watchtower-Pause via set_container_auto_update("never") vor Migration.
- Healthcheck-Verifikation post-Deploy.
- Audit-Retention dokumentiert (keine).
- LAN-Routing als Annahme dokumentiert.
- Hangar→Hub URL: http://print-hub:8000 intern via Container-Netz.
- FK auf printers_audit.printer_id bewusst weggelassen (Soft-Delete
behaelt Parent-Row sowieso).
- i18n: deutsch only.
Refs #124
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Round-2 Spec-Review: ops-TeamStatus: APPROVE (mit einem LOW-Hinweis) Round-1 Findings — Verifikation
Neue Round-2 FindingsLOW — down_stack-Fehlerbehandlung nicht spezifiziertSpec sagt LOW — CSRF und
|
Round-2 Spec-Review: network-TeamStatus: NEEDS_FIXES (1 HIGH, 1 MED, 2 LOW — aber alle klar lösbar, kein Architektur-Problem) Round-1 Findings — Verifikation
Neue Round-2 Findings[HIGH] N1: Healthcheck-Labels fehlen im Spec-Blueprint-Beispiel Spec zeigt Blueprint-Labels in Sektion "Authentifizierung" ohne den Healthcheck-Block. Fix: Blueprint-Beispiel in Sektion "Authentifizierung" um den Healthcheck-Block erweitern (Container-Name [MED] N2: Hangar→Hub Container-DNS-Name nicht verifiziert Spec sagt [LOW] N3: Spec definiert [LOW] N4: Bekannter Pangolin-Bug #3099 nicht erwähnt Mit Was gut ist
Pflicht vor Merge: N1 (Healthcheck-Labels) in Blueprint-Beispiel ergänzen. N2 als Verifikationsschritt in Phase-3-Smoke aufnehmen. N3 + N4 als Kommentar oder Risiko-Tabelleneintrag — kein Blocking. |
Round-2 Spec-Review: storage-TeamStatus: NEEDS_FIXES (1 HIGH neu, 1 MED neu, Rest APPROVE) Round-1 Findings — Verifikation
Neue Round-2 FindingsHIGH — H4-B: SNMP-Schema-Inkompatibilität (flach vs. verschachtelt)Problem: Die neue Das führt zu zwei Problemen:
Fix: Spec muss explizit definieren: (a) was genau in MED — M7:
|
Round-2 Spec-Review: code-qualityStatus: NEEDS_FIXES (2 Medium, 1 High — kein neues CRITICAL) Round-1 Findings — Verifikation
Neue Round-2 FindingsHIGHH-NEW-1: Beide Dateien importieren MEDIUMM-NEW-1: C5 — Der Spec-Satz "PrintRequest mit UUID eines disabled Druckers schlägt mit M-NEW-2: Spec sagt "Helper LOWL-NEW-1: CSRF-Test-Strategie zu vage
L-NEW-2: Trailing-Slash-Konvention für JSON-API nicht festgelegt 6 neue Was gut ist
Blockierend vor Umsetzung: H-NEW-1 (CI bricht sonst beim Merge) und M-NEW-1 (fehlendes Akzeptanzkriterium für disabled-Printer-Check). |
…D + 4 LOW) Round-2 Reviews: ops APPROVE, network/storage/code-quality NEEDS_FIXES. Folgendes wurde eingearbeitet: HIGH - H7 (network) Healthcheck-Labels im Blueprint-Snippet vollstaendig gemaess pangolin-resource-standard.md (alle Pflichtfelder seit Newt v1.18.4: name, full-domain, protocol, ssl, target+healthcheck, auth.sso-enabled, auth.basic-auth) plus Vault-Item-Konvention. - H8a (storage) SNMP-Schema verschachtelt (snmp.discover, snmp.community) statt flach — konsistent mit altem YAML (User-Entscheidung). - H8b (storage) Alembic-Backfill-Migration fuer Bestand-Drucker: queue_timeout_s + cut_defaults_half_cut als neue Spalten, plus connection.snmp Backfill mit Defaults fuer Rows ohne SNMP-Block. Phase 1b in Migration-Sektion. - H9 (code-q) 2 weitere Test-Files in C4-Liste: test_lifespan_seeds_and_upserts.py + test_lifespan_printer_upsert.py beide komplett geloescht. Verifikations-Greps im Akzeptanzkriterium. MEDIUM - M7 (storage) BEGIN IMMEDIATE Konflikt geloest: aiosqlite-Engine mit isolation_level="SERIALIZABLE" + Connect-Listener fuer journal_mode=WAL und foreign_keys=ON. session.begin() startet dann automatisch im IMMEDIATE-Modus. Kein manuelles BEGIN IMMEDIATE noetig. - M8 (code-q) PrintService.submit_print_job enabled-Check: neue PrinterDisabledError-Exception (HTTP 409), Code-Snippet + 2 Test-Cases im Spec. - M9 (code-q) redact_secrets in eigenem Modul app/services/audit_redaction.py mit SECRET_PATHS-Set, 80% Coverage, 4 Edge-Case-Tests (None, Bestandsdrucker ohne SNMP, etc.). - M10 (network) Container-DNS-Name `print-hub` Live-Verifikation als erster Schritt in Phase-3-Smoke. LOW - Pangolin-Resource-Standard + Vault-Item-Naming verlinkt. - Pangolin Bug #3099 (Basic-Auth-Dialog statt SSO-Redirect) als bekanntes Phaenomen in Risiken-Tabelle (R8) — nicht als Bug reporten. - CSRF-Test-Strategie konkret in 4 Faellen (Cookie+Token Match/Miss/ Wrong, Authorization-Header skipped). - Trailing-Slash-Konvention: ohne (FastAPI-Standard), konsistent mit existing Hub-Endpoints. Akzeptanzkriterien-Liste auf 18 Punkte erweitert (5 neue: Backfill-Verifikation, PrintService-enabled-Check, redact_secrets-Modul, SQLite-Engine-Setup, Container-DNS-Verifikation). Refs #124 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Round-3 Spec-Review: ops-TeamStatus: APPROVE Round-2 (APPROVE) bestätigt?Ja. Alle bisherigen APPROVE-Grundlagen (H1 env-merge-Pflicht, H2 down/start, Blueprint-Labels, Snapshot-Befehl, Watchtower-Pause) sind in Round-3 unverändert korrekt. Keine der neuen Bausteine zieht das Round-2-OK in Zweifel. Neue Round-3 FindingsLOW: WAL-Pragma + Backup-Artefakte (.wal/.shm)Der Connect-Listener in Einzige Lücke: Phase 1a sichert explizit LOW: Alembic-down für Phase-1b fehlt im Rollback-PfadDer Rollback-Pfad beschreibt SQLite-Restore + Compose-Revert. Das reicht in der Praxis (DB wird zurückgespielt, Alembic-Version-Tabelle kommt mit). Formal fehlt aber ein LOW: Container-DNS-Smoke-Schritt ist fragil bei abweichendem Compose-Service-Name
LOW: PrinterDisabledError → 409 (API-Contract-Änderung)
Was gut ist
ops-Team APPROVE — alle Findings sind LOW und non-blocking. |
Round-3 Spec-Review: network-TeamStatus: APPROVE Round-2 Findings — Verifikation
Neue Round-3 FindingsKeine. Die Backfill- und PrintService-Änderungen (H8b, M8) haben keine neuen Pangolin- oder Netzwerk-Implikationen. Hangar→Hub-Routing bleibt intern via Container-Netz — Pangolin-Resource nicht betroffen. Was gut ist
|
Round-3 Spec-Review: storage-TeamStatus: APPROVE (mit einem dokumentierten LOW-Finding) Round-2 Findings — Verifikation
Neue Round-3 FindingsLOW — Backfill Edge-Case: connection IS NULL Der Backfill-Code schreibt bei conn_json = row.connection or {}
if "snmp" not in conn_json:
conn_json["snmp"] = {"discover": False, "community": "public"}
conn.execute(... .values(connection=conn_json))NULL-connection ist im Schema erlaubt ( if not conn_json or "host" not in conn_json:
# skip + log — connection ohne host macht keinen Sinn
continueAlternativ reicht ein Kommentar: "Invariante: connection enthält immer host+port (upsert_runtime_printers-Garantie) — skip wenn NULL". LOW — Kein Downgrade-Pfad dokumentiert Spec enthält keinen Was gut ist
Die beiden LOW-Findings blockieren nicht — APPROVE. storage-agent, Round-3 |
Round-3 Spec-Review: code-qualityStatus: NEEDS_FIXES (2 neue Medium-Findings) Round-2 Findings — Verifikation
Neue Round-3 Findings[MEDIUM] M11 — Spec definiert: class PrinterDisabledError(LabelHubException):
http_status = 409Live-Check: Der Implementer steht vor der Wahl: Fix: Spec ergänzt [MEDIUM] M12 — Create-Flow Step 5c: row_dict = payload.model_dump() + {"id": printer_id, "created_at": ..., "updated_at": ...}
# INSERT INTO printers (...)
Der Implementer muss manuell flatten: row_dict["queue_timeout_s"] = payload.queue.timeout_s
row_dict["cut_defaults_half_cut"] = payload.cut_defaults.half_cut
row_dict.pop("queue")
row_dict.pop("cut_defaults")Das ist nicht trivial und fehleranfällig (besonders beim [LOW] Engine-Snippet Reihenfolge (Lesbarkeit) M7-Snippet zeigt Außerdem: Live Was gut ist
|
… 1 LOW) Round-3 Reviews: ops/network/storage APPROVE, nur code-quality NEEDS_FIXES mit 2 MED + 1 LOW. Eingearbeitet: - M11 LabelHubException existiert nicht: PrinterDisabledError leitet von der existierenden PrinterError-Basisklasse in app/printer_backends/exceptions.py ab. Konstruktor mit printer_id+slug. Error-Handler analog TapeMismatchError-Pattern in api/routes/print.py. Mapping 409 statt 404 da Drucker semantisch existiert. - M12 model_dump-Flattening: 3 explizite Helper-Funktionen mit Code-Snippets im Spec: - _payload_to_row(payload, id, ts): Pydantic → flache DB-row - _apply_update_patch(row, patch): nur changed Spalten zurueck - _row_to_audit_view(row): flach → verschachtelt fuer Audit-JSON Tests fuer alle 3 Helper benannt. Create-Flow + Update-Flow konsistent auf die Helper umgestellt. - LOW Engine-Snippet Reihenfolge: Snippet als Pseudo-Code markiert, korrekte Reihenfolge (create_async_engine VOR @event.listens_for). Delta-Hinweis was an engine.py NEU vs EXISTING ist. Refs #124 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Round-4 Spec-Review: code-qualityStatus: APPROVE Round-3 Findings — Verifikation
Neues Finding — R4a:
|
Basiert auf Spec Round-4 final (Commit 613bb97) — alle 4 Teams APPROVE. Phasen: - 0: Live-Check (Pangolin, DB-Schema, Test-Inventar) - 1: Foundation (Engine SERIALIZABLE+WAL, PrinterDisabledError, Alembic-Migration mit Backfill, derive_printer_id 4-arg) - 2: Service-Layer (Pydantic-Schemas, audit_redaction, Plugin-Registry, PrinterAdminService mit Flattening-Helper + CRUD) - 3: API + Web-Routes + CSRF-Middleware - 4: PrintService enabled-Check + 409-Mapping - 5: Removal (PrinterConfigLoader, 5 Test-Files, lifespan-Aufrufer) - 6: Pangolin-Resource-Standard (Vault-Item + Blueprint-Labels) - 7: Fresh-Install E2E-Test - 8: Production-Deploy (DB-Snapshot, Watchtower-Pause, Stack-Env-Merge, down/start, Smoke) Self-Review-Tabelle deckt alle Spec-Sektionen ab. Coverage-Schwellen pro Modul explizit (85% Mutation-Logic, 75% Helper). Refs #124 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Plan-Review Round-1: storage-TeamStatus: NEEDS_FIXES (2 Medium, 2 Low) FindingsMEDIUM — Task 1.1: isolation_level="SERIALIZABLE" mappt nicht zuverlässig auf aiosqliteDas Plan-Snippet setzt MEDIUM — Task 1.3:
|
Plan-Review Round-1: ops-TeamStatus: NEEDS_FIXES FindingsHIGHH1 — Parameter-Name-Bug Task 8.2: Fix: H2 — Rollback-Pfad fehlt komplett Minimaler Rollback-Step nach 8.3:
Ohne diesen Pfad ist kein sicheres Abbrechen möglich. MEDIUMM1 — Phase 0: Volume-Mount-Check fehlt mcp__dockhand__exec_container(command=["sh", "-c", "mount | grep /data"])Schützt vor dem Fall dass das Backup auf den falschen Pfad läuft. M2 — Pangolin Newt-Sync-Delay nicht berücksichtigt (Smoke 8.4 Step 4) Fix: Vor dem Browser-Test explizit warten — LOWL1 — Task 3.3 Granularität Was gut ist
|
Plan-Review Round-1: code-qualityStatus: NEEDS_FIXES (2 HIGH, 3 MEDIUM, 2 LOW — kein Blocker für Implementierungsstart wenn HIGH-Punkte vor Task 3.2 bzw. 4.1 adressiert werden) FindingsHIGHH1 — GET /api/printers filtert
Task 7.1 testet das Verhalten erst als E2E — wenn H2 — Task 3.2
MEDIUMM1 — Task 3.4 „Pattern wie Task 3.3" für 5 Routes reicht nicht Task 3.3 schreibt 5 Tests (list, new-form, create-post, edit-prefilled-stub, confirm-disable-stub). Task 3.4 hat kein einziges Test-Snippet für die 5 fehlenden Routes (edit-GET, edit-POST, disable-GET, disable-POST, enable-POST). Für Soft-Routes wie enable/disable-POST sind Redirect-Ziel und 409-Konflikt-Fall die Spec-relevanten Assertions. Ein Implementer der nur Task 3.4 liest, schreibt unter Zeitdruck Minimal-Tests ohne die Fehler-Pfade. M2 — Phase 6 ohne Verifikations-Task für Pangolin Header-Auth Phase 6 endet mit Labels im Compose. Der erste echte Smoke-Test ist Task 8.4 Step 5 (PrintService 409). Es fehlt ein direkter curl-Test M3 — Plan sagt: „Falls LOWL1 — Task 4.1 Fixture-Setup nicht ausgeschrieben
L2 — Coverage-Schwelle für Der Plan selbst setzt 70% für die Web-Routes, während die JSON-API (80%) und der Service (85%) höher liegen. Die Web-Routes enthalten Form-Parsing, Redirect-Logik und CSRF-Flow — das sind Mutations-Pfade. 70% ist nach test-coverage-pflicht.md für „HTMX-Event-Wiring / Form-Handler" Minimum 80%. Empfehlung: auf 80% anheben oder in die Coverage-Whitelist mit Begründung aufnehmen. Was gut ist
|
Plan-Review Round-1: network-TeamStatus: APPROVE mit 3 Anmerkungen (keine CRITICAL/HIGH) FindingsMEDIUM — Phase 0 Step 3: MCP-Tool-Name stimmt nicht (wird fehlschlagen)Plan schreibt: Das MCP-Tool heisst in dieser Umgebung so nicht — Pangolin MCP nutzt andere Tool-Namen (ermittelbar via Tool-Discovery). Subagent wird auf Fix: Step 3 umformulieren auf SSH-Fallback: # Vault-Key: homelab-pangolin-integration-api (Feld: password)
PANGOLIN_URL="https://backend-api.strausmann.cloud"
curl -sf -H "Authorization: Bearer ${PANGOLIN_TOKEN}" \
"${PANGOLIN_URL}/v1/org/strausmann/resources" \
| python3 -c "import json,sys; [print(r['resourceId'], r.get('fullDomain')) for r in json.load(sys.stdin)['data']['resources'] if 'print-hub' in r.get('fullDomain','')]"Alternativ: MCP-Tool-Namen via LOW — Phase 3.1 CSRF: zwei Implementierungs-Alternativen ohne EntscheidungPlan zeigt Empfehlung: LOW — Phase 3.2
|
…2 HIGH + 6 MED + 8 LOW) Round-1 Reviews: ops/storage/code-quality NEEDS_FIXES, network NEEDS_FIXES (light). Folgendes wurde eingearbeitet: CRITICAL - C1 (ops) set_container_auto_update Parameter heisst policy=, nicht auto_update=. MCP-Tool-Schema verifiziert via ToolSearch. Task 8.2 + 8.4 korrigiert. - C2 (code-q) GET /api/printers filterte nicht auf enabled=true. Existing printers_repo.list_all() macht SELECT * ohne WHERE-Clause. Zwei neue Tasks ergaenzt: 2.6 (Repo include_disabled-Parameter), 2.7 (Route nutzt es). Mit Failing-Tests und Coverage. - C3 (network) MCP-Tools existieren nicht: FALSCH-POSITIV. Live-Check via ToolSearch zeigt beide Pangolin-MCP-Tools mit den exakten Namen. Plan-Notiz ergaenzt damit Round-2-Review das nicht erneut bringt. HIGH - H1 (ops) Rollback-Pfad fehlt: neue Task 8.5 mit 8 Steps fuer Stack-Down + SQLite-Restore + Compose-Revert + Stack-Env-Re-Merge + printers.yaml wiederherstellen + Stack-Start + Verifikation. - H2 (code-q) Task 3.2 Placeholder-Tests: alle 9 Tests vollstaendig ausgeschrieben mit PAYLOAD-Konstante. MEDIUM - M1 (storage) Isolation-Level-Test gestrichen (False-Confidence). - M2 (storage) downgrade() raised NotImplementedError → pass (no-op). - M3 (code-q) Task 3.4 vollstaendig ausgeschrieben mit 5 Web-Route-Tests (Edit/Update/Disable-Confirm/Disable-POST/Enable-POST). - M4 (code-q) Neue Task 6.3 fuer curl-Verifikation des Header-Auth-Bypass vor dem Smoke-Test. - M5 (code-q) hangar_meta-Marker-Code entfernt — Tabelle existiert nicht im Hub. - M6 (ops) Smoke-Schritte verifizieren in Task 8.4. LOW - L1 Pangolin Bug #3099 als Hinweis im Smoke-Step. - L2 CSRF Custom-Wrapper-Variante explizit gewaehlt (statt 2 Alternativen). - L3 Task 4.1 Fixture-Setup vollstaendig mit disabled_printer-Fixture + enabled_printer-Regression-Test. - L4 Web-Routes Coverage 70% → 80%. - L5 json_extract Integer-Output mit erwarteter Smoke-Output dokumentiert. - L6 Test-Wording: "server_default" vs "Backfill-Funktion" jetzt zwei separate Tests, Backfill-Helper _backfill_snmp() exportiert fuer direkten Funktions-Test. Spec-Coverage-Tabelle + Coverage-Schwellen erweitert um die neuen Tasks (2.6, 2.7, 6.3, 8.5). printers_repo Coverage-Schwelle 85%. Refs #124 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Plan-Review Round-2: ops-TeamStatus: APPROVE (mit einem LOW-Finding zur expliziten Dokumentation) Round-1 Findings — VerifikationH1 Rollback (Task 8.5): Adressiert. 8 Steps vollständig. Reihenfolge ist korrekt: Stack down → DB-Restore → WAL/SHM-Removal → Compose-Revert → Env-Re-Merge → printers.yaml-Restore → Stack-Start → Verifikation. WAL/SHM-Removal in Step 2 direkt nach dem DB-Restore und vor Stack-Start ist die richtige Position — SQLite würde andernfalls beim Mount den WAL-Zustand wiederherstellen und den clean Restore überschreiben. C1 policy= Fix (Tasks 8.2 + 8.4): Adressiert. Beide Calls nutzen jetzt korrekt M6 Smoke-Schritte: Adressiert. Task 8.4 enthält jetzt json_extract Integer-Output-Hinweis (0/1 statt false/true) und Pangolin-Bug-#3099-Vermerk. Reicht. Neue Round-2 Findings[LOW] Task 8.5 Step 3: [KEINE ISSUE] Task 6.3 Reihenfolge: Die curl-Schritte in 6.3 sind als Pre-Deploy-Verifikation markiert — das macht sie zu einem "diese Labels funktionieren bereits"-Check. Der Text sagt klar "Nach Stack-Update in Phase 8.3 muss der Header-Auth-Bypass funktionieren. Dieser Task wird VOR dem Smoke-Test (8.4) explizit ausgeführt". Das bedeutet: 6.3 läuft nach 8.3, nicht als Phase-6-Check. Die Positionierung im Plan unter Phase 6 ist irreführend, aber der Text-Kommentar in Task 6.3 macht die tatsächliche Ausführungsreihenfolge klar. Kein Bug. [KEINE ISSUE] Task 2.6/2.7 und Hangar PrinterSync: Plan sagt, Hangar filtert disabled Drucker bereits im Cache-Layer heraus. Smoke-Test 8.4 Step 2 verifiziert DNS-Erreichbarkeit zwischen den Containern. Ein dedizierter Ops-Team gibt APPROVE. Der LOW-Hinweis zu |
Plan-Review Round-2: network-TeamStatus: APPROVE Round-1 Findings — VerifikationC3 Falsch-Positiv akzeptiert: Ja L1 Pangolin Bug #3099: adressiert L2 CSRF-Variante: adressiert Neue Round-2 FindingsR2-N1 (LOW): Task 6.3 Reihenfolge — leicht irreführend Empfehlung: In Task 6.3 Intro-Zeile klarstellen: "Dieser Task ist in Phase 6 vorbereitet (Credentials, Vault), wird aber nach 8.3 ausgeführt — erst dann sind die Labels live." Die aktuelle Formulierung sagt das schon halb, aber ein expliziter Satz "Ausführungs-Zeitpunkt: nach Task 8.3, vor Task 8.4" beseitigt jeden Zweifel. R2-N2 (LOW): Pangolin-Resource Bestand-Detection fehlt Das ist per ("Labels sind Source of Truth, API-Änderungen werden überschrieben") korrekt und gewollt. Kein Plan-Defekt, nur eine Klarstellung: wenn Phase 0 Step 3 zeigt dass , muss das Secret aus dem Vault-Item in 6.1 mit dem bestehenden übereinstimmen oder bewusst überschrieben werden. Dieser Hinweis fehlt in Task 6.1/6.2. Empfehlung: In Task 6.2 Step 2 eine Bemerkung: "Falls Phase 0 Step 3 zeigt dass headerAuth bereits gesetzt ist: das neue Secret aus Task 6.1 ersetzt es. Vault-Item entsprechend anlegen/aktualisieren." Beide Round-2-Findings sind LOW und blockieren die Umsetzung nicht. Der Plan ist in allen network-relevanten Punkten korrekt ausgearbeitet. |
Plan-Review Round-2: storage-TeamStatus: NEEDS_FIXES (1 MED neu) Round-1 Findings — Verifikation
Neue Round-2 Findings[MED] R2-M1 — Sync/Async-Mismatch in Der Test ruft Das ist auf der Produktions-Seite korrekt: Das Problem liegt im Test: Fix: Test muss # Option A — sync engine direkt
with engine.sync_engine.begin() as conn:
mig._backfill_snmp(conn)
# Option B — run_sync Pattern (spiegelt Alembic-Produktionsverhalten)
async with engine.begin() as conn:
await conn.run_sync(mig._backfill_snmp)Option B ist vorzuziehen weil sie 1:1 das Alembic- [LOW] R2-L1 — Rollback Task 8.5 Step 2: Reihenfolge ist korrekt Die Frage war ob WAL/SHM vor oder nach dem Restore gelöscht werden müssen. Die Plan-Reihenfolge (cp backup → db, dann rm WAL/SHM) ist korrekt: Stack ist bereits in Step 1 gestoppt, kein SQLite-Prozess kann neue WAL-Dateien anlegen. Das WAL/SHM-Löschen nach dem Restore bereinigt stale Dateien die zur alten (fehlerhaften) DB gehören. Kein Fix nötig. [LOW] R2-L2 — C2 Task 2.6 Step 5 sagt bereits: ZusammenfassungEin echter Bug: R2-M1 muss gefixt werden bevor der Test aussagekräftig ist — aktuell testet |
Plan-Review Round-2: code-qualityStatus: NEEDS_FIXES (2 neue Findings, 1 davon MEDIUM) Round-1 Findings — Verifikation
Neue Round-2 FindingsR2-M1 (MEDIUM) — Task 8.5 Step 4: Potential-Duplikat bei Rollback-Env-Merge # Task 8.5 Step 4:
existing = mcp__dockhand__get_stack_env(...)
merged = list(existing["variables"]) + [
{"key": "PRINTER_CONFIG_PATH", "value": "/etc/printer-hub/printers.yaml", ...},
]Wenn Fix: vor dem Concat explizit filtern: merged = [v for v in existing["variables"] if v["key"] != "PRINTER_CONFIG_PATH"] + [
{"key": "PRINTER_CONFIG_PATH", "value": "/etc/printer-hub/printers.yaml", "isSecret": False},
]Das ist symmetrisch zu Task 8.3 Step 1 und macht den Rollback idempotent. R2-L1 (LOW) — Task 8.5 Step 3: Task 8.5 Step 3 referenziert Der Rollback-Pfad setzt voraus dass der Agent den originalen Compose-Content irgendwo hat — das ist nur der Fall wenn Task 6.2 Step 1 ( Fix: In Task 0.1 (Phase 0) einen zusätzlichen Step ergänzen:
Alternativ in Task 8.5 Step 3 den Abruf direkt vor dem Revert machen (aber dann ist fraglich ob der Container schon crasht und R2-INFO — Task 2.7 Test-Konsistenz: kein Query-Param mehr, Test OK
ZusammenfassungR2-M1 ist ein echter Rollback-Korrektheitsfehler — im Fehlerfall (den dieser Task absichern soll) kann der Env-State inkonsistent werden. Bitte vor Round-3 adressieren. R2-L1 ist ein Dokumentationslücke die den Rollback-Pfad fragil macht. |
Round-2 Reviews: ops/network APPROVE, storage/code-quality NEEDS_FIXES. MEDIUM - R2-M1 (storage): Task 1.3 Backfill-Test rief sync _backfill_snmp mit AsyncConnection auf — Coroutine nie ausgefuehrt, Test prueft nichts. Fix: await conn.run_sync(mig._backfill_snmp) — spiegelt alembic env.py Pattern. - R2-M2 (code-q): Task 8.5 Step 4 Rollback-Env-Re-Merge konnte PRINTER_CONFIG_PATH duplizieren wenn 8.3 partiell durchgelaufen. Filter analog 8.3 vor dem Append ergaenzt. LOW - R2-L1 (ops + code-q): PRE_DEPLOY_COMPOSE_CONTENT war nicht explizit gesichert. Neue Phase 0 Step 4b mit get_stack_compose-Output in phase0-live-check-results.md. - R2-L2 (network): Task 6.3 curl-Verifikation hatte unklaren Ausfuehrungszeitpunkt. Verschoben nach Task 8.3.5 (zwischen start_stack und Smoke). Phase 6 nur noch Vorbereitung (Vault-Item + Compose-Labels), Live-Test in Phase 8. - R2-L3 (network): Bestand-Detection-Pfad fuer Pangolin-Resource ergaenzt. Phase 0 Step 3 mit Entscheidungsbaum: headerAuth null → neu anlegen headerAuth.user==claude-automation → Passwort holen statt neu headerAuth.user!=claude-automation → STOP, User-Klaerung healthCheck.enabled==false → Labels ergaenzen (Newt v1.18.4) Refs #124 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Plan-Review Round-3: ops-TeamStatus: APPROVE Round-2 Findings — Verifikation
Round-3 SpezifischTask 8.3.5 Reihenfolge (R2-L2): Verschiebung nach Phase 8 ist korrekt. Phase 0 Step 3 Bestand-Detection (R2-L3): 4-Fälle-Entscheidungsbaum deckt alle Zustände ab: null/claude-automation/fremder-User/healthCheck-disabled. Der STOP-Fall bei fremdem User ist wichtig und korrekt als manuelle Klärung markiert. Vollständig. Keine neuen Round-3-Findings aus ops-Perspektive. ops-Team Review, Sonnet 4.6 |
Plan-Review Round-3: network-TeamStatus: APPROVE Round-2 Findings — VerifikationR2-L2 Task 8.3.5 Verschiebung: adressiert. Task 6.3 ist jetzt ein leerer Platzhalter mit explizitem Hinweis auf Task 8.3.5. Die Positionierung zwischen 8.3 (start_stack) und 8.4 (Smoke-Test) ist korrekt. R2-L3 Bestand-Detection: adressiert. Phase 0 Step 3 enthält einen vollständigen 4-Fall-Entscheidungsbaum (null / claude-automation / anderer User / healthCheck.disabled). Round-3 FindingsTask 8.3.5 Bestand-Detection — Task 6.2 Compose-Snippet: Passwort-Klartext korrekt auf |
Plan-Review Round-3: storage-TeamStatus: APPROVE (mit einem LOW-Hinweis) Round-2 Findings — VerifikationR2-M1 run_sync: vollständig adressiert. Task 1.3, Zeilen 488-493: der Test ruft jetzt Neue Round-3 FindingsR3-L1 (LOW): Task 8.5 Step 2 — WAL/SHM-Reihenfolge semantisch falsch Aktuell: SQLite WAL-Semantik: Das alte Risikobewertung: LOW — Stack ist in Step 1 gestoppt, kein Prozess öffnet die DB zwischen cp und rm. In der Praxis kein Crash-Risiko, aber semantisch ist rm-vor-cp die korrekte Reihenfolge bei SQLite-WAL-Restore. Alle anderen Aspekte (R2-M2 Filter in Step 4, R2-L1 Phase-0-Sicherung, Rollback-Gesamtstruktur) sind korrekt. Plan ist umsetzungsbereit. |
Plan-Review Round-3: code-qualityStatus: APPROVE Round-2 Findings — Verifikation
Neue Round-3 FindingsR3-L1 (LOW): Task 6.3 Verweis-Stub — Navigation leicht riskant Der 3-Zeilen-Stub in Phase 6 lautet sinngemäß: "Dieser Schritt wurde nach Task 8.3.5 verschoben." Das ist korrekt, aber ein Implementer der sequenziell arbeitet könnte in Phase 6 stoppen und denken, die curl-Verifikation entfällt. Der Stub enthält keinen direkten Anker-Link auf Task 8.3.5, nur "Siehe Task 8.3.5 unten". In einem 4000-Zeilen-Plan ist das ausreichend, wenn der Implementer von oben nach unten arbeitet — aber bei Subagent-Driven-Development, wo Agents direkt auf benannte Tasks dispatcht werden, könnte Phase 6 ohne 8.3.5 als vollständig erscheinen. Empfehlung: Stub mit explizitem Hinweis "8.3.5 ist Pflicht-Schritt, KEIN optional" ergänzen. Kein Blocker. R3-N1 (NOTE): Phase 0 Step 3 STOP-Fall — Fallback vorhanden, ausreichend Der Entscheidungsbaum hat einen R3-N2 (NOTE): Coverage-Tabelle vs. Task 8.3.5 Task 8.3.5 ist ein reiner curl-Verifikations-Task ohne neuen Code — keine Coverage-Implikation. Die Coverage-Tabelle referenziert ihn korrekt nicht. ✅ GesamtbewertungAlle Round-2 Findings korrekt und vollständig adressiert. R3-L1 ist ein Low-Risiko Navigations-Hinweis der bei sequenzieller Ausführung nicht relevant ist. Plan ist umsetzungsreif. |
Round-3 Reviews: alle 4 Teams APPROVE. 4 verbleibende non-blocking LOWs zur Vollstaendigkeit eingearbeitet: - R3-L1 (network): sleep 60 in Task 8.3.5 Step 1 jetzt als Retry-Schleife (5×60s, max 5 Min, mit Fail-Hinweis fuer Newt-Logs-Check). - R3-L2 (network): Bestand-Detection-Baum Phase 0 Step 3 um Zeile auth.ssoEnabled==false erweitert (Phase 6.2 aktiviert SSO ohnehin). - R3-L3 (storage): Task 8.5 Step 2 SQLite-Restore: rm WAL/SHM (2a) VOR cp DB (2b) — semantisch korrekt damit kein altes WAL kurzzeitig mit neuer DB koexistiert. - R3-L4 (code-q): Task 6.3-Stub PFLICHT-HINWEIS-Blockquote ergaenzt damit Subagent-Driven-Development Phase 6 nicht ohne 8.3.5 als komplett markiert. Status: Plan Round-4 FINAL. Alle 4 Teams APPROVE in Round-3, alle 4 Round-3-LOWs nun adressiert. Bereit fuer superpowers:subagent-driven-development. Refs #124 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Draft-Spec für Issue #124
Dieser PR enthält nur den Spec-Entwurf für die Migration von
printers.yamlin die DB plus eine neue Admin-UI/admin/printers/. Keine Code-Änderungen — Review-Grundlage für die 4 Fachteams.Issue: #124
Brainstorming: Session vom 2026-06-14 mit @strausmann
Kern-Entscheidungen (User-bestätigt)
HUB_PRINTERS_JSONwurde explizit verworfen — Operator legt Drucker nur über die Admin-UI an.derive_printer_id(model, host, port, created_at). Bestandsdrucker behalten ihre alten UUIDs (created_at war damals nicht im Salt), neue Drucker bekommen kollisionssicheren UUID auch bei IP/Port-Wiederverwendung.ptouch,brother_ql). Admin-UI Model-Dropdown wird aus Plugin-Registry gefüllt.printers_auditanalog Hangarlayouts_audit.GET /api/printers.Was sich konkret ändert
app/services/printer_config_loader.pyapp/db/lifespan.py::upsert_runtime_printers()app/schemas/printer_config.py/etc/printer-hub/printers.yamlVolume-Mountprinters.yamlaus/docker/stacks/hangar-print-hub/config/app/services/printer_admin_service.pyapp/api/routes/admin_printers.pyapp/web/routes/admin_printers.pyapp/templates/admin_printers/printers_auditReview-Fokus für Fachteams
/api/v1/admin/printers) wie in pangolin-resource-standard.md?Closes-Spec-of #124