Skip to main content

Docker and Build

Cashlytics and the documentation site are built as separate container images.

App Image​

  • Repository: ghcr.io/aaronjoeldev/cashlytics-ai
  • Tags for releases: vX.Y.Z, latest, and the short commit SHA (7 characters)
  • Tags for the dev branch: dev-X.Y.Z, dev-latest, dev-<short-sha>
  • Runtime: Next.js standalone output, listening on port 3000
  • Purpose: application runtime

The release workflow (release.yml in the app repository) builds and pushes these tags. Pushes to main that do not produce a release do not overwrite the published tags.

Dockerfile stages​

StagePurpose
depsInstalls dependencies with npm ci
builderRuns npm run build
migrate-depsInstalls drizzle-kit, drizzle-orm, and postgres into /migrate so the runtime image stays small
runnernode:24-alpine, runs as the non-root user nextjs (uid 1001), sets PORT=3000 and HOSTNAME=0.0.0.0, exposes port 3000

Startup and migrations​

The container runs /entrypoint.sh. It applies database migrations with drizzle-kit migrate using DATABASE_URL from the runtime environment. If a migration attempt fails (for example because PostgreSQL is not ready yet), it retries up to 5 times, 3 seconds apart. If all attempts fail, the container exits with code 1 and does not start the app, so the restart policy can try again. After a successful migration it starts node /app/server.js.

Build-time variables​

NEXT_PUBLIC_* variables are compiled into the client bundle during npm run build. The Dockerfile has no build arguments and .dockerignore excludes .env, so setting them at runtime has no effect on the published image. To change NEXT_PUBLIC_DEFAULT_LOCALE or NEXT_PUBLIC_DEFAULT_CURRENCY, build your own image and set them in the builder stage. See Environment Variables.

Build the app locally​

docker compose up -d --build

This uses docker-compose.yml in the app repository: the image is built from the Dockerfile, the app is available on port 3000, and PostgreSQL is exposed on port 5432 with the fixed password cashlytics_secret. This file is meant for local use only. Unlike docker-compose.selfhost.yml, it does not pass AUTH_TRUST_HOST or EMAIL_TRANSPORT to the container.

Docs Image​

  • Repository: ghcr.io/<owner>/cashlytics-docs
  • Tags: latest (default branch) and sha-<commit>
  • Runtime: static build served via Nginx on port 80
  • Purpose: user and developer documentation at docs domain

Build Commands​

Run these from the root of the cashlytics-lp repository.

Build docs locally​

cd docs-site
npm install
npm run build

Build docs container locally​

docker build -f docs-site/Dockerfile -t cashlytics-docs:local docs-site

CI Scope​

  • Pull requests that touch docs-site/ build the docs image without pushing it.
  • Pushes to main build the docs image and push it to GHCR (latest and sha-<commit>).
  • CI does not deploy anything. Routing and release on the VPS are handled manually.
  • A separate workflow (docker.yml) builds the landing page image on pushes to main and v* tags.