Restructure the repo into a pnpm + Turborepo monorepo: - apps/web: Nuxt 4 site, now server-rendered and reading all content from the API; pages cached with SWR and purged on content changes - apps/api: NestJS 12 + Prisma 7 + PostgreSQL. Auth with short-lived access tokens and rotating httpOnly refresh cookies, roles (ADMIN, EDITOR), catalog, editable site sections, media upload to S3-compatible storage (converted to WebP), contact messages, audit log - apps/admin: Vue 3 admin panel (Ant Design Vue, Pinia, Tailwind) for products, categories, site sections, messages, media and users - packages/shared: Zod schemas and types shared by API and admin Also: - seed script that loads the original 8 categories / 89 products and section content - Docker images for api (with a one-off migrate service), web, admin, and an nginx gateway for both domains - dev and production compose files, daily database backup service - API e2e tests Removes the committed static out/ build and the old root Dockerfile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
1.8 KiB
Plaintext
59 lines
1.8 KiB
Plaintext
# Front door for the whole stack. Rendered by the nginx image's envsubst at start-up
|
|
# (only ${SITE_DOMAIN}, ${ADMIN_DOMAIN} and ${S3_BUCKET} are replaced; nginx's own $vars stay).
|
|
# TLS is expected to be terminated in front of this container (host nginx / Traefik / CDN).
|
|
|
|
upstream web_upstream { server web:3000; }
|
|
upstream api_upstream { server api:4000; }
|
|
upstream admin_upstream { server admin:80; }
|
|
upstream media_upstream { server minio:9000; }
|
|
|
|
# keep the scheme reported by the TLS proxy in front, if any
|
|
map $http_x_forwarded_proto $forwarded_proto {
|
|
default $http_x_forwarded_proto;
|
|
"" $scheme;
|
|
}
|
|
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $forwarded_proto;
|
|
|
|
server {
|
|
listen 80;
|
|
server_name ${SITE_DOMAIN} www.${SITE_DOMAIN};
|
|
client_max_body_size 20m;
|
|
|
|
location /api/ { proxy_pass http://api_upstream; }
|
|
|
|
location /media/ {
|
|
proxy_pass http://media_upstream/${S3_BUCKET}/;
|
|
proxy_set_header Host minio:9000;
|
|
proxy_hide_header Set-Cookie;
|
|
}
|
|
|
|
# cache purge endpoint is only for the API (called over the internal network)
|
|
location /_internal/ { return 404; }
|
|
|
|
location / { proxy_pass http://web_upstream; }
|
|
|
|
gzip on;
|
|
gzip_proxied any;
|
|
gzip_types text/css application/javascript application/json application/xml image/svg+xml text/plain;
|
|
}
|
|
|
|
server {
|
|
listen 80;
|
|
server_name ${ADMIN_DOMAIN};
|
|
client_max_body_size 20m;
|
|
add_header X-Robots-Tag "noindex, nofollow" always;
|
|
|
|
location /api/ { proxy_pass http://api_upstream; }
|
|
|
|
location /media/ {
|
|
proxy_pass http://media_upstream/${S3_BUCKET}/;
|
|
proxy_set_header Host minio:9000;
|
|
}
|
|
|
|
location / { proxy_pass http://admin_upstream; }
|
|
}
|