# Image unique : API FastAPI + WebSocket + PWA, servis sur le port 7860. # Fonctionne en local (`docker run -p 7860:7860 ...`) et comme Space Docker # Hugging Face (tier gratuit : 2 vCPU, 16 Go de RAM, 1 Go sur /data). FROM python:3.11-slim LABEL org.opencontainers.image.title="MSG MOTOC" \ org.opencontainers.image.description="Messagerie de groupe temps réel (PWA) — images en P2P" \ org.opencontainers.image.licenses="MIT" ENV PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ PIP_NO_CACHE_DIR=1 # Hugging Face impose de tourner en uid 1000. RUN useradd -m -u 1000 user WORKDIR /home/user/app COPY --chown=user requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY --chown=user app ./app COPY --chown=user static ./static COPY --chown=user scripts ./scripts # Volume persistant : base SQLite, clés VAPID, secret de signature. # Sur Hugging Face, /data est monté automatiquement si le Space a du stockage ; # sinon on retombe sur ce répertoire, non persistant entre deux redémarrages. RUN mkdir -p /data && chown user:user /data VOLUME ["/data"] USER user # Rétention calée sur la cible réelle : 110 groupes x ~500 messages sur 5 jours # de festival, soit ~27 Mo mesurés (voir scripts/load_test.py). ENV HOST=0.0.0.0 \ PORT=7860 \ DATA_DIR=/data \ APP_NAME="MSG MOTOC" \ KEEP_MESSAGES_PER_GROUP=500 \ RETENTION_DAYS=30 \ SEED_DEMO=1 EXPOSE 7860 HEALTHCHECK --interval=60s --timeout=5s --start-period=15s --retries=3 \ CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:7860/api/health',timeout=4).status==200 else 1)" # Au démarrage : le jeu de test (comptes et groupes préfixés `test_`) si # SEED_DEMO=1, puis le serveur. Le seed est idempotent — un redémarrage ne # duplique rien — et les PIN viennent des secrets SEED_SUPER_PIN / SEED_DEMO_PIN, # jamais du dépôt. Mettre SEED_DEMO=0 pour un déploiement sans jeu d'essai. # # Un seul worker, volontairement : le hub WebSocket, le rate limiter et les # compteurs anti-spam vivent en mémoire du process. Passer à plusieurs workers # exigerait un backend partagé (Redis) — inutile à l'échelle visée. CMD ["sh", "-c", "if [ \"${SEED_DEMO}\" = \"1\" ]; then python scripts/seed_benevoles.py || echo 'seed ignoré'; fi; exec uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-7860} --workers 1 --no-server-header --proxy-headers --forwarded-allow-ips='*' --ws-ping-interval 25 --ws-ping-timeout 60"]