# rebreak Admin Internes Verwaltungspanel fuer rebreak.org. **Status:** Phase 1 -- Skeleton (Auth-Wiring, Layout, Stub-Pages). Keine echten API-Calls. --- ## Stack | Schicht | Technologie | |---|---| | Framework | Nuxt 4.1.3 (SSR) | | UI | @nuxt/ui 4.x (Tailwind 4, Nuxt UI Komponenten) | | Auth | @nuxtjs/supabase 2.x (PKCE-Flow) | | Backend-Komm. | $fetch gegen /api/admin/* (Phase 3) | | Laufzeit | Node 24.11.1 / pm2 auf Hetzner CX23 | --- ## Wo die Admin-App lebt | Environment | URL | Port (intern) | pm2-Service | |---|---|---|---| | Staging | admin.staging.rebreak.org | 3017 | rebreak-admin-staging | | Prod | admin.rebreak.org | 3018 | rebreak-admin | Nginx-Routing-Config: wird in Phase 2 Deploy angelegt (analog zu staging.rebreak.org-Config). --- ## Lokale Entwicklung ```bash # Vom Monorepo-Root: pnpm dev:admin # Oder direkt: cd apps/admin && pnpm dev ``` Laeuft auf http://localhost:3017. Infisical-Secrets werden fuer lokales Dev nicht gebraucht -- die Supabase-URL/Key kommen als `process.env.NUXT_PUBLIC_SUPABASE_URL/KEY` oder fallen auf Staging-Defaults zurueck. --- ## Auth-Architektur ``` Admin-Browser | | 1. POST /api/auth/login (Supabase Email/Password) v Supabase Auth (db-staging.rebreak.org oder db.rebreak.org) | | 2. JWT zurueck (access_token) v Admin-Browser haelt Session (PKCE-Flow, persistSession=true) | | 3. GET /api/admin/* (Authorization: Bearer ) v Backend (staging.rebreak.org) | | 4. requireAdmin-Middleware: | - JWT verifizieren (Supabase public key) | - user_id in admin_users-Tabelle pruefen | - Bei Misserfolg: 403 v Admin-Endpoint-Response ``` **Aktueller Status (Phase 1):** Supabase-Login funktioniert. Schritt 4 (requireAdmin) ist NICHT implementiert -- jeder eingeloggte Supabase-User koennte theoretisch rein, wenn er die URL kennt. Das ist akzeptabel weil die Admin-URL nicht public ist und Staging-Daten keine hochsensiblen Produktionsdaten enthalten. **Phase 3 schaltet requireAdmin ein** -- dann ist der Zugang haerter gesperrt. --- ## DSGVO-Considerations fuer Admin-Zugriff Admins haben Zugriff auf User-Daten. Das bedingt: 1. **Audit-Log (TODO Phase 4 -- hans-mueller):** Jede Admin-Aktion (User ansehen, Domain genehmigen, Content moderieren) muss in einer `admin_audit_log`-Tabelle geloggt werden: - Wer (admin_user_id) - Was (action: "view_user" | "approve_domain" | "reject_domain" | "ban_user") - Welcher Datensatz (target_id) - Wann (timestamp) 2. **Daten-Minimierung im Admin-UI:** User-Liste zeigt NIEMALS echten Namen oder E-Mail. Nur Nickname (analog zur App-Anzeige). E-Mail ist nur fuer Kontaktaufnahme via Support-Ticket, nicht fuer Browse-UI. 3. **Admin-Zugangs-Liste:** `admin_users`-Tabelle in Supabase darf nur von User (Chahine) befuellt werden. Kein Self-Signup, kein automatisches Promoten. 4. **Data-Processing-Agreement:** Wenn externe Personen Admin-Zugang bekommen (z.B. Moderatoren), braucht es einen AVV. Aktuell: nur interner Zugang (Chahine). 5. **Datenschutzfolgeabschaetzung (DSFA):** Admin-Zugang auf Nutzerdaten von Suchtkranken faellt unter Art. 35 DSGVO (besondere Kategorien). Hans-Mueller-Task. --- ## Deploy-Plan ### Variante A: SSR auf Hetzner (Empfehlung) Analog zu `rebreak-staging` -- separater pm2-Service, separater Port, nginx-Subdomain. **Pros:** Kein zusaetzlicher Hosting-Service, Server-Side-Auth-Checks funktionieren native, Infisical-Secrets per Infisical-run-wrapper wie gewohnt. **Cons:** Belastet CX23 zusaetzlich (RAM). Admin-App hat aber wenig Traffic -- kein Risiko. **Setup:** ```bash # /srv/rebreak/ecosystem.config.js (ergaenzen): { name: 'rebreak-admin-staging', script: '/srv/rebreak/apps/admin/.output-staging/server/index.mjs', env: { PORT: 3017, NODE_ENV: 'production' } } ``` ```nginx # nginx: admin.staging.rebreak.org server { listen 443 ssl; server_name admin.staging.rebreak.org; location / { proxy_pass http://127.0.0.1:3017; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` ### Variante B: Static via Cloudflare Pages `nuxt generate` + Deploy zu Cloudflare Pages. **Pros:** Kostenlos, globales CDN, keine Hetzner-Last. **Cons:** Kein echter SSR (Auth-Checks nur client-side), API-Calls gehen trotzdem zu Hetzner. Fuer eine Admin-App die Server-Side-Checks braucht suboptimal. **Entscheidung: Variante A (SSR auf Hetzner).** --- ## GitHub-Actions-Pipeline -- Plan fuer Phase 2 Deploy Die bestehende `.github/workflows/deploy-staging.yml` baut nur `backend/`. Admin-App braucht einen separaten Job ODER einen eigenen Workflow. ### Option 1: Separater Workflow `deploy-admin-staging.yml` (empfohlen) ```yaml name: Deploy Admin Staging on: push: branches: [main] paths: - "apps/admin/**" - ".github/workflows/deploy-admin-staging.yml" workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 24.11.1 cache: pnpm - run: pnpm install --frozen-lockfile - name: Build admin working-directory: apps/admin run: pnpm build - run: tar czf admin-output.tar.gz -C apps/admin/.output . - uses: actions/upload-artifact@v4 with: name: admin-output path: admin-output.tar.gz deploy: needs: build runs-on: ubuntu-latest environment: staging steps: # ... analog zu deploy-staging.yml: # scp admin-output.tar.gz -> /srv/rebreak/apps/admin/.output-incoming.tar.gz # ssh -> scripts/deploy-admin-from-artifact.sh ``` **Warum separater Workflow:** `paths`-Filter verhindert dass ein Backend-Push auch die Admin-App rebuildet (und vice versa). Weniger GH-Actions-Minutes-Verbrauch. ### Option 2: Zusaetzlicher Job in `deploy-staging.yml` Parallel-Job neben dem bestehenden `build`-Job. Einfacher aber kein `paths`-Filter moeglich ohne komplizierte Logik -- jeder Push rebuildet alles. **Entscheidung: Option 1 (eigener Workflow mit paths-Filter).** Der Workflow-File wird in Phase 2 angelegt -- NICHT jetzt (Pipeline-Scope-Creep verhindern). --- ## Server-Script fuer Admin-Deploy Analog zu `scripts/deploy-from-artifact.sh` -- ein `scripts/deploy-admin-from-artifact.sh` das: 1. Admin-Artifact extrahiert nach `/srv/rebreak/apps/admin/.output-staging-new/` 2. Atomisches mv nach `.output-staging` 3. `pm2 restart rebreak-admin-staging` KEIN Migration-Step (Admin-App hat keine eigene DB -- nutzt Backend-API). --- ## TODOs nach Phase 1 ### Backend (rebreak-backend-Agent / Phase 3) - [ ] `requireAdmin`-Middleware: JWT verifizieren + admin_users-Tabelle-Check - [ ] Supabase-Migration: `admin_users`-Tabelle (`id uuid references auth.users`, `created_at`) - [ ] GET /api/admin/verify-admin (prueft ob eingeloggter User Admin ist) - [ ] GET /api/admin/users (paginierte User-Liste, NUR nickname + plan + created_at + last_seen) - [ ] GET /api/admin/domains (Blocker-Domain-Approval-Queue) - [ ] POST /api/admin/domains/:id/approve - [ ] POST /api/admin/domains/:id/reject - [ ] GET /api/admin/stats (aggregierte anonyme Metriken) ### Hans-Mueller / DSGVO (Phase 4) - [ ] DSFA fuer Admin-Zugriff auf Nutzerdaten gemaess Art. 35 DSGVO - [ ] Audit-Log-Design: `admin_audit_log`-Tabelle + Retention-Policy - [ ] AVV-Template fuer externe Moderatoren (falls noetig) - [ ] TOM (Technische+Organisatorische Massnahmen) fuer Admin-Zugang dokumentieren - [ ] Loeschkonzept fuer Audit-Log-Eintraege (wie lange aufbewahren?) ### Backyard (Phase 2 Deploy) - [ ] nginx-Config: `admin.staging.rebreak.org` -> Port 3017 - [ ] nginx-Config: `admin.rebreak.org` -> Port 3018 - [ ] Let's Encrypt-Cert fuer admin.staging.rebreak.org + admin.rebreak.org - [ ] ecosystem.config.js: rebreak-admin-staging + rebreak-admin Service - [ ] GH-Actions-Workflow: `deploy-admin-staging.yml` (paths-filtered) - [ ] Server-Script: `scripts/deploy-admin-from-artifact.sh` - [ ] GitHub-Environment: `staging` muss HETZNER_SSH_KEY/HOST/USER schon haben (von backend-deploy geerbt)