Stack technique chez www.ideo-lab.com

Vue d’ensemble compacte et imprimable. Focus sur les traitements asynchrones (Celery + Redis) et l’outillage d’observabilité.

Inventaire des briques
MàJ : Mode sombre natif
DomaineTechnologiesRôle / UsageBonnes pratiquesNotes & outils
FrontendHTML5 CSS (Bootstrap 5 / Tailwind) JS (Alpine / HTMX)UI sobre et responsive (thèmes clair/sombre), composants accessibles (ARIA), animations légères.
  • Lisibilité d’abord (14–18px corps, titres ≤ 28px).
  • Composants réutilisables; CSS utilitaire.
  • Images SVG optimisées.
Dark/light toggle natif, icônes SVG, build minifié.
BackendPython 3.12 Django 5.x DRF Django AdminApps modulaires (services, demandes de devis), API REST, auth, admin enrichie type CRM.
  • Config via django-environ; secrets hors repo.
  • Transactions atomiques; validations modèle.
  • Limiter les signals; préférer services/domain events.
Healthcheck cron pour préchauffage; logs JSON.
Base de donnéesPostgreSQL psycopg RDS (prod)Stockage relationnel, contraintes fortes, index, éventuellement vues matérialisées.
  • Migrations maîtrisées; index ciblés; FK explicites.
  • EXPLAIN/ANALYZE sur requêtes lentes; pool.
  • Backups chiffrés + restauration testée.
pgAdmin/psql; pgBackRest; pg_stat_statements.
Cache / BrokerRedis 7 ElastiCache (prod)Cache clé/valeur, sessions, broker Celery et éventuellement result backend.
  • Namespaces séparés (sessions / broker / results).
  • TTL explicites; éviter gros payloads.
  • Surveillance mémoire/latence.
redis-cli; redis_exporter; CloudWatch.
AsynchroneCelery Celery Beat FlowerTâches arrière‑plan (emails, PDF, ETL légers, analyses, pré‑chauffage), planification récurrente.
  • Tâches idempotentes et petites (chunking), acks_late.
  • Retries avec backoff + jitter; time/rate limits.
  • Résultats TTL court ou désactivés si inutiles.
Queues high/default/low, observabilité Flower + métriques.
Web / ServeursNginx Gunicorn / UvicornReverse proxy, TLS, statiques, workers WSGI/ASGI adaptés au profil machine.
  • Timeouts/limits; GZip/Brotli; headers sécurité.
  • Workers/concurrency mesurés en charge réelle.
  • Reload 0‑downtime; endpoints de santé.
nginx_stub_status; logs access/error; OTel si dispo.
Conteneurs / CI‑CDDocker docker‑compose GitHub ActionsBuilds reproductibles, orchestrations locales, déploiements CI/CD avec tests et scans.
  • Images minces, multi‑stage; user non‑root.
  • SBOM & scans sécurité; tags immutables.
  • Healthchecks et dépendances explicites.
Trivy/Grype; Hadolint; cache builds.
ObservabilitéFlower Prometheus / Grafana SentryMetrics, traces, erreurs; suivi des workers Celery/queues et des services.
  • Corrélation logs‑traces; dashboards actionnables.
  • Alerting SLO/SLA; budgets d’erreur.
  • Logs JSON + niveaux (INFO/WARN/ERROR).
Exporters Redis/Postgres; sampling traces.
SécuritéHeaders TLS/HSTS django‑axes CSP stricteHardenings HTTP, limites auth, gestion secrets/permissions, audit.
  • Rotation clés/secrets; least privilege.
  • CSP, CSRF, cookies sécurisés.
  • Dépendances pinées + scans réguliers.
OWASP ASVS; bandit; pip‑audit; dependabot.
Code & InstructionsNUMBER OF LINES OF CODE HTML JS AND PYTHON IDEOLAB PRIVATE CODEExecuting Lines of code by CLOC (3.7 Millions of Lines).
DJANGO PYTHON.
Configuration Django + Celery (extraits)
# settings.py
CELERY_BROKER_URL = env("CELERY_BROKER_URL", default="redis://127.0.0.1:6379/1")
CELERY_RESULT_BACKEND = env("CELERY_RESULT_BACKEND", default="redis://127.0.0.1:6379/2")  # ou ""/None si inutile
CELERY_TASK_SERIALIZER = "json"
CELERY_ACCEPT_CONTENT = ["json"]
CELERY_RESULT_SERIALIZER = "json"
CELERY_TIMEZONE = "Europe/Paris"
CELERY_TASK_ACKS_LATE = True
CELERY_TASK_REJECT_ON_WORKER_LOST = True
CELERY_TASK_ALWAYS_EAGER = False  # True en dev si besoin
CELERY_TASK_DEFAULT_QUEUE = "default"
CELERY_TASK_ROUTES = {
  "app.tasks.envoi_email": {"queue": "high"},
  "app.tasks.rapport_pdf": {"queue": "default"},
}
CELERY_BEAT_SCHEDULE = {
  "cleanup-results-hourly": {
    "task": "app.tasks.cleanup_results",
    "schedule": 3600,
  },
}
# projet/celery.py
import os
from celery import Celery

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "projet.settings")
app = Celery("projet")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()

@app.task(bind=True)
def debug_task(self):
    print(f"Request: {self.request!r}")
# app/tasks.py
from celery import shared_task

@shared_task(bind=True, max_retries=5, default_retry_delay=60, retry_backoff=2, retry_jitter=True, acks_late=True)
def envoi_email(self, destinataire_id: int):
    try:
        # ... envoi via AWS SES ...
        return {"status": "ok"}
    except Exception as exc:
        raise self.retry(exc=exc)

@shared_task
def cleanup_results():
    # Purge résultats/artefacts obsolètes (TTL)
    pass
Commandes de lancement & monitoring
# Worker (3 queues)
celery -A projet worker -l info -Q high,default,low -O fair -n worker1@%h --concurrency=4
# Planificateur
celery -A projet beat -l info
# Monitoring
celery -A projet inspect ping
flower -A projet --port=5555
docker-compose (extrait)
services:
  redis:
    image: redis:7
    ports: ["6379:6379"]
  worker:
    build: .
    command: celery -A projet worker -l info -Q high,default,low -O fair
    depends_on: [redis, web]
  beat:
    build: .
    command: celery -A projet beat -l info
    depends_on: [redis, web]
  flower:
    image: mher/flower
    command: ["flower", "-A", "projet", "--port=5555"]
    ports: ["5555:5555"]
    depends_on: [redis, worker]

Astuce : pour EC2 sans compose, créer des units systemd séparées (web/gunicorn, worker, beat, flower) avec WantedBy=multi-user.target et Restart=on-failure.