From 2adb03ff33b60be3d82021244e13e8a903cfb54f Mon Sep 17 00:00:00 2001 From: "Vaka.pro" Date: Sat, 25 Apr 2026 17:25:28 +0300 Subject: [PATCH] chore: use shared postgres for family wishlist --- .env.example | 14 ++++++++------ README.md | 26 ++++++++++++++++++-------- docker-compose.dev.yml | 7 ++++--- docker-compose.yml | 37 ++++++++++++++----------------------- docker/nginx.conf | 4 ++-- 5 files changed, 46 insertions(+), 42 deletions(-) diff --git a/.env.example b/.env.example index 778aced..e3fb466 100644 --- a/.env.example +++ b/.env.example @@ -1,12 +1,14 @@ # ========================================== # Database # ========================================== -POSTGRES_USER=wishlist -POSTGRES_PASSWORD=change_me -POSTGRES_DB=family_wishlist -# DATABASE_URL uses the docker-compose service name `postgres`. -# When running backend outside docker against docker-postgres use localhost:5432. -DATABASE_URL=postgresql://wishlist:change_me@postgres:5432/family_wishlist +DB_HOST=postgres_budget +DB_PORT=5432 +DB_NAME=db_family +DB_USER= +DB_PASSWORD= +# Fill DATABASE_URL explicitly; .env files do not expand ${...} automatically for the app. +# For local host-based development, point it to localhost:5432 instead of postgres_budget. +DATABASE_URL=postgresql://:@postgres_budget:5432/db_family # ========================================== # Users (two fixed accounts) diff --git a/README.md b/README.md index 92a936d..c826f1f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A small, private wishlist app for two users. Each user has their own profile, sl - **Backend**: Node.js 20, Fastify 4, Prisma 5, PostgreSQL 16 - **Frontend**: React 18, Vite 5, Tailwind CSS, TanStack Query, React Hook Form + Zod - **Monorepo**: pnpm workspaces -- **Deploy**: Docker Compose (Postgres + backend + nginx-served frontend) +- **Deploy**: Docker Compose (shared Postgres + backend + nginx-served frontend) --- @@ -32,7 +32,7 @@ apps/ packages/ shared/ zod schemas + DTO types shared between backend and frontend docker/ Dockerfiles + nginx.conf -docker-compose.yml prod stack (postgres + backend + frontend) +docker-compose.yml prod stack (shared postgres + backend + frontend) docker-compose.dev.yml dev helper (postgres only) .env.example full env template ``` @@ -127,10 +127,11 @@ Review the rest of `.env`: - `USER1_USERNAME`, `USER1_SLUG`, `USER1_DISPLAY_NAME` - `USER2_USERNAME`, `USER2_SLUG`, `USER2_DISPLAY_NAME` -- `POSTGRES_*` (used by Docker) +- `DB_HOST=postgres_budget`, `DB_PORT=5432`, `DB_NAME=db_family` +- `DB_USER`, `DB_PASSWORD`, `DATABASE_URL` (sensitive values stay only in `.env`) - `PUBLIC_APP_URL` (used for CORS in production) -### 3. Run everything via Docker +### 3. Run the shared Docker stack ```bash docker compose up --build @@ -139,12 +140,18 @@ docker compose up --build Opens: - Frontend: http://localhost:8080 -- Backend API: http://localhost:8080/api (proxied by nginx) or http://localhost:3000 if you map `backend` -- Postgres: internal only +- Backend API: http://localhost:8080/api (proxied by nginx) or http://localhost:3000 if you map `family-wishlist-backend` + +Before first start, create a dedicated database and user for this project in the existing Postgres host: + +- host: `postgres_budget` +- port: `5432` +- database: `db_family` +- user/password: set only in `.env` and do not commit them On first start, the backend: -1. Runs `prisma db push` against the Postgres service (creates tables from `schema.prisma`; idempotent). +1. Runs `prisma db push` against the configured shared Postgres database (creates tables from `schema.prisma`; idempotent). 2. Seeds/upserts both users from env (public fields only — password hash stays in env). 3. Starts Fastify on port 3000. 4. Registers the daily trash-purge cron (runs at 03:17 UTC, also once on startup). @@ -159,7 +166,7 @@ Run Postgres in a container, apps on the host: ```bash docker compose -f docker-compose.dev.yml up -d # Override DATABASE_URL to point to localhost: -# DATABASE_URL=postgresql://wishlist:change_me@localhost:5432/family_wishlist +# DATABASE_URL=postgresql://:@localhost:5432/db_family pnpm --filter @family-wishlist/backend prisma:push # apply schema (first time and on schema changes) pnpm --filter @family-wishlist/backend seed # upsert two users from env into DB @@ -170,6 +177,9 @@ This starts both apps in parallel: - Frontend: http://localhost:5173 (proxying `/api` and `/uploads` to http://localhost:3000) - Backend: http://localhost:3000 +- Dev Postgres: `localhost:5432` for local-only development data + +The dev compose file stays isolated from the shared `postgres_budget` instance. Keep production credentials and local credentials in `.env`, and never hardcode them in compose files or source code. ### 5. Useful scripts diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 861fe11..d018846 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,11 +1,12 @@ services: postgres: image: postgres:16-alpine + container_name: family-wishlist-postgres-dev restart: unless-stopped environment: - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${DB_USER} + POSTGRES_PASSWORD: ${DB_PASSWORD} + POSTGRES_DB: ${DB_NAME} ports: - "5432:5432" volumes: diff --git a/docker-compose.yml b/docker-compose.yml index b3ef795..bed20f8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,33 +1,16 @@ services: - postgres: - image: postgres:16-alpine - restart: unless-stopped - environment: - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB} - volumes: - - pgdata:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] - interval: 10s - timeout: 5s - retries: 10 - - backend: + family-wishlist-backend: build: context: . dockerfile: docker/backend.Dockerfile + container_name: family-wishlist-backend restart: unless-stopped env_file: .env environment: NODE_ENV: production UPLOADS_DIR: /app/apps/backend/uploads BACKEND_PORT: 3000 - DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} - depends_on: - postgres: - condition: service_healthy + DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} volumes: - uploads:/app/apps/backend/uploads healthcheck: @@ -42,18 +25,26 @@ services: timeout: 5s retries: 5 start_period: 20s + networks: + - postgres_default frontend: build: context: . dockerfile: docker/frontend.Dockerfile + container_name: family-wishlist-frontend restart: unless-stopped depends_on: - backend: - condition: service_started + family-wishlist-backend: + condition: service_healthy ports: - "8080:80" + networks: + - postgres_default volumes: - pgdata: uploads: + +networks: + postgres_default: + external: true diff --git a/docker/nginx.conf b/docker/nginx.conf index 440382d..9fe37e4 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -13,7 +13,7 @@ server { # API proxy location /api/ { - proxy_pass http://backend:3000/api/; + proxy_pass http://family-wishlist-backend:3000/api/; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -25,7 +25,7 @@ server { # Uploaded files (images) location /uploads/ { - proxy_pass http://backend:3000/uploads/; + proxy_pass http://family-wishlist-backend:3000/uploads/; proxy_http_version 1.1; proxy_set_header Host $host; proxy_cache_valid 200 1h;