diff --git a/README.md b/README.md index 71264c6d..79db28a5 100644 --- a/README.md +++ b/README.md @@ -188,3 +188,64 @@ To contribute: - Include a **deployment section (Docker / CI)** - Write a **more enterprise-focused version** for internal tools + +## Quickstart with Docker + +The fastest way to get the backend running locally with a matching Postgres 16 and Redis 7 (same versions as CI) is via Docker Compose. + +### Prerequisites + +- Docker and Docker Compose installed + +### Run it + +```bash +git clone +cd AssetsUp +docker compose up +``` + +This brings up three containers: + +| Service | Description | Port | +| ---------- | --------------------------------------- | ---- | +| `postgres` | Postgres 16, data persisted in a volume | 5432 | +| `redis` | Redis 7, data persisted in a volume | 6379 | +| `backend` | NestJS API in watch mode (`start:dev`) | 3000 | + +No manual Postgres/Redis install or configuration is required — the backend +container is pre-wired with the same env var names used in +`.github/workflows/backend-ci.yml` (`DB_HOST`, `DB_PORT`, `DB_USERNAME`, +`DB_PASSWORD`, `DB_NAME`, `REDIS_HOST`, `REDIS_PORT`, `JWT_SECRET`). + +The API will be available at `http://localhost:3000` once all three +containers report healthy. + +### Overriding defaults + +Create a `.env` file at the repo root to override any default credentials +before running `docker compose up`: + +```bash +DB_USERNAME=postgres +DB_PASSWORD=postgrespassword +DB_NAME=assetsup_dev +JWT_SECRET=dev-secret-key +``` + +### Stopping / resetting + +```bash +docker compose down # stop containers, keep data +docker compose down -v # stop containers and wipe Postgres/Redis volumes +``` + +### Building a production image + +The backend `Dockerfile` is multi-stage. `docker compose up` builds the +`development` target (hot reload). To build the production image used for +deployment: + +```bash +docker build --target production -t assetsup-backend ./backend +``` diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 00000000..99c291db --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,16 @@ +node_modules +npm-debug.log +dist +coverage +.git +.gitignore +.env +.env.* +!.env.example +.vscode +.idea +*.md +Dockerfile +.dockerignore +docker-compose.yml +.github \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 00000000..acbeec40 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,35 @@ +# syntax=docker/dockerfile:1 + +# ---------- Base ---------- +FROM node:20-alpine AS base +WORKDIR /app +COPY package*.json ./ + +# ---------- Development ---------- +# Used by docker-compose for local dev (hot reload via `npm run start:dev`) +FROM base AS development +ENV NODE_ENV=development +RUN npm ci +COPY . . +EXPOSE 3000 +CMD ["npm", "run", "start:dev"] + +# ---------- Production dependencies ---------- +FROM base AS dependencies +RUN npm ci --omit=dev + +# ---------- Build ---------- +FROM base AS build +RUN npm ci +COPY . . +RUN npm run build + +# ---------- Production ---------- +FROM node:20-alpine AS production +WORKDIR /app +ENV NODE_ENV=production +COPY --from=dependencies /app/node_modules ./node_modules +COPY --from=build /app/dist ./dist +COPY package*.json ./ +EXPOSE 3000 +CMD ["node", "dist/main.js"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..f48a378c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3.9" + +services: + postgres: + image: postgres:16-alpine + container_name: assetsup_postgres + restart: unless-stopped + environment: + POSTGRES_USER: ${DB_USERNAME:-postgres} + POSTGRES_PASSWORD: ${DB_PASSWORD:-postgrespassword} + POSTGRES_DB: ${DB_NAME:-assetsup_dev} + ports: + - "${DB_PORT:-5432}:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME:-postgres}"] + interval: 10s + timeout: 5s + retries: 5 + + redis: + image: redis:7-alpine + container_name: assetsup_redis + restart: unless-stopped + ports: + - "${REDIS_PORT:-6379}:6379" + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + + backend: + build: + context: ./backend + dockerfile: Dockerfile + target: development + container_name: assetsup_backend + restart: unless-stopped + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + environment: + NODE_ENV: development + DB_HOST: postgres + DB_PORT: 5432 + DB_USERNAME: ${DB_USERNAME:-postgres} + DB_PASSWORD: ${DB_PASSWORD:-postgrespassword} + DB_NAME: ${DB_NAME:-assetsup_dev} + REDIS_HOST: redis + REDIS_PORT: 6379 + JWT_SECRET: ${JWT_SECRET:-dev-secret-key} + ports: + - "3000:3000" + volumes: + - ./backend:/app + - /app/node_modules + command: npm run start:dev + +volumes: + postgres_data: + redis_data: