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>
28 lines
797 B
TypeScript
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,
|
|
},
|
|
});
|
|
});
|