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

28 lines
797 B
TypeScript

// Admin-App proxy: forwards to backend /api/admin/users mit x-admin-secret
// (Pattern wie andere admin-pages — admin-secret bleibt server-side, nie im Browser).
//
// Query-Params werden 1:1 weitergereicht. Backend macht die Validierung.
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig();
const query = getQuery(event);
const params = new URLSearchParams();
for (const [k, v] of Object.entries(query)) {
if (v !== undefined && v !== null && v !== "") {
params.set(k, String(v));
}
}
const url = `${config.public.apiBase}/api/admin/users${
params.toString() ? `?${params.toString()}` : ""
}`;
return $fetch(url, {
method: "GET",
headers: {
"x-admin-secret": config.adminSecret as string,
},
});
});