{
  "id": "create-an-admin-dashboard",
  "type": "prompts",
  "category": "prompts",
  "locale": "de",
  "url": "/de/prompts/create-an-admin-dashboard",
  "title": "Prompt zum Erstellen eines Admin-Dashboards in Next.js",
  "description": "AI-Agent-Prompt zum Erstellen eines geschützten Next.js Admin-Dashboards mit Datentabellen, serverseitigen Auth-Guards und einem Sidebar-Layout mit Tailwind.",
  "tools": [
    "Cursor",
    "Claude Code",
    "Codex",
    "Windsurf"
  ],
  "stack": [
    "Next.js",
    "PostgreSQL",
    "TypeScript",
    "Tailwind"
  ],
  "tags": [
    "nextjs",
    "tailwind",
    "typescript",
    "auth",
    "postgres"
  ],
  "difficulty": "hard",
  "updated": "2026-06-08",
  "markdown": "Geben Sie diesen Prompt Ihrem Agenten, um einen rollenbasierten Admin-Bereich mit einer persistenten Sidebar, sortierbaren Datentabellen und serverseitigen Auth-Checks zu erstellen – ohne ein vollständiges neues Next.js-Projekt zu erstellen oder ein aufgeblähtes Admin-Framework zu installieren.\n\n## Haupt-Prompt\n\n```txt title=\"Main Prompt\"\nYou are working in an existing Next.js App Router project with TypeScript, Tailwind CSS v4,\nand PostgreSQL. Auth is already set up (assume a `getSession()` helper exists in `src/lib/get-session.ts`\nthat returns `{ user: { id, email, role } } | null`).\n\nTask: add an admin dashboard at the `/admin` route group.\n\nRequirements:\n- Create a `src/app/(admin)/layout.tsx` that:\n  - Calls `getSession()` and redirects to `/login` if the session is null or `role !== 'admin'`.\n  - Renders a persistent sidebar with links: Dashboard, Users, Settings.\n  - Uses Tailwind for layout — a fixed-width sidebar and a scrollable main area.\n- Create `src/app/(admin)/dashboard/page.tsx` with:\n  - Four KPI cards: Total Users, Active Today, Revenue (MRR), Churn Rate — all fetched from\n    PostgreSQL using parameterized queries via `postgres` npm package.\n  - A `<UsersTable>` server component that renders the 50 most recent users (id, email, role,\n    created_at) with sortable column headers (URL-based sort param).\n- Create `src/components/admin/KpiCard.tsx` and `src/components/admin/UsersTable.tsx`.\n- All DB queries must use parameterized placeholders — never string interpolation.\n- Do not install Prisma, Drizzle, or any ORM. Use the `postgres` package directly.\n- Do not use any pre-built admin UI library (Refine, AdminJS, etc.).\n\nStop and list all planned file changes before writing any code.\n```\n\n## Implementierungshinweise\n\n- Die Klammern der Routengruppe `(admin)` halten `/admin/dashboard` aus der URL heraus, während das Layout gemeinsam genutzt wird – der Agent vergisst manchmal die Klammern und erstellt ein literales `/admin`-Segment.\n- Sortierbare Spalten sollten URL-Parameter `?sort=email&dir=asc` verwenden, die in der Server-Komponente über die `searchParams`-Prop gelesen werden – kein Client-Status erforderlich.\n- KPI-Abfragen sollten parallel mit `Promise.all` ausgeführt werden, um DB-Roundtrips zu minimieren.\n\n## Erwartete Dateiänderungen\n\n```txt\nsrc/app/(admin)/layout.tsx                  (new)\nsrc/app/(admin)/dashboard/page.tsx          (new)\nsrc/components/admin/KpiCard.tsx            (new)\nsrc/components/admin/UsersTable.tsx         (new)\nsrc/lib/queries/admin-stats.ts             (new)\n```\n\n## Akzeptanzkriterien\n\n- Der Besuch von `/dashboard` als Nicht-Admin-Benutzer leitet zu `/login` weiter.\n- KPI-Karten zeigen echte Werte aus PostgreSQL.\n- Die Benutzertabelle wird serverseitig nach den URL-Parametern `sort` + `dir` sortiert.\n- `bun run build` beendet mit Exit-Code 0 und ohne Typfehler.\n\n## Testbefehle\n\n```bash\nbun run typecheck\nbun run build\nbun run dev\n# log in as admin and visit /dashboard\n# visit /dashboard without auth — confirm redirect to /login\n# add ?sort=email&dir=asc to the URL and confirm table order\n```\n\n## Häufige KI-Fehler\n\n- Erstellen von `src/app/admin/layout.tsx` anstelle von `src/app/(admin)/layout.tsx`.\n- Durchführen der Auth-Überprüfung clientseitig, was umgangen werden kann.\n- Verwendung von String-Interpolation in SQL-Abfragen: `` `SELECT * FROM users WHERE role = '${role}'` ``.\n- Abrufen von KPI-Statistiken sequenziell anstatt mit `Promise.all`.\n\n## Korrektur-Prompt\n\n```txt title=\"Fix Prompt\"\nThe admin layout does not redirect unauthenticated users, or the route group folder name is wrong.\nFix in order:\n1. Rename `src/app/admin/` to `src/app/(admin)/` — the parentheses are required for a route group.\n2. In `layout.tsx`, add the auth check at the very top using `getSession()` and `redirect('/login')`.\n3. Audit all SQL query strings and replace any interpolated variables with `$1`, `$2` placeholders.\nShow the corrected diff only.\n```"
}