Files
SBC/docker-compose.yml
T
Claude 96dca2a802 Application complète SLUC Business Club (React + Express + PostgreSQL, Docker)
Implémente l'intégralité de la maquette « SLUC Business Club.dc.html » :
- Site public : accueil (héro administrable, carrousel membres, agenda avec
  inscription en ligne, rencontres passées, demande d'adhésion), annuaire
  avec recherche/filtres/fiche détaillée, page association
- Espace membre : connexion, édition de fiche avec aperçu direct, upload
  logo/photo, statut d'adhésion par saison, changement de mot de passe
- Espace admin : tableau de bord, membres (validation par saison),
  rencontres (CRUD + inscrits + impression + export Excel), inscriptions,
  catégories, contenu du site

Architecture : 3 conteneurs Docker Compose — PostgreSQL 16 (réseau interne,
rôle applicatif restreint), API Express (non-root, read-only fs), nginx
non privilégié (frontend React + reverse-proxy + CSP stricte).

Sécurité : requêtes 100 % paramétrées, bcrypt + JWT httpOnly SameSite=Strict,
vérification d'Origin (CSRF), validation zod, rate limiting, uploads vérifiés
par octets magiques avec noms aléatoires, aucun secret committé.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fkg15RCxNgUys4ru73He2o
2026-07-10 19:43:07 +00:00

78 lines
1.9 KiB
YAML

name: sluc-business-club
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: sbc
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
APP_DB_PASSWORD: ${APP_DB_PASSWORD:?set APP_DB_PASSWORD in .env}
volumes:
- db_data:/var/lib/postgresql/data
- ./db/init:/docker-entrypoint-initdb.d:ro
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d sbc"]
interval: 5s
timeout: 3s
retries: 12
# No published ports: the database is reachable only from the backend network.
api:
build: ./server
restart: unless-stopped
environment:
NODE_ENV: production
PORT: "3000"
DATABASE_URL: postgres://sbc_app:${APP_DB_PASSWORD}@db:5432/sbc
JWT_SECRET: ${JWT_SECRET:?set JWT_SECRET in .env}
ADMIN_INITIAL_PASSWORD: ${ADMIN_INITIAL_PASSWORD:-}
MEMBER_INITIAL_PASSWORD: ${MEMBER_INITIAL_PASSWORD:-}
COOKIE_SECURE: ${COOKIE_SECURE:-false}
UPLOAD_DIR: /data/uploads
volumes:
- uploads:/data/uploads
depends_on:
db:
condition: service_healthy
networks:
- backend
- frontend
read_only: true
tmpfs:
- /tmp
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
interval: 10s
timeout: 5s
retries: 6
web:
build: ./web
restart: unless-stopped
ports:
- "${WEB_PORT:-8080}:8080"
volumes:
- uploads:/var/www/uploads:ro
depends_on:
- api
networks:
- frontend
security_opt:
- no-new-privileges:true
networks:
backend:
# internal: the db network never routes to the outside world
internal: true
frontend:
volumes:
db_data:
uploads: