Aller au contenu

Architecture technique

Vue d'ensemble de la stack LObsTer.

Vue macro

flowchart TB
    subgraph Client
      UB[Navigateur
utilisateur] end subgraph "Cloudflare (edge)" CF[Caddy + Cloudflare
HTTPS + DDoS] end subgraph "VPS Hetzner" FRONT[Frontend React
Vite build statique] API[FastAPI backend
uvicorn + asyncpg] PG[(PostgreSQL 15
+ PostGIS)] end subgraph "APIs externes" ANTHROPIC[Anthropic API
Claude Sonnet 4.6] STRIPE[Stripe
Checkout + webhooks] BREVO[Brevo
emails transactionnels] ADEME[ADEME DPE
API live] end subgraph "Storage" R2[Cloudflare R2
rapports PDF signés] end UB --> CF CF --> FRONT CF --> API API --> PG API --> ANTHROPIC API --> STRIPE API --> BREVO API --> ADEME API --> R2 classDef client fill:#f0f4fa,stroke:#0d1f3c classDef edge fill:#e87722,stroke:#0d1f3c,color:#fff classDef backend fill:#0d1f3c,stroke:#e87722,color:#fff classDef ext fill:#2a7f7f,stroke:#0d1f3c,color:#fff classDef store fill:#c9a84c,stroke:#0d1f3c,color:#0d1f3c class UB client class CF edge class FRONT,API,PG backend class ANTHROPIC,STRIPE,BREVO,ADEME ext class R2 store

Stack

Backend

  • Python 3.10+
  • FastAPI — framework async
  • asyncpg — driver PostgreSQL natif async (plus rapide que psycopg2)
  • Pydantic — validation des inputs API et des outputs LLM
  • Playwright — headless Chromium pour rendu PDF (via html_to_pdf.py)
  • python-jose — JWT tokens
  • bcrypt — hash passwords
  • slowapi — rate limiting
  • stripe-python — SDK Stripe
  • brevo-python — SDK Brevo (emails)
  • anthropic — SDK Claude API

Frontend

  • React 18 + TypeScript
  • Vite — build tool
  • React Router — navigation
  • TanStack Query — data fetching + cache
  • Recharts — graphs (avec fix infinite loop via minWidth)
  • Leaflet — cartes interactives (SITADEL, EPCI, drill-down BPE)
  • TailwindCSS — styling

Base de données

  • PostgreSQL 15
  • PostGIS — requêtes spatiales (communes, parcelles, EPCI)
  • Vues matérialisées — cache pour agrégations lourdes
  • pgAdmin4 — UI admin optionnelle (Docker Compose)

Infrastructure production

  • Hetzner CX22 — 2 vCPU, 4 Go RAM, 40 Go SSD, ~4,51 €/mois
  • Docker + Docker Compose — orchestration locale
  • Caddy — reverse proxy + HTTPS automatique (Let's Encrypt)
  • systemd — services backend
  • cron — backups quotidiens

Infrastructure wiki

  • Cloudflare Pages — hébergement statique
  • Pages Functions — Basic Auth middleware (100k invocations/j gratuit)
  • GitHub (privé) — repo source avec CI automatique

Flow d'une commande

sequenceDiagram
    actor Client
    participant Front as Frontend React
    participant API as FastAPI
    participant Stripe
    participant DB as PostgreSQL
    participant Claude as Anthropic
    participant Brevo
    participant R2 as Cloudflare R2

    Client->>Front: choisit commune + étude
    Front->>API: POST /api/orders (tunnel Observatoire)
    API->>DB: INSERT order status=pending
    API->>Stripe: create checkout session
    Stripe-->>Client: redirect Stripe Checkout
    Client->>Stripe: paiement CB
    Stripe-->>API: webhook checkout.session.completed
    API->>DB: UPDATE order status=paid
    API->>API: déclenche pipeline
    API->>DB: collector récupère données
    API->>Claude: mega-prompt étude
    Claude-->>API: JSON structuré
    API->>API: render HTML template
    API->>API: html_to_pdf.py (Playwright)
    API->>R2: upload PDF, retourne URL signée
    API->>DB: UPDATE order status=delivered + download_url
    API->>Brevo: send livraison rapport email
    Brevo-->>Client: email avec lien de téléchargement
    Client->>R2: télécharge PDF

Schéma base de données (principales tables)

Référentiel

  • communes (36 000 rows)
  • epci (~1 250 rows)
  • arrondissements (PLM)

Démographie

  • rp_demographics — agrégats par commune
  • rp_details — pyramide âges, CSP, ménages
  • filosofi — revenus, pauvreté
  • projections — OMPHALE

Logement

  • rp_housing — RP logement
  • lovac — vacance structurelle
  • rpls — parc social
  • zonage_abc — tension marché
  • anil_loyers (à créer Sprint 1)

Immobilier

  • sitadel — 2,3M permis
  • dvf — transactions (réimport en cours)
  • dvf_staging — 13,9M rows en staging (à nettoyer)
  • parcelles — cadastre (réimport 99 fichiers dept)

Équipements / social / santé

  • bpe_equipements
  • caf_communal — 157K rows
  • aides_dept — APA, PCH
  • rpps — 1,2M professionnels
  • finess — 86K établissements

Business

  • users, orders, subscriptions
  • reports — métadonnées rapports générés

Vues matérialisées

  • mv_commune_summary — agrégation pour territoire portrait
  • mv_housing_diagnostic — pour LOG-01

Conventions code

Backend

  • Naming : snake_case pour fonctions, PascalCase pour classes Pydantic
  • Async : tout endpoint est async def, jamais de requests.get bloquant
  • Erreurs : HTTPException uniquement (propagée en 4xx/5xx), pas de raw raise Exception
  • Logs : logging standard Python, pas de print
  • Tests : pytest async, test_<module>.py à côté du module

Frontend

  • Composants : un fichier par composant, pas de fichiers géants
  • Style : TailwindCSS, éviter CSS custom
  • State : TanStack Query pour le remote, React Context pour le global, useState pour le local

Pipeline études

  • Data collector : backend/app/report_pipeline/data_collectors/<code>.py — retourne dict plat
  • Prompt : backend/app/report_pipeline/prompts/<code>_html_report.py — mega-prompt templaté
  • Schema : backend/app/report_pipeline/schemas/<code>.py — Pydantic strict
  • Template HTML : backend/app/templates/<code>.html — format paysage A4 IBM Plex

Sécurité

  • JWT : expiration 24h pour access tokens, refresh tokens 30j
  • Rate limiting : 10/min login, 5/min register, 3/min forgot-password
  • Bcrypt : hash password coût 12
  • CORS : whitelist https://l-obster.fr + domaine wiki
  • Stripe webhook : signature vérifiée via STRIPE_WEBHOOK_SECRET
  • Secrets : jamais en dur, toujours env vars (voir Déploiement)

Points techniques à renforcer

  • Tests automatisés pipeline (0 actuellement — red-team finding)
  • Monitoring Sentry pour erreurs prod
  • CI GitHub Actions (lint + tests)
  • Redis pour rate limiting distribué (si multi-instance)
  • Queue asynchrone (Celery/Dramatiq) pour pipelines longs