name: libreshop-demo # Standalone preview of the libreshop toolkit. Brings up cms + cms-db # + mail + pdf + nginx + shop with placeholder values so the stack is # clickable without any adapter. Adapters (e.g. mp) replace this file # with their own composition + branding env. # # Usage: # cp .env.example .env # placeholder values, OK for local # docker compose pull # docker compose up -d # open http://localhost:8080 # # Component versions are pinned to specific releases so the demo is # reproducible across hosts and survives rolling :main churn. # nginx: v0.1.1, cms: v0.1.1, pdf/mail/shop: v0.1.0 services: cms-db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_DB: ${CMS_DB_NAME:-libreshop} POSTGRES_USER: ${CMS_DB_USER:-libreshop} POSTGRES_PASSWORD: ${CMS_DB_PASSWORD:-changeme-in-prod} healthcheck: test: ["CMD", "pg_isready", "-U", "${CMS_DB_USER:-libreshop}"] interval: 10s timeout: 3s retries: 5 volumes: - cms-db-data:/var/lib/postgresql/data networks: - data cms-permissions: image: alpine user: root volumes: - cms-data:/app/public:rw command: | sh -c " addgroup -g 1000 node 2>/dev/null || true && adduser -D -u 1000 -G node node 2>/dev/null || true && mkdir -p /app/public && chown -R node:node /app/public " cms: image: git.librete.ch/libreshop/cms:${LIBRESHOP_CMS_TAG:-v0.1.1} pull_policy: missing restart: unless-stopped environment: NODE_ENV: ${NODE_ENV:-production} DATABASE_HOST: cms-db DATABASE_PORT: 5432 DATABASE_NAME: ${CMS_DB_NAME:-libreshop} DATABASE_USERNAME: ${CMS_DB_USER:-libreshop} DATABASE_PASSWORD: ${CMS_DB_PASSWORD:-changeme-in-prod} DATABASE_CLIENT: postgres DATABASE_SSL: "false" STRAPI_TELEMETRY_DISABLED: "true" STRAPI_DISABLE_UPDATE_NOTIFICATION: "true" STRAPI_HIDE_STARTUP_MESSAGE: "true" BROWSER: "false" JWT_SECRET: ${CMS_JWT_SECRET:-changeme-jwt-secret-32-bytes-min!!!} API_TOKEN_SALT: ${CMS_API_TOKEN_SALT:-changeme-api-token-salt} ADMIN_JWT_SECRET: ${CMS_ADMIN_JWT_SECRET:-changeme-admin-jwt-secret} APP_KEYS: ${CMS_APP_KEYS:-key-a,key-b,key-c,key-d} TRANSFER_TOKEN_SALT: ${CMS_TRANSFER_TOKEN_SALT:-changeme-transfer-salt} PDF_API_ADDRESS: http://pdf:1111 MAIL_API_ADDRESS: http://mail:2222 ADMIN_EMAIL_ADDRESS: ${ADMIN_EMAIL_ADDRESS:-admin@example.invalid} volumes: - cms-data:/app/public:rw networks: - internal - data depends_on: cms-permissions: condition: service_completed_successfully cms-db: condition: service_healthy healthcheck: test: wget --no-verbose --spider -S -T 1 http://cms:5555/_health || exit 1 interval: 30s timeout: 10s retries: 3 start_period: 5m mail: image: git.librete.ch/libreshop/mail:${LIBRESHOP_MAIL_TAG:-v0.1.0} pull_policy: missing restart: unless-stopped environment: ENVIRONMENT: ${ENVIRONMENT:-development} PYTHONUNBUFFERED: "true" # Demo: log mail to stdout instead of relaying. Set the SMTP_RELAY_* # block to send for real. SMTP_RELAY_HOST: ${MAIL_SMTP_RELAY_HOST:-} SMTP_RELAY_PORT: ${MAIL_SMTP_RELAY_PORT:-587} SMTP_RELAY_USERNAME: ${MAIL_SMTP_RELAY_USERNAME:-} SMTP_RELAY_PASSWORD: ${MAIL_SMTP_RELAY_PASSWORD:-} networks: - internal healthcheck: test: wget --no-verbose --spider -S -T 1 http://mail:2222/health || exit 1 interval: 30s timeout: 10s retries: 3 pdf: image: git.librete.ch/libreshop/pdf:${LIBRESHOP_PDF_TAG:-v0.1.0} pull_policy: missing restart: unless-stopped environment: ENVIRONMENT: ${ENVIRONMENT:-development} PYTHONUNBUFFERED: "true" networks: - internal healthcheck: test: wget --no-verbose --spider -S -T 1 http://pdf:1111/health || exit 1 interval: 30s timeout: 10s retries: 3 shop: image: git.librete.ch/libreshop/shop:${LIBRESHOP_SHOP_TAG:-v0.1.0} pull_policy: missing restart: unless-stopped environment: NUXT_SHOP_API_TOKEN: ${SHOP_API_TOKEN:-demo-shop-api-token} NUXT_CMS_INTERNAL_URL: http://cms:5555 NUXT_SITE_URL: ${SHOP_SITE_URL:-http://localhost:8080} NUXT_PUBLIC_BASE_URL: ${SHOP_BASE_URL:-/} NUXT_PUBLIC_PAYMENT_ENVIRONMENT: ${PAYMENT_ENVIRONMENT:-sandbox} NUXT_PUBLIC_PAYPAL_CLIENT_ID: ${PAYPAL_CLIENT_ID:-} networks: - internal depends_on: cms: condition: service_started healthcheck: test: ["CMD", "node", "-e", "fetch('http://localhost:9999/api/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))"] interval: 30s timeout: 10s retries: 3 start_period: 30s nginx: image: git.librete.ch/libreshop/nginx:${LIBRESHOP_NGINX_TAG:-v0.1.1} pull_policy: missing restart: unless-stopped ports: - "${LIBRESHOP_DEMO_PORT:-8080}:80" environment: NGINX_HOST: ${NGINX_HOST:-localhost} depends_on: shop: condition: service_started cms: condition: service_started networks: - internal healthcheck: test: service nginx status || exit 1 interval: 30s timeout: 10s retries: 3 networks: internal: data: volumes: cms-data: cms-db-data: