Files
hedena_gold/docker-compose.yml
T
s.esmaeiliandClaude Sonnet 5 2b6795d007 api: fix migration runner, serve uploads correctly, add product photos
Three real bugs found and fixed while wiring up product images end-to-end:

1. src/prisma/migrate.ts only discovered flat prisma/migrations/<name>.sql
   files, never Prisma's own folder-per-migration layout
   (<timestamp>_<name>/migration.sql). Every migration created the normal
   way (via 'prisma migrate dev') was silently skipped; only a hand-added
   flat duplicate (prisma/migrations/0001_init.sql, now removed) ever ran.
   This meant schema.prisma had drifted well ahead of what any real deploy
   database actually had (missing columns on City, Customer, Branch,
   Product, several new tables). Fixed to discover both layouts; the
   drift is closed with a new 20260914165255_sync_schema_drift migration.

2. Neither nginx.conf (production) nor vite.config.ts (dev) proxied
   /uploads/ to the API — only /api/. UploadedFile/ProductImage URLs
   (/uploads/<file>, served by main.ts's useStaticAssets OUTSIDE the /api
   prefix) 404'd through both. Both now proxy /uploads/ the same way /api/
   already was.

3. docker-compose.yml's api service had no volume for storage/uploads, so
   every uploaded file — and by extension every ProductImage row pointing
   at one — was lost on the next container recreate/redeploy. Added a
   named volume.

Also: main.ts's static file serving now sets Content-Type: image/avif
explicitly (serve-static's bundled mime table predates .avif and served it
as application/octet-stream; browsers rendered it anyway by sniffing, but
a stricter client would not have).

Product photos: copied 15 real jewelry photos into the uploads volume,
registered them as UploadedFile rows, and assigned each of the 5 existing
Product rows a randomly picked one (duplicates allowed, per request),
replacing their /img/no-items.png placeholder ProductImage row. Verified
end-to-end in a real browser against the real containerized API+DB: logged
in, opened the admin product list, confirmed all 5 rows render their photo
(naturalWidth/Height populated, network 200s, no console errors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 20:56:17 +03:30

78 lines
2.2 KiB
YAML

version: '3.8'
services:
db:
image: docker.arvancloud.ir/postgres:15-alpine
container_name: goldbank_db
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
POSTGRES_DB: ${POSTGRES_DB:-goldbank}
ports:
- "${EXTERNAL_DB_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-goldbank}"]
interval: 5s
timeout: 5s
retries: 12
api:
build:
context: ./apps/api
dockerfile: Dockerfile
container_name: goldbank_api
# Prisma connects on module init, so a not-yet-ready DB crash-loops the API.
depends_on:
db:
condition: service_healthy
environment:
- DATABASE_URL=${DATABASE_URL:-postgresql://postgres:postgres@db:5432/goldbank?schema=public}
- PORT=${PORT:-3000}
# No host ports — Dokploy/Traefik routes by domain to container port 3000
expose:
- "3000"
# Uploaded files (product images, etc.) land in storage/uploads inside the
# container. Without a volume they vanish on every recreate/redeploy, and
# every UploadedFile/ProductImage row created before that would then point
# at a URL that 404s.
volumes:
- api_uploads:/app/storage/uploads
restart: unless-stopped
# The bare name "api" is ambiguous on Dokploy's shared network (other stacks
# register it too), which made nginx dial the wrong containers. Use a unique alias.
networks:
default:
aliases:
- goldbank-api
admin-panel:
build:
context: ./apps/admin-panel
dockerfile: Dockerfile
container_name: goldbank_admin_panel
# No host ports — Dokploy/Traefik routes by domain to container port 80
expose:
- "80"
restart: unless-stopped
depends_on:
- api
user-app:
build:
context: ./apps/user-app
dockerfile: Dockerfile
container_name: goldbank_user_app
# No host ports — Dokploy/Traefik routes by domain to container port 80
expose:
- "80"
restart: unless-stopped
depends_on:
- api
volumes:
postgres_data:
api_uploads: