HR-ATS-Portal/DOCKER.md

4.0 KiB

Docker

Production stack is self-contained: Postgres, Redis, API, ATS engine, Taskiq workers, and the React SPA. Only the frontend is published on the host.

Production

# 1. Root compose env (DB password, port, workers) — see .env.example
cp .env.example .env
# Edit DB_PASSWORD (and JWT_SECRET_KEY inside backend/.env)

# 2. App secrets (JWT, OpenAI, email, Buffer, …)
cp backend/.env.example backend/.env
# Fill JWT_SECRET_KEY, OPENAI_API_KEY, DB_* matching the Compose postgres, …

# 3. Build and start
docker compose up -d --build
docker compose ps
Service Image Host port
frontend hrms-frontend:local ${FRONTEND_PORT:-80}
backend-api hrms-backend:local (internal)
ats-engine hrms-ats-engine:local (internal)
redis redis:7-alpine (internal)
postgres hrms-postgres:local (internal)
Taskiq workers / schedulers hrms-backend:local (internal)

Browser → http://<host>/ → nginx (same-origin) → backend-api:8000. CV files live in the attachments-data named volume (shared by API + workers).

Schema / migrations (automatic)

On every backend-api start (docker compose up -d --build):

  1. Fresh empty Postgres → create all tables from models and stamp a marker.
  2. Otherwise → alembic upgrade head if any revision files exist in the image (they normally do not — versions stay gitignored and are excluded from builds).
  3. If DB_AUTOGENERATE=true (Compose default) → detect ORM drift (new/changed/removed columns or tables) and apply DDL in-memory — no versions/*.py is written on the server.
  4. Apply any pending backend/migrations/manual/*.sql (seed/RBAC batches only).

Revision scripts under backend/migrations/versions/ remain gitignored and are listed in .dockerignore so they never ship in the production image.

Toggle with root .env: DB_AUTO_MIGRATE / DB_AUTOGENERATE (default true).

Verify

docker compose config
curl -sf http://127.0.0.1/health          # nginx → backend /health
curl -sf -o /dev/null -w "%{http_code}\n" http://127.0.0.1/
docker compose logs -f backend-api

Open the SPA, sign in, confirm /jobs lists requisitions (Network: /jobs/fetch same-origin JSON, not HTML).

Secrets

  • Never bake .env into images (.dockerignore already excludes them).
  • Require a strong DB_PASSWORD and JWT_SECRET_KEY before any real deploy.
  • Root .env is for Compose substitution; backend/.env is for the app process.

TLS

This stack serves HTTP on the frontend port. Terminate TLS at a reverse proxy or cloud load balancer in front of port 80.

Local development (host Postgres)

Restores published ports, bind-mounted attachments, and --reload:

docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build
Override Value
DB_HOST host.docker.internal
Frontend ${FRONTEND_PORT:-5173}
API ${BACKEND_PORT:-8000}
ATS ${ATS_PORT:-8100}
Redis ${REDIS_PORT:-6379}
Attachments ./backend/inbox/decoded_attachments

Container Postgres still starts (production default) but is unused while DB_HOST=host.docker.internal. Host Postgres must accept Docker-bridge clients (listen_addresses = '*', pg_hba for the bridge subnet).

For the Vite HMR loop, run npm run dev on the host against frontend/.env.development (VITE_API_BASE=http://127.0.0.1:8000).

Data migration

The Compose Postgres volume starts empty. To move an existing host database:

pg_dump -Fc hrms > hrms.dump
# with postgres published via the dev overlay, or `docker compose exec -T postgres …`
pg_restore -h 127.0.0.1 -p 5433 -U postgres -d hrms --clean --if-exists hrms.dump

Useful commands

docker compose logs -f backend-api
docker compose logs -f taskiq-worker
docker compose restart backend-api
docker compose down                 # keep volumes
docker compose down -v              # wipe postgres + attachments + redis data