feat(presets): Phase 1k.3 — User-Presets Store + CRUD + Preview (Refs #104 #101)#136
Open
strausmann wants to merge 14 commits into
Open
feat(presets): Phase 1k.3 — User-Presets Store + CRUD + Preview (Refs #104 #101)#136strausmann wants to merge 14 commits into
strausmann wants to merge 14 commits into
Conversation
…tiveNav-Werte Die Nav-Bar hatte keinen Link auf /admin/printers, obwohl Phase 7 die Admin-UI für Drucker-Verwaltung bereitgestellt hat. User mussten die Route raten oder via Browser-Adresszeile direkt aufrufen. Außerdem teilten die beiden Admin-Bereiche (Drucker + API-Keys) denselben ActiveNav-Wert "admin" — der aktive Tab war nicht eindeutig. Änderungen: - layout.html: "Drucker" Link zwischen Templates und API Keys ergänzt - admin_printers.go: ActiveNav = "admin-printers" (7 Handler) - admin_api_keys.go: ActiveNav = "admin-api-keys" (5 Handler) - base.go: TemplateData Docstring aktualisiert Templates-Link bleibt drin — laut Issue #104 (Phase 1k.3 User-Templates) ist das Konzept weiterhin geplant. Aktuell gibt der Link 503 weil der Backend- Endpoint noch nicht da ist. Das wird mit #104 reaktiviert. Refs Issue #104 (Templates Phase 1k.3)
Spec für Phase 1k.3. Prämisse von #104 war veraltet (templates-Table/ TemplateLoader/templates:write-Scope wurden in Phase 1k.1a entfernt). Neu zugeschnitten auf: - Variante B: Hub als Preset-Store + Preview, Druck-Pfad bleibt template-agnostisch - B1: bestehende presets-Tabelle erweitern (content_type default qr_three_lines, tape_mm default 12) - CRUD /api/v1/presets + GET /{id}/preview.png (nutzt LayoutEngine wieder) - Writes require_print, Reads require_read - Geometrie-Overrides defern (YAGNI) Refs #104 #101 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9QnxBQkA1URkoVE14vxdc
… (Refs #104 #101) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9QnxBQkA1URkoVE14vxdc
- Neues Modul app/services/preset_service.py: - Domain-Errors PresetNotFoundError, DuplicatePresetNameError - _validate_layout(): prüft tape_mm ∈ TAPE_GEOMETRY und ContentType-Pflichtfelder - PresetService mit create/get/list_all/update/delete (CRUD vollständig) - Nutzt UnsupportedTapeError + ContentTypeDataMismatchError aus printer_backends.exceptions - LayoutEngine.required_fields(@classmethod) als öffentlicher Accessor auf _REQUIRED_FIELDS - Tests in test_preset_service.py ergänzt: - session-Fixture (in-memory SQLite, lokal in der Datei) - 8 neue Service-Tests (create happy/error×3, update happy/error, delete happy/error) - TDD: RED zuerst (ModuleNotFoundError), dann GREEN (10/10 passed) - ruff + mypy sauber Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9QnxBQkA1URkoVE14vxdc
…(Refs #104) M1: Falsy-`or`-Guard durch explizites `is not None` ersetzt (konsistent mit übrigen Guards in PresetService.update). M2: Test für inkompatiblen content_type-Wechsel beim update (ContentTypeDataMismatchError). M3: Test für Namens-Duplikat beim update (case-insensitiv, DuplicatePresetNameError). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9QnxBQkA1URkoVE14vxdc
…efs #104) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9QnxBQkA1URkoVE14vxdc
- presets_api_router in main.py importiert und via include_router registriert - Smoke-Test test_presets_router_registered_in_app ergänzt (TDD: RED → GREEN) - response_class=Response für preview.png-Endpunkt ergänzt (kein Default-JSON-Schema) - test_openapi_completeness: Endpunkt-Bereich auf 28-55 erweitert (35 Endpunkte erwartet) - test_openapi_completeness: Segment-Regex erlaubt jetzt Punkte für .png-Endpunkte Refs #104
….to_thread (Refs #104) Fix 1 (Critical): qr_with_listing-Presets werden mit UnsupportedContentTypeError abgelehnt (→ 422), statt 500 beim Preview-Render. _validate_layout prüft vor Tape-Validierung; create + update decken beide Pfade ab. Fix 2 (Important): Alle str(exc)-Interpolationen in presets_api.py durch feste deutschsprachige Meldungen ersetzt (CWE-209: keine internen Details an Clients). Fix 3 (Important): render_preview_png lagert den CPU-gebundenen Render-Block (engine.render + image.save) via asyncio.to_thread aus — analog print.py. Tests: +test_create_rejects_qr_with_listing (Service), +test_create_qr_with_listing_returns_422 (API).
|
Warning Gemini encountered an error creating the summary. You can try again by commenting |
This was referenced Jun 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 1k.3 — User-Presets (Hub-Backend)
Baut die zuvor ungenutzte
presets-Tabelle zum Layout-Preset-Store aus: ein "User-Template" = ein gespeichertes Preset auscontent_type+tape_mm+ Default-Feldwerten. Der Hangar-Editor (Companion, späteres Issue) nutzt diese Presets, um das Druck-Formular vorzubefüllen — der Druck-Pfad bleibt unangetastet (template-agnostisch).Refs #104 #101
Wichtig: #104 hatte eine veraltete Prämisse
#104 wurde vor der Layout-Engine (Phase 1k.1a) geschrieben und nahm
templates-Tabelle,TemplateLoader, YAML-Templates und einentemplates:write-Scope an — die in 1k.1a alle entfernt wurden. Dieser PR ist entsprechend neu zugeschnitten (Spec dokumentiert die Abweichung). #104 sollte vom PM an diesen Stand angeglichen + Labelsuperpowers:brainstorminggesetzt werden.Architektur-Entscheidungen
presets-Tabelle erweitert (bewusst akzeptierter Semantik-Blur)require_print(damit Hangars print-scoped Key Presets verwalten kann; SSO-Browser-User nach ADR 0014 trusted), Reads/Previewrequire_readqr_three_linesÄnderungen
presets+content_type+tape_mm(Alembic, server_default, leere Tabelle)get_by_name(case-insensitiv)PresetCreatePayload/PresetUpdatePayload/PresetResponsePresetService(Validierung gegenContentType/TAPE_GEOMETRY+ CRUD), wiederverwendete Domain-Errors/api/v1/presetsCRUD +GET /{id}/preview.png(nutzt bestehendeLayoutEngine, kein neuer Render-Pfad)Qualität
qr_with_listing-Preset → 500 bei Preview (jetzt 422 abgelehnt), CWE-209 sichere Fehlermeldungen (wieprint.py), Render viaasyncio.to_threadOut of Scope / Follow-ups
qr_with_listing/items-UnterstützungUnsupportedContentTypeError-Catch im Preview-Handler (aktuell unerreichbar)Spec & Plan
docs/superpowers/specs/2026-06-23-user-presets-design.mddocs/superpowers/plans/2026-06-23-phase-1k3-user-presets.md🤖 Generated with Claude Code