Skip to content

System infrastructure

This page covers the parts of the system that matter when you need to run, debug, or deploy the app.

At a glance

WMA is a Next.js app backed by PostgreSQL, Redis, S3-compatible object storage, and SMTP for email.

graph TB
    Client[Browser]
    App[Next.js app]
    DB[(PostgreSQL on Neon)]
    Cache[(Redis)]
    Storage[S3-compatible storage]
    Email[SMTP]

    Client --> App
    App --> DB
    App --> Cache
    App --> Storage
    App --> Email

Runtime services

App

  • Runs in wma-web
  • Built from Dockerfile.prod
  • Exposes port 3000
  • Runs as the nextjs user in production

Redis

  • Runs in wma-redis
  • Uses redis:7.4-alpine
  • Shared with the app over the wma Docker network

Deployment files

  • Dockerfile.prod: production image build
  • docker-compose.staging.yml: staging containers
  • docker-compose.prod.yml: production containers
  • Taskfile.yml: shorthand commands for build and deploy steps

Useful commands

# local app
pnpm install
pnpm dev

# database
pnpm db:push-dev
pnpm db:seed:dev
pnpm db:deploy-prod

# staging
task 01-build-staging
task 02-start-staging
task 03-stop-staging

# production
task 04-build-production
task 05-start-production
task 06-stop-production

Environment variables

Keep secrets out of git. The app depends on a few groups of variables:

  • Database: DATABASE_URL, DIRECT_URL
  • Auth: NEXTAUTH_SECRET, NEXTAUTH_URL, HASH_SECRET
  • Redis: REDIS_URL or REDIS_HOST and REDIS_PORT
  • Storage: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, S3_ENDPOINT, BUCKET_NAME
  • Email: GMAIL_APP_PASSWORD
  • Public config: NEXT_PUBLIC_HOST_URL, NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY
  • Private Turnstile config: CLOUDFLARE_TURNSTILE_SECRET_KEY

Database notes

  • PostgreSQL is hosted on Neon.
  • Prisma is the only supported ORM path in the repo.
  • Schema files live under prisma/schema/.
  • Use db:deploy-prod for production migrations.

Storage and email

  • File uploads use DigitalOcean Spaces through the AWS SDK.
  • Outbound email uses Gmail SMTP.

Logs and checks

docker compose -f docker-compose.prod.yml logs -f wma-web
docker compose -f docker-compose.prod.yml logs -f wma-redis

Basic runtime checks:

  • App responds on http://localhost:3000
  • Redis container is up
  • Database migrations have been applied

Operational notes

  • Production and staging both use Dockerfile.prod.
  • The production image is a multi-stage build.
  • Redis is internal-only in compose.
  • Back up the database before risky production changes.