Files
Presencia/docker-compose.yml
T
Claude 3df521ac30 Revue complète : sécurité, optimisations et UI/UX mobile
Sécurité
- JWT : un JWT_SECRET d'exemple ou trop court est ignoré au profit d'un
  secret aléatoire conservé en base (avant, la valeur publique de
  docker-compose.yml permettait de forger un jeton admin).
- Le compte est relu en base à chaque requête : désactivation, changement
  de rôle et réinitialisation du mot de passe prennent effet immédiatement.
- Connexion : 10 échecs max par e-mail / 15 min, temps constant que l'e-mail
  existe ou non, mot de passe admin retiré des logs.
- Validation des entrées (ids, dates, mois, longueurs, e-mail) : 400 au
  lieu de 500. Un admin ne peut plus se désactiver ni se rétrograder.
- Mots de passe : 8 caractères minimum ; changement en libre-service.
- Export : nom de fichier conforme RFC 5987 (un nom de société avec « — »
  faisait planter l'export).
- esc() échappe aussi les guillemets (injection d'attributs HTML).
- En-têtes CSP / X-Frame-Options / nosniff (Nginx + API), API et Postgres
  publiés sur 127.0.0.1 seulement, image backend non-root via npm ci.

Optimisations
- Export : une requête pour tout le mois au lieu d'une par cadre.
- Saisie groupée : un seul INSERT (unnest), doublons dédupliqués.
- Dates renvoyées en chaînes (plus de décalage d'un jour selon le TZ).
- Planning : chaque clic met à jour l'affichage localement au lieu de
  recharger le mois ; les réponses de mois périmées sont ignorées.
- Recherche Utilisateurs / Plannings filtrée localement (plus une requête
  par touche) ; statuts des sociétés chargés en parallèle.

UI/UX
- Mobile : toutes les destinations dans la barre basse (Sociétés et Ma
  saisie étaient inaccessibles à l'admin) ; tableaux affichés en cartes
  (les boutons d'action étaient hors écran).
- Boutons désactivés pendant l'envoi, focus et Échap dans les dialogues,
  retour à l'écran de connexion quand la session est révoquée, erreurs
  d'export affichées au lieu d'un fichier JSON téléchargé, actions
  destructives signalées, confirmation avant désactivation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D5Bdayziw6tybgqETZoNSt
2026-10-09 07:17:54 +00:00

59 lines
1.5 KiB
YAML

services:
presencia-db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: presencia
POSTGRES_PASSWORD: R4dsITu0vuigNQQwNlvj0agVyHupSyX
POSTGRES_DB: presencia
volumes:
- presencia_pgdata:/var/lib/postgresql/data
ports:
# Reachable from this host only (psql, backups), not from the network.
- "127.0.0.1:6543:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U presencia"]
interval: 5s
timeout: 5s
retries: 10
presencia-backend:
build: ./backend
restart: unless-stopped
depends_on:
presencia-db:
condition: service_healthy
environment:
PORT: 4790
PGHOST: presencia-db
PGPORT: 5432
PGUSER: presencia
PGPASSWORD: R4dsITu0vuigNQQwNlvj0agVyHupSyX
PGDATABASE: presencia
# Leave empty to let the API generate a random secret, stored in the
# database. If set, it must be at least 32 random characters.
JWT_SECRET: ""
COOKIE_SECURE: "false"
ADMIN_EMAIL: michaelschal@ffest.fr
ADMIN_PASSWORD: Lapîn2509
ADMIN_NAME: Michael
ports:
# The browser goes through the frontend; direct API access stays local.
- "127.0.0.1:4790:4790"
presencia-frontend:
build: ./frontend
restart: unless-stopped
depends_on:
- presencia-backend
ports:
- "8781:80"
networks:
default:
name: nginx_default
external: true
volumes:
presencia_pgdata: