chahinebrini d3dfa74cf8 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:17:20 +02:00

60 lines
2.3 KiB
Vue

<template>
<div>
<h1 class="text-xl font-semibold text-white mb-1">Dashboard</h1>
<p class="text-sm text-gray-500 mb-8">rebreak Admin -- internes Verwaltungspanel</p>
<!-- Stat-Cards (Placeholder bis Phase 2 echte API-Calls hat) -->
<div class="grid grid-cols-2 gap-4 lg:grid-cols-4 mb-8">
<div
v-for="card in statCards"
:key="card.label"
class="rounded-lg border border-gray-800 bg-gray-900 p-4"
>
<div class="flex items-center gap-2 mb-2">
<UIcon :name="card.icon" class="h-4 w-4 text-gray-500" />
<span class="text-xs text-gray-500">{{ card.label }}</span>
</div>
<p class="text-2xl font-bold text-white">{{ card.value }}</p>
</div>
</div>
<!-- Phase 2 Preview -->
<div class="rounded-lg border border-gray-800 bg-gray-900 p-6">
<h2 class="text-sm font-medium text-gray-400 mb-3">Phase 2 -- ausstehende Features</h2>
<ul class="space-y-2 text-sm text-gray-500">
<li class="flex items-center gap-2">
<UIcon name="heroicons:clock" class="h-4 w-4 text-gray-600" />
Domain-Approval-Queue (wartende Anfragen)
</li>
<li class="flex items-center gap-2">
<UIcon name="heroicons:clock" class="h-4 w-4 text-gray-600" />
User-Liste mit Plan-Status + letztem Login
</li>
<li class="flex items-center gap-2">
<UIcon name="heroicons:clock" class="h-4 w-4 text-gray-600" />
SOS-Session-Statistiken (aggregiert, anonym)
</li>
<li class="flex items-center gap-2">
<UIcon name="heroicons:clock" class="h-4 w-4 text-gray-600" />
Content-Moderation-Queue (gemeldete Nachrichten)
</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
// Auth-Guard via Nuxt-Middleware (siehe middleware/admin-auth.ts)
definePageMeta({
middleware: "admin-auth",
})
// Placeholder-Werte -- Phase 2 ersetzt mit echten API-Calls gegen backend /api/admin/*
const statCards = [
{ label: "Aktive User (30d)", value: "—", icon: "heroicons:users" },
{ label: "SOS-Sessions heute", value: "—", icon: "heroicons:chat-bubble-left-ellipsis" },
{ label: "Domains pending", value: "—", icon: "heroicons:globe-alt" },
{ label: "Free / Pro / Legend", value: "—", icon: "heroicons:star" },
]
</script>