Thunderstrux is a Next.js App Router SaaS foundation for student societies. It supports organisation-scoped dashboards, event management, ticket types, public event discovery, credentials-based authentication, and Stripe-based checkout/connect flows.
- Next.js 16 App Router
- React 19
- Auth.js / NextAuth Credentials provider
- Prisma
- PostgreSQL
- Tailwind CSS
- Docker Compose
- Docker Desktop
- Node.js and
pnpmif you want to run commands outside Docker
Local development expects a .env file. Current important values:
DATABASE_URL=postgresql://thunderstrux:thunderstrux@db:5432/thunderstrux?schema=public
AUTH_SECRET=your-secret
AUTH_URL=http://localhost:3000
NEXTAUTH_URL=http://localhost:3000
NEXT_PUBLIC_APP_URL=http://localhost:3000
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
STRIPE_CONNECT_WEBHOOK_SECRET=Use http://localhost:3000 for browser-facing URLs. Do not use 0.0.0.0 for auth callbacks.
docker compose up --buildApp:
http://localhost:3000
Database:
localhost:5432
Run Prisma migrations in the app container:
docker compose run --rm app pnpm exec prisma migrate deploySeed demo data:
docker compose run --rm app pnpm prisma:seedTypecheck:
docker compose run --rm app corepack pnpm exec tsc --noEmitAuth uses the Credentials provider.
- Login page:
/login - Signup page:
/signup - Protected dashboard routes redirect unauthenticated users to
/login
Session data includes session.user.id, which is used for organisation access and checkout ownership.
Common local accounts:
user1@example.com/password123user2@example.com/password123empty@example.com/password123
Additional one-off e2e test users may exist in the local database if validation scripts were run.
Public:
/- homepage, published events only/events/[eventId]- public event page
Auth:
/login/signup
Dashboard:
/dashboard- organisation selection / onboarding/dashboard/create- create organisation/dashboard/[orgSlug]- organisation dashboard/dashboard/[orgSlug]/events- event list/dashboard/[orgSlug]/events/new- create event/dashboard/[orgSlug]/events/[eventId]/edit- edit event/dashboard/[orgSlug]/settings- organisation settings / Stripe Connect
GET /api/orgs- organisations for the authenticated userPOST /api/orgs- create organisation andorg_ownermembershipGET /api/events?orgId=...- organisation-scoped eventsPOST /api/events- create event with optional ticket typesPATCH /api/events/[eventId]- update event and ticket typesPATCH /api/events/[eventId]/publish- publish/unpublish eventDELETE /api/events/[eventId]- delete event if safeGET /api/public/events- published public eventsGET /api/public/events/[eventId]- published public event detailPOST /api/payments/checkout/event- authenticated checkout start
- New events start as
draft - Draft events are not publicly visible
- Publish/unpublish is handled through
PATCH /api/events/[eventId]/publish - Publishing requires at least one ticket type and total quantity greater than zero
- Unpublishing is blocked if orders already exist
Checkout is authenticated and server-scoped:
- The API resolves
organisationIdfrom the event, not the client - The pending order is linked to
session.user.id - Validation checks event status, ticket type, and inventory before Stripe readiness
To complete checkout locally, the organisation must have a Stripe-ready connected account and Stripe env vars must be configured.
If an App Router page exists in source but still returns 404, clear the dev cache:
Remove-Item -LiteralPath .next -Recurse -Force
docker compose restart appThis was required for stale dynamic dashboard routes such as /dashboard/[orgSlug]/events/new.
If Docker/Turbopack serves stale output:
docker compose down
docker volume prune -f
rm -rf .next
docker compose up --build --force-recreate -d
docker compose run --rm app pnpm exec prisma migrate deploydocker volume prune -f can wipe the local database volume.
app/ App Router pages and API routes
components/ UI and feature components
lib/ Auth, Prisma, validators, Stripe, client helpers
prisma/ Schema, migrations, seed script
docs/obsidian/ Internal codebase notes
docker/ Dockerfile and container setup