Skip to content

Containerize the backend and add a local Postgres compose file #18

Description

@AlaskanTuna

The owner asked for Docker/devcontainer. The honest answer is not both — here is the split and the reasoning.

Scope: Dockerfile (new), .dockerignore (new), compose.yaml (new), heroku.yml (new), Procfile (delete, if the container stack replaces it), .github/workflows/ci-cd.yml, RUNBOOK.md

Depends on: #9, #15 — the compose.yaml half depends on nothing and may be pulled forward into any earlier wave

Checklist

  • Add compose.yaml with a single postgres:17 service, a named volume, a pinned port, and dev-only credentials. No app service — the app runs on the host via dev; the point is an offline database, not a full local stack
  • Document it in RUNBOOK.md as the local DATABASE_URL alternative to a Neon branch, and as the target for restoring the task-1 rescue dump
  • verify: docker compose up -d then prisma migrate deploy against the local URL succeeds, db:seed seeds TariffConfig, and dev boots against it with GET /api/health returning ok
  • Decision gate. Build the image only if at least one is true: task 18's Bun adoption is proceeding on Heroku (no official buildpack ⇒ container stack), or a Render cutover is actually happening. If neither holds, stop here, record the reason in the issue, and leave the compose half as the delivered value
  • Write a multi-stage Dockerfile: builder installs dev dependencies, runs prisma generate, and builds sharedbackendfrontend; the runtime stage carries production dependencies, backend/dist, frontend/dist, the Prisma schema and migrations, and the generated client
  • Base on debian-slim, not alpine. Both sharp and Prisma's engines want glibc/OpenSSL; musl means chasing linux-musl-openssl-3.0.x binary targets and platform-specific sharp installs for no benefit on a solo project
  • If the image runs Bun, remember that the Prisma CLI's dynamic subcommand loading wants npm present — the oven/bun base image has no npm, while node:*-slim does. Whichever base is chosen, the release-phase migration must be proven inside the image, not just locally
  • Add .dockerignore covering node_modules, .git, docs/, assets/, frontend/public/*.webp, and dist — without it the build context balloons and layer caching is useless
  • Add heroku.yml with the build stage and a release: phase running the migration deploy (this is the container-stack equivalent of the current Procfile release line, and it is also the answer to Render free's missing pre-deploy hook noted in task 10)
  • Add a HEALTHCHECK against the existing /api/health route
  • Size for the constrained target: Render free is 512 MB RAM / 0.1 CPU with no persistent disk. Nothing in the image may assume local disk persistence for GeoTIFF caching — after task 6 that is R2's job. Record the final image size and the container's idle RSS in the issue
  • Build the image in CI on every PR (with layer caching) so it cannot silently rot. Do not push it from CI — building is the freshness guarantee, pushing is a separate decision
  • verify: docker build succeeds from a clean context, and the resulting container serves GET /api/health locally with only the documented env vars set
  • verify: inside the container, a cached project loads end-to-end and a panel drag recomputes flux with zero outbound calls to solar.googleapis.com — this proves sharp, geotiff.js, and the R2 client all work in the image, which is the only part of containerisation that can genuinely fail
  • verify: a staging deploy of the image (Heroku container stack or Render Docker) boots and passes the same checks, and the release-phase migration ran
  • verify: CI fails if the Dockerfile breaks — introduce a deliberate error and confirm the pipeline goes red, then revert. An image build that cannot fail the pipeline is not a guarantee

Priority: Low · Phase 12 task 21 of the maintainer’s migration plan.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3-lowNice to haveinfraHosting, DNS, CI/CDtoolingBuild, lint, monorepo, developer workflow

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions