198 lines
6.0 KiB
Markdown
198 lines
6.0 KiB
Markdown
# Deployment
|
|
|
|
## Environments
|
|
|
|
- development
|
|
- test/CI
|
|
- production
|
|
|
|
## Docker Compose
|
|
|
|
Baseline services:
|
|
- frontend
|
|
- API
|
|
- worker
|
|
- PostgreSQL
|
|
- Redis
|
|
- reverse proxy
|
|
|
|
Persistent data:
|
|
- PostgreSQL data
|
|
- Redis data where needed
|
|
- image storage
|
|
|
|
## Production Compose
|
|
|
|
The repository includes `compose.production.yaml` with separate API, worker,
|
|
web, PostgreSQL, and Redis services. It exposes only the Nginx web service and
|
|
keeps database and Redis ports internal to the Compose network.
|
|
|
|
Before starting, create a production `.env` containing real values for
|
|
`POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `DATABASE_URL`,
|
|
`REDIS_URL`, `SMTP_URL`, `SMTP_FROM`, and a stable base64-encoded 32-byte
|
|
`MFA_ENCRYPTION_KEY`. Set `PRICING_HTTP_PROVIDER_ENDPOINT` to the approved
|
|
provider's HTTPS endpoint and provide its token through
|
|
`PRICING_HTTP_PROVIDER_TOKEN` when required. Production startup rejects the
|
|
fixture provider, missing endpoints, and non-HTTPS endpoints.
|
|
|
|
Start the stack and apply migrations with:
|
|
|
|
```sh
|
|
docker compose -f compose.production.yaml up -d --build postgres redis
|
|
docker compose -f compose.production.yaml run --rm api npm run db:migrate
|
|
docker compose -f compose.production.yaml up -d --build api worker web
|
|
```
|
|
|
|
The default web port is `8080` and can be changed with `WEB_PORT`. The API and
|
|
worker images share the same Node workspace image; the web image builds the Vue
|
|
application and serves it through Nginx with SPA fallback and internal `/api`
|
|
proxying.
|
|
|
|
API and worker share the persistent `image-storage` volume at
|
|
`/var/lib/pokemon-inventory/images`. Set `IMAGE_STORAGE_VOLUME` to a NAS bind
|
|
mount when deploying outside Docker-managed volumes, for example:
|
|
|
|
```env
|
|
IMAGE_STORAGE_VOLUME=/volume1/docker/pokemon-inventory/images
|
|
```
|
|
|
|
Include this directory in image-storage backups alongside PostgreSQL dumps.
|
|
|
|
## Tagged Releases And Rollback
|
|
|
|
Use an immutable release tag for every deployment. The production Compose file
|
|
uses `IMAGE_TAG` to select matching API, worker, and web images. Deploy with:
|
|
|
|
```sh
|
|
RELEASE_TAG=2026-09-09-01 ./scripts/deploy-production.sh
|
|
```
|
|
|
|
The deploy script builds the three tagged images, starts healthy data services,
|
|
applies migrations with the tagged API image, and then switches the application
|
|
services. Keep the previous release tag and migration state with the deployment
|
|
record.
|
|
|
|
Rollback application images with:
|
|
|
|
```sh
|
|
RELEASE_TAG=2026-09-08-02 ./scripts/rollback-production.sh
|
|
```
|
|
|
|
Image rollback is safe only when the previous image understands the current
|
|
database schema. If the release included an incompatible schema change, restore
|
|
the matching PostgreSQL backup before starting the previous images. Always
|
|
verify the API and web health checks after a rollback.
|
|
|
|
Run the post-deploy smoke check against the public endpoints:
|
|
|
|
```sh
|
|
WEB_BASE_URL=http://localhost:8080 \
|
|
./scripts/smoke-production.sh
|
|
```
|
|
|
|
The check performs read-only requests against API health, the web health path,
|
|
and public search. Without `API_HEALTH_URL`, the API check runs inside the
|
|
Compose API container, which is appropriate because the production API port is
|
|
not exposed publicly. It exits nonzero on the first failed request. Both deploy
|
|
and rollback scripts run this check after changing application services.
|
|
|
|
## Health Checks
|
|
|
|
Production Compose waits for healthy PostgreSQL, Redis, and API services before
|
|
starting the web service. The API health endpoint is `GET /health`; the web
|
|
container checks its `/health` response through Nginx.
|
|
|
|
## Backup And Restore
|
|
|
|
Create a PostgreSQL custom-format dump from the running production stack:
|
|
|
|
```sh
|
|
BACKUP_DIR=/secure/backups \
|
|
POSTGRES_DB=inventory \
|
|
POSTGRES_USER=inventory \
|
|
POSTGRES_PASSWORD='use-secret-storage' \
|
|
./scripts/backup-postgres.sh
|
|
```
|
|
|
|
Restore only during a planned maintenance window because `pg_restore` replaces
|
|
matching database objects:
|
|
|
|
```sh
|
|
BACKUP_FILE=/secure/backups/inventory-20260909T000000Z.dump \
|
|
POSTGRES_DB=inventory \
|
|
POSTGRES_USER=inventory \
|
|
POSTGRES_PASSWORD='use-secret-storage' \
|
|
./scripts/restore-postgres.sh
|
|
```
|
|
|
|
Verify a dump before scheduling a restore:
|
|
|
|
```sh
|
|
BACKUP_FILE=/secure/backups/inventory-20260909T000000Z.dump \
|
|
./scripts/verify-postgres-backup.sh
|
|
```
|
|
|
|
This checks that the file is a readable PostgreSQL custom-format archive without
|
|
changing any database.
|
|
|
|
Restore a database dump during a scheduled window:
|
|
|
|
```sh
|
|
BACKUP_FILE=/secure/backups/inventory-20260909T000000Z.dump \
|
|
POSTGRES_DB=inventory \
|
|
POSTGRES_USER=inventory \
|
|
POSTGRES_PASSWORD='use-secret-storage' \
|
|
./scripts/restore-postgres.sh
|
|
```
|
|
|
|
Restore image storage snapshots using the preserved NAS backup:
|
|
|
|
```sh
|
|
IMAGE_STORAGE_SOURCE=/secure/backups/pokemon-inventory-images \
|
|
IMAGE_STORAGE_DESTINATION=/var/lib/pokemon-inventory/images \
|
|
./scripts/restore-image-storage.sh
|
|
```
|
|
|
|
Back up image storage and the deployment `.env` through the NAS secret/backup
|
|
system as well. Never commit either one. Before upgrading, record the current
|
|
image tags and database migration state. To roll back, stop the application
|
|
services, restore the previous image tags, restore the database dump if the
|
|
schema changed, then restore the image snapshot and verify `/health` and a
|
|
read-only catalog request.
|
|
|
|
## Reverse proxy
|
|
|
|
Responsible for:
|
|
- HTTPS/TLS
|
|
- routing
|
|
- compression
|
|
- security headers
|
|
- rate limiting where appropriate
|
|
|
|
## Configuration
|
|
|
|
Environment variables/secrets:
|
|
- database connection
|
|
- Redis connection
|
|
- authentication/session secrets
|
|
- provider credentials
|
|
- email credentials
|
|
- storage credentials
|
|
|
|
Application settings such as pricing strategy and site settings belong in the database.
|
|
|
|
## Backups
|
|
|
|
Back up:
|
|
- PostgreSQL
|
|
- image storage
|
|
- required environment/configuration information
|
|
|
|
Retention policy and restore procedures must be documented for production.
|
|
|
|
Disaster recovery should allow reconstruction elsewhere from database backup, image backup, and deployment/environment configuration.
|
|
|
|
## Future hosting
|
|
|
|
Initial deployment targets a home server/NAS. The architecture should allow later movement to an online server or managed infrastructure without redesigning the domain model.
|