Commit graph

7 commits

Author SHA1 Message Date
Jesko Anschütz
27c4562175 Tenant-Feature Phase 3b: Login-Redirect + Tenant-Context in Manage-UI
- reqcontext-Package: shared contextKey für httpapi und manage
- Login-Redirect: Tenant-User → /manage/<slug>, Admin → /admin
- GetUserByUsername: LEFT JOIN tenants für TenantSlug-Befüllung
- manage/ui.go: reqcontext.UserFromContext statt hardcoded "morz"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 18:00:02 +01:00
Jesko Anschütz
0b21be6469 Tenant-Feature Phase 3: Auth-Middleware verdrahtet
- TenantSlug in User-Struct + GetSessionUser per JOIN befüllt
- middleware.go: RequireAuth, RequireAdmin, RequireTenantAccess
- router.go: alle Routen mit passendem Middleware-Stack gesichert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 17:52:55 +01:00
Jesko Anschütz
cea393c1a0 Auth Phase 1 Review: Fix 3 critical bugs in auth foundation
1. [SQL] Fix username uniqueness constraint
   - Changed from global unique to composite unique(tenant_id, username)
   - Multi-tenant apps need same usernames across tenants (e.g., each tenant can have 'admin')

2. [Go] Fix inconsistent error handling in scanSession
   - Now returns pgx.ErrNoRows when session not found (like scanUser)
   - Allows proper 404 vs 500 error distinction in handlers

3. [Go] Add missing VerifyPassword function
   - Implements bcrypt.CompareHashAndPassword for password verification
   - Enables login flow with proper error handling for missing users
   - Paired with existing GenerateFromPassword for secure password hashing

Security checks:
- SQL injection: All queries parameterized (no string interpolation)
- bcrypt: Cost factor 12 (production-recommended)
- Session tokens: PostgreSQL gen_random_uuid() (cryptographically secure)
- Password hashes: Protected with json:"-" tag (never exposed in responses)
- Error handling: Comprehensive, no silent failures

Build & Vet: All checks pass (go build ./..., go vet ./...)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 15:37:18 +01:00
Jesko Anschütz
585cb83ed0 MQTT-Playlist-Push: Änderungen erreichen Client binnen 5 Sekunden
Backend published auf signage/screen/{slug}/playlist-changed nach
Playlist-Mutationen (2s Debounce). Agent subscribed und fetcht
Playlist sofort (3s Debounce). 60s-Polling bleibt als Fallback.

Neue Packages: mqttnotifier (Backend), mqttsubscriber (Agent)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 11:35:50 +01:00
Jesko Anschütz
e03948f25d Kopplung Agent↔Backend: Selbstregistrierung + Playlist-Rotation
Backend:
- ScreenStore.Upsert(): idempotentes INSERT ON CONFLICT für Self-Registration
- POST /api/v1/screens/register: Agent registriert sich beim Start (upsert)
- manage/register.go: neuer Handler, immer unter Tenant "morz"

Agent:
- config: screen_name + screen_orientation (mit Fallback auf screen_id / landscape)
- app.go: registerScreen() — POST /api/v1/screens/register beim Start (Retry 30s)
- app.go: pollPlaylist() — GET /api/v1/screens/{slug}/playlist alle 60s
- app.go: nowFn liefert Playlist statt statischer URL; PlayerContentURL als Fallback
- playerserver: PlaylistItem-Struct in NowPlaying; JS rotiert Items per duration_seconds
- JS: Playlist-Fingerprint verhindert Reset laufender Rotation bei unverändertem Stand

Ansible:
- config.json.j2: screen_name + screen_orientation ergänzt
- host_vars/info10: screen_name + screen_orientation
- host_vars/info01-dev: screen_name + screen_orientation

Kopplung per Konvention: screen_id (config.json) = slug (DB)
Beim ersten Neustart der Agents erscheinen die Bildschirme automatisch im Admin-UI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 05:57:58 +01:00
Jesko Anschütz
d395804612 Bugfixes: JSON-Tags, Tenant-Lookup, Dockerfile Go-Version
- store: JSON-Tags auf allen Domain-Typen (snake_case statt PascalCase)
- media.go: PathValue("tenantId") → "tenantSlug" + Tenant-Lookup via TenantStore
- media.go: leere Asset-Liste gibt [] statt null zurück
- router.go: TenantStore an HandleListMedia/HandleUploadMedia weitergeben
- Dockerfile: golang:1.24 → golang:1.25 (go.mod fordert >= 1.25)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 23:26:56 +01:00
Jesko Anschütz
803f355220 Baue Ebene 2: PostgreSQL-Backend, Medien-Upload und Playlist-UI
- DB-Package mit pgxpool, Migrations-Runner und eingebetteten SQL-Dateien
- Schema: tenants, screens, media_assets, playlists, playlist_items
- Store-Layer: alle Repositories (TenantStore, ScreenStore, MediaStore, PlaylistStore)
- JSON-API: Screens, Medien, Playlist-CRUD, Player-Sync-Endpunkt
- Admin-UI (/admin): Screens anlegen, löschen, zur Playlist navigieren
- Playlist-UI (/manage/{slug}): Drag&Drop-Sortierung, Item-Bearbeitung,
  Medienbibliothek, Datei-Upload (Bild/Video/PDF) und Web-URL
- Router auf RouterDeps umgestellt; manage-Routen nur wenn Stores vorhanden
- parseOptionalTime akzeptiert nun RFC3339 und datetime-local HTML-Format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 22:53:00 +01:00