## Docker Environments Three Docker environments are available: - `Dockerfile.dev` with `docker-compose.dev.yml` - `Dockerfile.test` with `docker-compose.test.yml` - `Dockerfile.production` with `docker-compose.production.yml` - `docker-compose.pgmanage.yml` for a standalone pgManage container ### Development Use the full dev stack for local work with hot reload and bundled Postgres and Redis: ```bash docker compose -f docker-compose.dev.yml --profile full up --build ``` Services: - marketplace: `http://localhost:3000` - dashboard: `http://localhost:3001` - admin: `http://localhost:3002` - public-site: `http://localhost:3003` - api: `http://localhost:4000` - pgAdmin: `http://localhost:5050` Each dev app now runs in its own container and can be started independently with a profile tag: ```bash docker compose -f docker-compose.dev.yml --profile api up --build docker compose -f docker-compose.dev.yml --profile marketplace up --build docker compose -f docker-compose.dev.yml --profile dashboard up --build docker compose -f docker-compose.dev.yml --profile admin up --build docker compose -f docker-compose.dev.yml --profile public-site up --build docker compose -f docker-compose.dev.yml --profile tools up --build ``` Notes: - `api` starts `postgres`, `redis`, and `migrate` automatically through dependencies. - frontend profiles also start `api` and its dependencies automatically. - `tools` starts only `pgadmin` plus its required `postgres` dependency. On startup, Docker now waits for Postgres to become healthy, runs a one-shot `migrate` service, and only then starts the selected app container. For development, that bootstrap runs `db:generate` every time, but `db:deploy` and `db:seed` only the first time for a persisted dev database, so your local data survives rebuilds and normal restarts. Default dev platform administrator: - email: `admin@rentaldrivego.com` - password: `changeme123` If you intentionally want a fresh dev bootstrap: ```bash docker compose -f docker-compose.dev.yml down -v ``` If you want to keep the database and only apply new schema changes manually: ```bash docker compose -f docker-compose.dev.yml run --rm migrate sh -c "npm run db:deploy" ``` pgAdmin dev login: - email: `admin@rentaldrivego.local` - email: `admin@rentaldrivego.dev` - password: `admin` pgAdmin opens with the dev Postgres server pre-registered as `RentalDriveGo Dev DB`. pgAdmin Postgres connection: - host: `postgres` - port: `5432` - database: `rentaldrivego` - username: `postgres` - password: `password` ### Standalone pgManage If you want a standalone Postgres management UI without starting the full development stack: ```bash docker compose -f docker-compose.pgmanage.yml up -d ``` It publishes `http://localhost:8000` with a standard Docker port mapping and persists its data in the named Docker volume `pgmanage_data`. From inside the container, connect to the local Postgres service through `host.docker.internal:5432`. ### Test Use the test stack to run repeatable containerized verification: ```bash docker compose -f docker-compose.test.yml up --build --abort-on-container-exit ``` The test container runs: - `npm run db:deploy` - `npm run db:generate` - `npm run type-check` - `npm run build` ### Production The production stack runs behind **Traefik** (reverse proxy + automatic HTTPS via Let's Encrypt). All services communicate over a private Docker network (`internal`). Traefik reaches public-facing services via a separate `traefik-proxy` network. #### 1. Point DNS to your server Add an A record for every subdomain to your server's public IP before deploying so Let's Encrypt can issue certificates: | Subdomain | Service | |---|---| | `rentaldrivego.ma` | marketplace and public site | | `api.rentaldrivego.ma` | API | | `pgmanage.rentaldrivego.ma` | pgManage (DB admin) | #### 2. Install Docker and clone the repo ```bash # Install Docker (if not already installed) curl -fsSL https://get.docker.com | sh git clone rentaldrivego cd rentaldrivego ``` #### 3. Create the shared Traefik network Only needs to be done once per server. If it already exists this is a no-op. ```bash docker network create traefik-proxy ``` #### 4. Configure environment variables ```bash cp .env.docker.production.example .env.docker.production ``` Open `.env.docker.production` and fill in every value. The minimum required secrets are: | Variable | What to set | |---|---| | `POSTGRES_PASSWORD` | Strong random password | | `JWT_SECRET` | Long random string (e.g. `openssl rand -hex 64`) | | `ACME_EMAIL` | Your email for Let's Encrypt notifications | | `RESEND_API_KEY` | Resend API key (or configure SMTP vars instead) | Production now derives `DATABASE_URL` inside the app container from `POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_DB`, `POSTGRES_USER`, and `POSTGRES_PASSWORD` when `DATABASE_URL_FROM_POSTGRES=true`. That avoids Prisma auth failures when the database password contains reserved URL characters such as `@`, `:`, or `/`. The example file uses `rentaldrivego.ma` for the marketplace and public site. The dashboard and admin panel are routed under that same host at `/dashboard` and `/admin`. #### 5. Start Traefik Traefik must be running before the app stack so it can wire up routes at startup. ```bash docker compose -f traefik.yaml up -d ``` #### 6. Build and start the app stack ```bash npm run docker:prod:up ``` Or use the new helper scripts if you want to start one production container at a time: ```bash npm run docker:prod:start:traefik npm run docker:prod:start:postgres npm run docker:prod:start:redis npm run docker:prod:start:api npm run docker:prod:start:marketplace npm run docker:prod:start:dashboard npm run docker:prod:start:admin npm run docker:prod:start:frontends npm run docker:prod:start:pgmanage npm run docker:prod:start:all ``` Docker will: 1. Build the monorepo image 2. Start all app services (`api`, `marketplace`, `dashboard`, `admin`, `pgmanage`) Traefik automatically picks up the containers and provisions TLS certificates. Services are live at their `https://` URLs within ~30 seconds. #### Updating after a code change Pull the latest code and rebuild only the changed service: ```bash git pull docker compose -p rentaldrivego-prod --env-file .env.docker.production -f docker-compose.production.yml up --build -d --no-deps # e.g. to redeploy only the API: docker compose -p rentaldrivego-prod --env-file .env.docker.production -f docker-compose.production.yml up --build -d --no-deps api ``` To rebuild everything: ```bash npm run docker:prod:up ``` #### Apply database migrations without downtime ```bash docker compose -p rentaldrivego-prod --env-file .env.docker.production -f docker-compose.production.yml run --rm api npm run db:deploy ``` #### Create the first production admin The repo includes a seed that creates the first `SUPER_ADMIN` if that email does not already exist. ```bash docker compose -p rentaldrivego-prod --env-file .env.docker.production -f docker-compose.production.yml run --rm \ -e ADMIN_SEED_EMAIL=rentaldrivego@gmail.com \ -e ADMIN_SEED_PASSWORD='Qwerty00!@#$%' \ -e ADMIN_SEED_FIRST_NAME=Super \ -e ADMIN_SEED_LAST_NAME=Admin \ api npm run db:seed:admin ``` Then sign in at `https://rentaldrivego.ma/admin/login` and create any additional admin users from the admin panel. #### View logs ```bash # All services npm run docker:prod:logs # Single service npm run docker:prod:logs:api ``` #### Stop the stack ```bash # Stop containers but keep volumes (data is preserved) npm run docker:prod:down # Stop and delete all data (destructive — irreversible) docker compose -p rentaldrivego-prod --env-file .env.docker.production -f docker-compose.production.yml down -v ``` #### pgManage (DB admin UI) pgManage is available at `https://pgmanage.rentaldrivego.ma`. To connect to the production database, add a connection inside pgManage with: - **Host:** `localhost` - **Port:** `5432` - **Database:** `rentaldrivego` - **Username:** `postgres` - **Password:** value of `POSTGRES_PASSWORD` from `.env.docker.production` ### Notes - The production image builds the whole monorepo once, then each service overrides its runtime command. - The dev compose file bind-mounts the repo and keeps `node_modules` in a named volume. - `API_INTERNAL_URL` is used for server-side container-to-container calls, while `NEXT_PUBLIC_API_URL` is used by the browser. - The Dockerfiles activate the repo's pinned `npm@10.5.0` with `corepack` before install so container builds do not depend on the npm version bundled with the base image. - The dev compose stack stores Postgres data in `postgres_dev_data` and the bootstrap marker in `postgres_bootstrap_state`, so `up --build` does not reseed an existing local database. - If you need database schema updates inside Docker, run: ```bash docker compose -f docker-compose.dev.yml run --rm migrate ``` If a cached base image still fails during `npm ci`, refresh it and rebuild without cache: ```bash docker pull node:20-bookworm docker compose -f docker-compose.dev.yml build --no-cache dashboard ```