Creating a New Next.js Application¶
This guide walks you through creating a new Next.js application from scratch on the Proxmox host.
Estimated time: 5-10 minutes
Prerequisites¶
- SSH access to Proxmox host
- Node.js 22+ installed (already available on host)
- K8s Supabase sandbox running (
supabase-sandboxnamespace)
Overview¶
The process consists of four stages:
- Create Next.js app using create-next-app
- Apply scaffold with Authentik auth, Supabase, and shadcn/ui
- Configure environment with Supabase credentials
- Run development server
Note: Authentication is now built-in. The scaffold includes the complete Authentik SSO pattern with AUTH_MODE switching.
Using the Intent (Recommended)¶
The quickest way to create a new app:
Or via the run-intent script:
This handles all stages automatically.
Manual Workflow¶
Stage 1: Create Next.js Application¶
Context: On Proxmox host
cd /root/projects
npx create-next-app@latest my-app \
--typescript \
--tailwind \
--app \
--src-dir \
--eslint \
--import-alias '@/*' \
--no-turbopack
What these flags mean:
- --typescript - Use TypeScript
- --tailwind - Include Tailwind CSS v4
- --app - Use App Router (not Pages Router)
- --src-dir - Use src/ directory structure (matches home-portal)
- --eslint - Include ESLint configuration
- --import-alias '@/*' - Set path alias for imports
- --no-turbopack - Use standard Webpack bundler
Checkpoint: Verify app created:
Estimated time: 1-2 minutes
Stage 2: Apply App Scaffold¶
Context: On Proxmox host
The scaffold adds the complete standard stack: - Authentik SSO with AUTH_MODE switching - Supabase integration with schema isolation - shadcn/ui components - RBAC helpers
What this adds:
my-app/
├── src/
│ ├── app/
│ │ ├── login/
│ │ │ └── page.tsx # Login page
│ │ └── api/
│ │ └── auth/
│ │ ├── [...nextauth]/
│ │ │ └── route.ts # NextAuth handlers
│ │ └── mode/
│ │ └── route.ts # Auth mode API
│ ├── components/
│ │ ├── auth/
│ │ │ └── dev-banner.tsx # Dev mode warning
│ │ ├── layout/
│ │ │ ├── session-provider.tsx
│ │ │ └── user-menu.tsx # User avatar/menu
│ │ └── ui/ # shadcn components
│ ├── lib/
│ │ ├── auth/
│ │ │ ├── index.ts # Auth module entry
│ │ │ ├── config.ts # AUTH_MODE config
│ │ │ ├── middleware.ts # Route protection
│ │ │ ├── rbac.ts # Tier helpers
│ │ │ ├── supabase-bridge.ts # JWT bridge
│ │ │ └── providers/
│ │ │ └── authentik.ts # NextAuth config
│ │ ├── supabase/
│ │ │ ├── client.ts # Browser client
│ │ │ └── server.ts # Server client
│ │ └── utils/
│ │ └── cn.ts # Tailwind class merger
│ ├── types/
│ │ ├── database.ts # Type definitions
│ │ └── next-auth.d.ts # Session types
│ └── middleware.ts # Root middleware
├── .env.local.example # Environment template
└── .gitignore
The scaffold also: - Installs all dependencies automatically - Initializes shadcn/ui with default components - Adds button, card, avatar, dropdown-menu components
Checkpoint: Verify scaffold applied:
ls /root/projects/my-app/src/lib/auth/
# Should see: index.ts, config.ts, middleware.ts, rbac.ts, supabase-bridge.ts, providers/
Estimated time: 2-3 minutes
Stage 3: Configure Environment¶
Context: On Proxmox host, in project directory
cd /root/projects/my-app
# Get Supabase credentials
kubectl get secret -n supabase-sandbox supabase-secrets -o jsonpath='{.data.ANON_KEY}' | base64 -d
kubectl get secret -n supabase-sandbox supabase-secrets -o jsonpath='{.data.SERVICE_ROLE_KEY}' | base64 -d
kubectl get secret -n supabase-sandbox supabase-secrets -o jsonpath='{.data.JWT_SECRET}' | base64 -d
# Create .env.local from template
cp .env.local.example .env.local
# Edit .env.local with your keys
Required environment variables:
# Auth mode: none (dev) or authentik (production)
AUTH_MODE=none
# Supabase
NEXT_PUBLIC_SUPABASE_URL=http://10.89.97.20:8000
NEXT_PUBLIC_SUPABASE_ANON_KEY=<your-anon-key>
SUPABASE_SERVICE_ROLE_KEY=<your-service-role-key>
SUPABASE_JWT_SECRET=<your-jwt-secret>
Checkpoint: Verify environment configured:
Estimated time: 1-2 minutes
Stage 4: Run Development Server¶
Context: In project directory
Option A: Direct run (foreground)
Option B: Tmux session (recommended for persistence)
Checkpoint: Verify server running:
Access your app: http://10.89.97.10:3000 (Proxmox host IP)
Estimated time: < 1 minute
Summary of Commands¶
Complete workflow (copy-paste friendly):
# Create Next.js app
cd /root/projects
npx create-next-app@latest my-app --typescript --tailwind --app --src-dir --eslint --import-alias '@/*' --no-turbopack --yes
# Apply scaffold (installs dependencies and shadcn)
/root/tower-fleet/scripts/scaffold-nextjs.sh /root/projects/my-app my-app
# Configure environment
cd my-app
ANON_KEY=$(kubectl get secret -n supabase-sandbox supabase-secrets -o jsonpath='{.data.ANON_KEY}' | base64 -d)
SERVICE_KEY=$(kubectl get secret -n supabase-sandbox supabase-secrets -o jsonpath='{.data.SERVICE_ROLE_KEY}' | base64 -d)
JWT_SECRET=$(kubectl get secret -n supabase-sandbox supabase-secrets -o jsonpath='{.data.JWT_SECRET}' | base64 -d)
AUTH_SECRET=$(openssl rand -base64 32)
cat > .env.local << EOF
AUTH_MODE=none
AUTH_SECRET=$AUTH_SECRET
NEXT_PUBLIC_SUPABASE_URL=http://10.89.97.20:8000
NEXT_PUBLIC_SUPABASE_ANON_KEY=$ANON_KEY
SUPABASE_SERVICE_ROLE_KEY=$SERVICE_KEY
SUPABASE_JWT_SECRET=$JWT_SECRET
EOF
# Start dev server
npm run dev
Using K8s Supabase with Schema Isolation¶
When using the shared K8s Supabase instance, each app needs its own schema.
Create Schema for New App¶
SCHEMA_NAME="my_app" # Use underscores, not hyphens
# Create schema
kubectl exec -n supabase-sandbox postgres-0 -- psql -U postgres << EOF
CREATE SCHEMA IF NOT EXISTS $SCHEMA_NAME;
GRANT USAGE ON SCHEMA $SCHEMA_NAME TO postgres, authenticated, service_role, anon;
GRANT ALL ON SCHEMA $SCHEMA_NAME TO postgres;
ALTER DEFAULT PRIVILEGES IN SCHEMA $SCHEMA_NAME
GRANT ALL ON TABLES TO postgres, authenticated, service_role;
ALTER DEFAULT PRIVILEGES IN SCHEMA $SCHEMA_NAME
GRANT SELECT ON TABLES TO anon;
EOF
# Update PostgREST to expose schema
CURRENT_SCHEMAS=$(kubectl get configmap -n supabase-sandbox supabase-config -o jsonpath='{.data.PGRST_DB_SCHEMA}')
kubectl patch configmap -n supabase-sandbox supabase-config --type=json \
-p="[{\"op\": \"replace\", \"path\": \"/data/PGRST_DB_SCHEMA\", \"value\": \"$CURRENT_SCHEMAS,$SCHEMA_NAME\"}]"
# Restart PostgREST
kubectl rollout restart deployment -n supabase-sandbox rest
The scaffold automatically configures Supabase clients to use the correct schema (derived from app name).
Authentication Modes¶
The scaffold includes dual-mode authentication code:
| Mode | AUTH_MODE |
Behavior |
|---|---|---|
| Development | none |
No authentication, all routes accessible |
| Production | authentik |
Real OAuth/OIDC with Authentik SSO |
What's Included vs Manual Setup¶
| Included in Scaffold | Manual Setup Required |
|---|---|
| Auth middleware & route protection | Create Authentik Provider |
| NextAuth configuration | Create Authentik Application |
| Login page & API routes | Get OAuth credentials |
| Session provider & user menu | Configure .env.local |
| RBAC helpers | Set redirect URIs in Authentik |
Switching to Production Auth¶
- Create OAuth2/OpenID Provider in Authentik admin (
https://auth.bogocat.com/if/admin/): - Name:
{app-name}-provider - Client type: Confidential
- Redirect URIs:
http://localhost:3000/api/auth/callback/authentikhttps://{app}.bogocat.com/api/auth/callback/authentik
-
Scopes:
openid profile email groups -
Create Application in Authentik admin:
- Name:
{app-name} - Slug:
{app-name} -
Provider:
{app-name}-provider -
Configure environment (
.env.localor K8s secrets): -
Restart the application
Full guide: /root/tower-fleet/docs/workflows/migrating-to-authentik.md
Common Issues¶
Issue: npm command not found¶
Cause: Not in a shell with Node.js available
Solution: Node.js 22 is installed on the Proxmox host. Verify:
Issue: Supabase connection errors¶
Cause: Wrong URL or key, or supabase-sandbox not running
Solution:
# Check supabase-sandbox pods
kubectl get pods -n supabase-sandbox
# Verify Kong is accessible (sandbox)
curl http://10.89.97.20:8000/rest/v1/
# Check .env.local has correct values
cat .env.local
Issue: Permission denied on database¶
Cause: Schema not created or PostgREST not updated
Solution: Follow the schema isolation steps above.
Next Steps¶
After your app is running:
- Set up database schema - See Database Migrations
- Review implementation patterns - See App Conventions
- Deploy to production - See Production App Deployment
- Add to project tracking - Update
/root/PROJECTS.md
Development vs Production Supabase¶
| Environment | Namespace | URL | Purpose |
|---|---|---|---|
| Sandbox | supabase-sandbox |
http://10.89.97.20:8000 |
Development, testing |
| Production | supabase |
http://10.89.97.20:8000 |
Deployed apps |
Use --prod flag with scaffold script to configure for production Supabase:
Reference Implementation¶
The home-portal app is the reference implementation for the standard stack:
- Location: /root/projects/home-portal
- Fully implemented Authentik SSO
- RBAC with tier-based access
- Supabase integration with schema isolation