3 Commits

Author SHA1 Message Date
chahinebrini
b36d9ae7c4 feat(admin): index.vue als quick-link-dashboard (Phase 2 done)
Phase 2-pending-Liste durch 4 NuxtLink-Cards ersetzt → tap navigiert direkt
zur jeweiligen page. Plus separater Stats-Quick-Link unten.

Pages-content unangetastet, nur dashboard refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 15:48:35 +02:00
chahinebrini
3bc5360832 feat(admin): Phase 2 Frontend — Domains/Stats/Users/Moderation pages + responsive layout
4 page-implementations + server-route-proxies (admin-secret stays server-only):

DOMAINS (apps/admin/pages/domains.vue):
- UTable mit pending-submissions queue
- Approve / Reject buttons per row
- Reject-confirm-modal mit optional note
- useToast + refresh nach action
- 3 server-routes: GET list + POST approve/reject

STATS (apps/admin/pages/stats.vue):
- Stat-cards: Total Users + delta-week, Total Posts + delta-week,
  Domains pending (link to /domains), Domains approved, Feedback pending,
  Lyra-Posts (30d)
- UProgress für Domain-Approval-Quote
- Auto-refresh 60s + manual refresh-button
- USkeleton während loading
- 1 server-route: GET /api/stats

USERS (apps/admin/pages/users.vue):
- UTable mit avatar+nickname/username, plan-badge, streak, status, createdAt
- Search-input + plan-filter dropdown
- Action-dropdown per row: Plan-Change / Ban-Toggle / Soft-Delete
- 3 separate UModals mit confirm-pattern
- Cursor-pagination (Mehr laden button)
- 3 server-routes: GET list, PATCH /:id, DELETE /:id

MODERATION (apps/admin/pages/moderation.vue):
- Stack-layout mit card-pro-item (statt table — content-preview braucht space)
- Type-badge (Post/Comment), Author + Plan-badge, content-preview (200 chars),
  reportedAt
- Action-buttons: Dismiss (gray), Delete Content (red soft + reason-modal),
  Ban User (red solid + warning-modal)
- Empty-state, cursor-pagination
- 4 server-routes: GET /queue, POST /:id/dismiss/delete/ban-user

Server-route pattern (apps/admin/server/api/...):
- Use useRuntimeConfig().adminSecret server-only
- Client never sees x-admin-secret
- Body/query passthrough to backend

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 15:48:35 +02:00
chahinebrini
f7c9c79365 feat(admin): Admin App initial commit + Deploy-Infrastructure
apps/admin/:
- Nuxt 4.1.3 + @nuxt/ui 4 + @nuxtjs/supabase, port 3017 staging
- 7 pages: index (59 LOC dashboard), login (72 LOC), auth/confirm, plus stubs
  für domains/users/stats/moderation (14-17 LOC each, content für separate
  Phase 2 Session)
- composables/useAdminAuth.ts: Supabase login + verifyAdminRole hook
- middleware/admin-auth.ts: route guard (Phase 3 backend-check ready)
- layouts/default.vue, app.vue, README.md
- nuxt.config.ts: SSR=true, port 3017, dark-mode preference, Supabase
  pkce-flow, runtimeConfig.adminSecret für Phase 3 backend-binding

Deploy-Infrastructure:
- .github/workflows/deploy-admin-staging.yml: build admin auf push to main mit
  path-filter apps/admin/**, scp tar zu Server, atomic-mv + pm2 restart
- scripts/deploy-admin-from-artifact.sh: Server-side deploy (extract, atomic mv,
  pm2 reload). Kein prisma-migrate (admin hat kein eigenes DB-Schema).
- apps/admin/start-admin-staging.sh: pm2 start-script mit Infisical-wrapper,
  port 3017, mappt Infisical SUPABASE_URL/KEY auf NUXT_PUBLIC_*
- ecosystem.config.js: rebreak-admin-staging Eintrag (port 3017,
  max_memory_restart 400M)
- ops/nginx/admin-staging.rebreak.org.conf: HTTP→HTTPS redirect, SSL paths,
  proxy auf 127.0.0.1:3017, noindex header

Pending User-Actions für go-live:
1. DNS-A-Record admin.staging.rebreak.org → 49.13.55.22
2. SSL-cert via certbot (oder bestehender wildcard *.staging.rebreak.org)
3. nginx-config auf Server aktivieren (sudo cp + ln + reload)
4. pm2 initial start: pm2 start ecosystem.config.js --only rebreak-admin-staging
5. Infisical-secret ADMIN_SECRET (server-only, Phase 3 binding)

GH-Actions: keine neuen Secrets (nutzt bestehende HETZNER_SSH_KEY/HOST/USER)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 22:30:17 +02:00