282 lines
9.5 KiB
Markdown
282 lines
9.5 KiB
Markdown
## 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.
|
|
|
|
Uploaded assets handled by the API, including vehicle photos and company branding images, are stored in the named Docker volume `api_uploads_dev` at `/var/lib/rentaldrivego/storage` inside the container. They stay available across normal container rebuilds and 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 <repo-url> 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.
|
|
|
|
Uploaded assets handled by the API, including vehicle photos and company branding images, are persisted in the named Docker volume `api_uploads`, mounted inside the API container at `/var/lib/rentaldrivego/storage`. Rebuilding or redeploying the API no longer clears those files as long as that volume is kept.
|
|
|
|
#### 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 <service>
|
|
# 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
|
|
```
|