'use client'; import Link from 'next/link'; import { useEffect, useMemo, useState } from 'react'; import { Icons } from '@/components/icons'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { cn } from '@/lib/utils'; type WizardState = { appUrl: string; authSecret: string; dbHost: string; dbPort: string; dbName: string; dbUser: string; dbPassword: string; superAdminEmail: string; superAdminPassword: string; superAdminName: string; resetPassword: boolean; buildStandalone: boolean; }; const steps = [ 'Project URL', 'Database', 'Auth + seed', 'Preview .env.local' ] as const; function generateSecret() { const bytes = new Uint8Array(32); crypto.getRandomValues(bytes); return Array.from(bytes, (value) => value.toString(16).padStart(2, '0')).join(''); } function download(filename: string, content: string) { const blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); const anchor = document.createElement('a'); anchor.href = url; anchor.download = filename; anchor.click(); URL.revokeObjectURL(url); } export function SetupWizard() { const [copied, setCopied] = useState(false); const [state, setState] = useState({ appUrl: 'http://localhost:3000', authSecret: '', dbHost: 'localhost', dbPort: '5432', dbName: 'training_system', dbUser: 'postgres', dbPassword: 'postgres', superAdminEmail: 'admin@example.com', superAdminPassword: 'change-this-password', superAdminName: 'Super Admin', resetPassword: false, buildStandalone: false }); useEffect(() => { setState((current) => current.authSecret ? current : { ...current, authSecret: generateSecret() } ); }, []); const databaseUrl = useMemo(() => { const user = encodeURIComponent(state.dbUser); const password = encodeURIComponent(state.dbPassword); return `postgres://${user}:${password}@${state.dbHost}:${state.dbPort}/${state.dbName}`; }, [state.dbHost, state.dbName, state.dbPassword, state.dbPort, state.dbUser]); const envContent = useMemo( () => [ '# Generated by /setup', '', '# Authentication (Auth.js)', `AUTH_SECRET=${state.authSecret}`, '', '# Optional local app URL reference', `APP_URL=${state.appUrl}`, '', '# Database (PostgreSQL)', `DATABASE_URL=${databaseUrl}`, '', '# Initial Super Admin Seed', `SUPER_ADMIN_EMAIL=${state.superAdminEmail}`, `SUPER_ADMIN_PASSWORD=${state.superAdminPassword}`, `SUPER_ADMIN_NAME=${state.superAdminName}`, `SUPER_ADMIN_RESET_PASSWORD=${state.resetPassword ? 'true' : 'false'}`, '', '# Build Configuration', `BUILD_STANDALONE=${state.buildStandalone ? 'true' : ''}`, '', '# Sentry (optional)', 'NEXT_PUBLIC_SENTRY_DSN=', 'NEXT_PUBLIC_SENTRY_ORG=', 'NEXT_PUBLIC_SENTRY_PROJECT=', 'SENTRY_AUTH_TOKEN=', 'NEXT_PUBLIC_SENTRY_DISABLED="false"' ].join('\n'), [databaseUrl, state] ); async function copyToClipboard() { await navigator.clipboard.writeText(envContent); setCopied(true); window.setTimeout(() => setCopied(false), 2000); } const completedSteps = [ !!state.appUrl.trim(), !!state.dbHost.trim() && !!state.dbPort.trim() && !!state.dbName.trim(), !!state.authSecret.trim() && !!state.superAdminEmail.trim() && !!state.superAdminPassword.trim(), true ].filter(Boolean).length; return (
Template onboarding

Configure the template, then jump straight into the example dashboard.

This setup wizard collects your local database and Auth.js seed values, generates a ready-to-use .env.local, and points you to the public example routes under /example/dashboard/*.

Local app Reference URL used during local development. setState({ ...state, appUrl: event.target.value })} placeholder='http://localhost:3000' /> Auth secret Generated automatically for Auth.js credentials flow. setState({ ...state, authSecret: event.target.value })} />
Database configuration Fill in the PostgreSQL connection details. The wizard will build DATABASE_URL for you.
setState({ ...state, dbHost: event.target.value })} />
setState({ ...state, dbPort: event.target.value })} />
setState({ ...state, dbName: event.target.value })} />
setState({ ...state, dbUser: event.target.value })} />
setState({ ...state, dbPassword: event.target.value })} />
Initial super admin seed These values feed the seed script used by npm run setup:db.
setState({ ...state, superAdminEmail: event.target.value }) } />
setState({ ...state, superAdminPassword: event.target.value }) } />
setState({ ...state, superAdminName: event.target.value }) } />
setState({ ...state, resetPassword: event.target.checked }) } className='mr-3' /> Reset the seeded super admin password on reruns
setState({ ...state, buildStandalone: event.target.checked }) } className='mr-3' /> Enable standalone output for Docker-oriented builds
.env.local preview {completedSteps}/{steps.length} steps ready Copy or download this file, then run npm run setup:db.