# Architecture data-flow — Scope

> **Document de travail.** Brouillon commercial à relire par un avocat IT et RGPD avant signature. Aucune valeur contractuelle en l'état.

**Version** : v1.1 — 2026-05-27
**Éditeur** : Amir KELLOUSIDHOUM AE, SIRET 917 709 024 00017
**Contact DPO** : [dpo@getscope.dev](mailto:dpo@getscope.dev)
**Contact sécurité** : [security@getscope.dev](mailto:security@getscope.dev)
**Renvoi sous-traitants** : voir [`./subprocessors.md`](./subprocessors.md)

---

## 1. Vue d'ensemble

Scope ingère des **briefs et fichiers de cadrage** (PDF, DOCX, audio FR), les traite via un **pipeline IA en 4 stages**, persiste les résultats structurés dans **Supabase EU**, et permet l'**export PDF/DOCX/PPTX** + optionnellement la **signature électronique eIDAS** via DocuSeal auto-hébergé.

**Principe directeur** : les données applicatives persistées par Scope (briefs, transcripts, exports, audit logs) restent en Union européenne. Les sous-traitants US-domiciliés du périmètre persistant sont configurés pour traiter en région UE (Railway EU West, Supabase Dublin, Resend Irlande, GlitchTip Frankfurt). Pour les inférences LLM, OpenRouter est un proxy stateless (États-Unis) qui achemine à ce jour les prompts vers OpenAI (GPT-4o et GPT-4o mini, États-Unis) et Anthropic (Claude Sonnet 4.6 et Haiku 4.5, États-Unis) sous Clauses Contractuelles Types UE et avec la directive contractuelle `data_collection=deny` ; aucun prompt ni output n'est conservé ni utilisé pour l'entraînement. Une option Enterprise de routage UE-résident (Anthropic Claude via AWS Bedrock région Paris, ou Mistral Large hébergé à Paris) est en cours de validation interne et sera proposée sur demande dès que les tests de qualité FR seront concluants.

## 2. Diagramme du flux

```mermaid
flowchart LR
    subgraph CLIENT[Client : Navigateur PM ESN]
        UI[Application web<br/>Next.js + React]
    end

    subgraph RAILWAY[Railway — EU West, EU]
        EDGE[Edge Functions<br/>Routes serverless]
    end

    subgraph SUPABASE[Supabase — Dublin eu-west-1, EU]
        AUTH[Auth<br/>JWT + MFA TOTP]
        DB[(Postgres<br/>+ RLS 60 tables)]
        STORAGE[Storage<br/>briefs/audio/exports]
    end

    subgraph LLM[Pipeline IA — 4 stages]
        EXTRACT[1. Extract<br/>structurer le brief]
        CLARIFY[2. Clarify<br/>questions au PM]
        SCOPING[3. Scoping<br/>document de cadrage]
        ESTIMATE[4. Estimate<br/>chiffrage déterministe]
    end

    subgraph OPENROUTER[OpenRouter — proxy stateless US, data_collection=deny]
        LLM_UPSTREAM[OpenAI GPT-4o / 4o-mini US<br/>Anthropic Claude Sonnet 4.6 / Haiku 4.5 US<br/>sous CCT UE + DPA]
    end

    GLADIA[Gladia SAS<br/>Paris — transcription audio FR]
    DOCUSEAL[DocuSeal auto-hébergé<br/>Railway EU West — eIDAS]
    RESEND[Resend<br/>eu-west-1 IE — emails transactionnels]
    STRIPE[Stripe<br/>Dublin IE — paiement tokenisé]
    GLITCHTIP[GlitchTip<br/>DigitalOcean Frankfurt — monitoring erreurs]

    UI -- "Upload brief<br/>(données client)" --> EDGE
    EDGE -- "Persiste brief<br/>(données client)" --> STORAGE
    UI -- "Stream audio<br/>(données client, PCM 16k)" --> EDGE
    EDGE -- "Init session STT" --> GLADIA
    GLADIA -- "Transcript texte<br/>(données client)" --> EDGE
    EDGE -- "Persiste transcript" --> DB

    STORAGE -- "Brief structuré" --> LLM
    DB -- "Métadonnées projet" --> LLM
    LLM -- "Prompts<br/>(données client)" --> OPENROUTER
    OPENROUTER -- "Passthrough sous CCT UE<br/>+ data_collection=deny" --> LLM_UPSTREAM
    LLM_UPSTREAM -- "Réponse LLM" --> LLM
    LLM -- "Résultats structurés" --> DB

    UI -- "Demande export" --> EDGE
    EDGE -- "Lit document" --> DB
    EDGE -- "Génère PDF/DOCX/PPTX" --> STORAGE
    STORAGE -- "URL signée<br/>(temporaire)" --> UI

    UI -- "Demande signature" --> EDGE
    EDGE -- "Envoi enveloppe" --> DOCUSEAL
    DOCUSEAL -- "Webhook signé HMAC" --> EDGE
    EDGE -- "Email notification" --> RESEND

    EDGE -- "Paiement abonnement" --> STRIPE
    EDGE -- "Erreur runtime<br/>(stack scrubbée, sans PII)" --> GLITCHTIP

    AUTH -.->|"JWT vérifié sur chaque appel"| EDGE
    DB -.->|"audit_log append-only<br/>13mo CNIL + 10y comptable"| DB
```

**Légende des flèches** :
- **Trait plein** : données client transportées (brief, transcript, prompts, exports).
- **Trait pointillé** : métadonnées techniques (JWT, audit logs).

**Code couleur résidence** (à interpréter dans la vue rendue) :
- Tous les noeuds applicatifs persistants sont en **UE** : Railway EU West, Supabase Dublin, Gladia Paris, DocuSeal Railway EU West, Resend Irlande, Stripe Dublin, GlitchTip Frankfurt.
- Le pipeline LLM transite via OpenRouter (proxy stateless US) qui appelle à ce jour OpenAI (US) et Anthropic (US) sous CCT UE + `data_collection=deny`. Aucun prompt ni output n'est conservé. Option Enterprise UE-résident (Bedrock Paris, Mistral Paris) en validation roadmap.
- Cloudflare DNS (non rendu sur le diagramme) ne traite que des métadonnées DNS et de routage email, jamais de donnée applicative.

## 3. Description du pipeline IA en 4 stages

### 3.1 Stage 1 — Extract

**Entrée** : un ou plusieurs documents bruts (PDF, DOCX, transcript audio Gladia).
**Sortie** : structure JSON typée (acteurs, besoins exprimés, contraintes, livrables, périmètre). Chaque élément porte un champ `sources` avec verbatim + offset dans le document source (traçabilité bout-en-bout).
**LLM utilisé** : Claude Sonnet 4.6 via OpenRouter (passthrough vers Anthropic US sous CCT UE + `data_collection=deny`).
**Persistence** : table `extract_outputs` avec `org_id` + `project_id` (cloisonné par RLS).

### 3.2 Stage 2 — Clarify

**Entrée** : sortie Extract.
**Sortie** : 6 à 12 questions ciblées au PM pour combler les ambiguïtés détectées + contradictions remontées (severity `high|medium|low`).
**LLM utilisé** : idem Stage 1.
**Persistence** : table `clarify_outputs`, plus les réponses PM dans `clarify_answers` (avec `provenance: human_input`).

### 3.3 Stage 3 — Scoping

**Entrée** : Extract + Clarify + réponses PM + side-inputs (notes manuelles, hypothèses confirmées).
**Sortie** : document de cadrage complet — executive summary, périmètre, hypothèses, acteurs, livrables, planning, RACI, risques, critères d'acceptation. Chaque section porte ses sources (`ref_id` pointant vers les `extract_outputs`).
**LLM utilisé** : idem.
**Persistence** : table `scoping_documents` avec `structured_data` JSONB + `content` TipTap markdown (édition rich-text).
**Édition manuelle** : tout champ édité par le PM porte `provenance: human_edited`. Une régénération ne peut pas écraser ces champs sans confirmation explicite (cf. `ConfirmDialog`).

### 3.4 Stage 4 — Estimate

**Entrée** : Scoping validé + hypothèses chiffrage confirmées par le PM (wizard mandatory pré-génération depuis Vague D §1A).
**Sortie** : décomposition en lots × profils × jours-hommes, application TJM, calcul PERT (optimiste/réaliste/pessimiste), arrondi 0.5/5 documenté.
**LLM utilisé** : Claude pour la **décomposition T-shirt** seulement (XS/S/M/L/XL avec verbatim source). Le calcul jours × TJM est **déterministe en TypeScript pur** (`lib/estimate/compute.ts` + 200 tests Vitest). Aucun chiffre n'est inventé par le LLM.
**Persistence** : table `estimations` avec `audit_log` field-level (chaque édition manuelle PM tracée avec `reason` + `diff` sparse).
**Verrouillage pré-export** : `locked_at` + guard sur 5 routes export. Un export sur une estimation non verrouillée tamponne la mention "VERSION PROVISOIRE".

## 4. Données traitées par catégorie

| Catégorie | Description | Stockage primaire | Rétention | Sensibilité |
|---|---|---|---|---|
| **Brief content** | Documents PDF/DOCX/notes uploadés par le PM. Contiennent typiquement : descriptif projet, contraintes, noms d'acteurs internes/externes, exigences fonctionnelles. PII potentielle (noms, emails, fonctions). | Supabase Storage bucket `briefs` (RLS path-scoped `{org_id}/{project_id}/...`) | Durée de vie du projet + délai de suppression Art. 8 DPA | Confidentielle (B2B) |
| **Audio dictée** | Enregistrements vocaux PM (≤ 60 min par session), capturés via AudioWorklet PCM 16k base64. | Supabase Storage bucket `audio` + Gladia transient (1 jour côté Gladia, configuration Pro+) | **90 jours** sur Supabase Storage, purge automatique pg_cron | PII (voix) |
| **Transcriptions** | Texte issu de la transcription audio Gladia. | Supabase Postgres (`transcripts`) | Durée de vie du projet | PII (contenu vocal transcrit) |
| **Projet metadata** | Nom projet, vertical, dates, statut, membres, lexique, glossaire, DNT. | Supabase Postgres (`projects`, `project_members`) | Durée de vie du projet | Faible |
| **User auth** | Email professionnel, nom, password hash bcrypt, MFA TOTP secret, sessions JWT. | Supabase Auth (table `auth.users` managée) | Durée d'inscription. Suppression sur demande RGPD Art. 17 | PII |
| **Org metadata** | Raison sociale, SIRET (optionnel), logo, plan abonnement, tier, membres, configuration MFA. | Supabase Postgres (`organizations`) | Durée de l'abonnement + délai DPA | Faible |
| **Billing** | Customer ID Stripe (référence externe), invoices, événements abonnement, payment methods (tokenisés Stripe, jamais sur nos serveurs). | Stripe (Dublin EU) + références dans `subscriptions` Postgres | 10 ans (obligation comptable art. L.123-22 Code de commerce) | Faible (tokenisé) |
| **Audit logs** | Mutations sensibles : exports, signatures, débits crédits, changements rôle, suppression données. Append-only triggers. | Supabase Postgres (`audit_logs`) | **13 mois** CNIL pour les actions standards. **10 ans** pour `metadata.source='comptable'` (ledger crédits, événements signature). | Forensic |
| **AI model usage** | Pour chaque appel LLM : modèle utilisé, tokens in/out, cached, coût EUR, latency_ms, stage, provider, request_id. | Supabase Postgres (`ai_model_usage`) | **24 mois** (couvre AI Act Art. 26 + DORA RoI annuel + marge audit) | Métadonnées techniques |
| **Error monitoring** | Stack traces runtime scrubbées (PII et secrets retirés avant émission). | GlitchTip DigitalOcean Frankfurt | 30 jours par défaut | Métadonnées techniques scrubbées |
| **Web analytics** | Statistiques agrégées de pages vues (Plausible). **Aucune donnée personnelle**, aucun cookie. Activé après consentement opt-in. | Plausible Hetzner DE | Agrégé indéfiniment, désactivable | Anonyme |

## 5. Frontières et points d'attention

### 5.1 Points où des données utilisateur **quittent** le périmètre Scope (vers sous-traitant)

**Tous les transferts sont vers des sous-traitants EU ou US avec mitigations Cloud Act documentées** (cf. [`./subprocessors.md`](./subprocessors.md) §3).

- **Railway région EU West (Union européenne)** : exécution des routes serverless. Pas de persistance applicative, mais les payloads transitent en RAM le temps du traitement.
- **Supabase eu-west-1 (Dublin)** : persistence durable (DB + Storage). Cloisonnement RLS strict.
- **OpenRouter (proxy stateless, US)** : transit éphémère des prompts vers les fournisseurs LLM aval — à ce jour OpenAI (US) et Anthropic (US) sous CCT UE et `data_collection=deny` contractuel. Option Enterprise UE-résident (Bedrock Paris, Mistral Paris) en validation roadmap.
- **Gladia (Paris)** : audio uploadé pour transcription. Compte configuré en rétention 1 jour côté Gladia (default 12 mois) — l'audio brut reste sous Supabase Scope.
- **DocuSeal Railway EU West** : documents soumis à signature électronique. Auto-hébergé par Scope, aucune donnée partagée avec un tiers.
- **Resend (eu-west-1)** : emails transactionnels (notifications, magic links). Contenu limité au strict nécessaire.
- **Stripe (Dublin)** : aucune donnée carte chez Scope ; tokenisation totale Stripe.

### 5.2 Points où **uniquement** des hashes ou métadonnées transitent

- **GlitchTip (Frankfurt)** : stack traces scrubbées côté SDK (PII redactées avant émission). Pas de payload applicatif.
- **Plausible (Hetzner DE)** : événements de navigation agrégés, sans identifiant personnel.
- **Cloudflare (réseau global)** : DNS + routage email MX uniquement. Aucune donnée applicative.
- **`hashEmail()`** : Sentry/GlitchTip et logs serveur stockent l'email sous forme `SHA-256 salté`, jamais en clair.

### 5.3 Points où des données utilisateur **ne quittent jamais** la zone EU

- Tous les exports PDF/DOCX/PPTX sont générés côté Railway EU West et persistés dans Supabase Dublin.
- Les signatures électroniques transitent via DocuSeal Railway EU West (UE).
- Toute la donnée durable (briefs, transcripts, documents de cadrage, audit logs, exports) reste en UE.

### 5.4 Inférences LLM — transfert vers les États-Unis sous CCT UE

Le pipeline LLM transit via OpenRouter en proxy stateless (États-Unis) qui achemine à ce jour les requêtes vers OpenAI (GPT-4o et GPT-4o mini, États-Unis) et Anthropic (Claude Sonnet 4.6 et Haiku 4.5, États-Unis). Les prompts ne sont ni loggués ni utilisés pour l'entraînement (clause contractuelle `data_collection=deny` relayée par OpenRouter en aval). Les transferts vers les États-Unis sont encadrés par les Clauses Contractuelles Types UE et les DPA propres à OpenRouter, OpenAI et Anthropic. Une option Enterprise de routage UE-résident (Anthropic Claude via AWS Bedrock région Paris `eu-west-3`, ou Mistral Large hébergé à Paris) est en cours de validation interne et sera proposée sur demande dès que les tests de qualité FR seront concluants.

## 6. Engagements de Scope sur le data-flow

1. **Minimisation** : Scope ne demande au pipeline LLM que les éléments strictement nécessaires (extract → clarify → scoping → estimate). Pas de copie de la donnée vers d'autres systèmes.
2. **Chiffrement** : TLS 1.2+ en transit partout, AES-256 au repos (volumes Supabase Postgres et Storage).
3. **Cloisonnement multi-tenant** : Row Level Security (RLS) sur 60 tables Supabase + helpers `is_member_of_org` / `is_org_role` avec `SECURITY DEFINER` et `search_path=public`.
4. **Audit trail** : `audit_logs` append-only via triggers Postgres + rétention 13 mois CNIL + 10 ans comptable.
5. **Idempotence** : tout webhook (Stripe, DocuSeal) est rejouable sans effet de bord, identifié par `event_id` ou `request_id`.
6. **PII scrub** : monitoring d'erreurs et logs serveur scrubés côté SDK avant émission (emails, tokens, secrets, identifiants personnels).
7. **Pas de partage avec tiers** au-delà des sous-traitants listés en [`./subprocessors.md`](./subprocessors.md).

## 7. Renvois utiles

- **Registre sous-traitants** : [`./subprocessors.md`](./subprocessors.md)
- **DPA Scope** : [`./dpa-template.md`](./dpa-template.md) + page web [https://getscope.dev/dpa](https://getscope.dev/dpa)
- **RTO/RPO** : [`./rto-rpo.md`](./rto-rpo.md)
- **Incident Response** : [`./incident-response.md`](./incident-response.md)
- **Exit Plan** : [`./exit-plan.md`](./exit-plan.md)
- **Trust Center** : [https://getscope.dev/trust](https://getscope.dev/trust)
- **Politique de confidentialité** : [https://getscope.dev/politique-de-confidentialite](https://getscope.dev/politique-de-confidentialite)

---

*Document `architecture-data-flow.md` v1.1 — 2026-05-27 — à relire par avocat IT/RGPD avant signature.*

**Changelog v1.1 (2026-05-27)** : alignement du récit LLM sur le runtime réel. Le runtime (`lib/ai/openrouter.ts`) exclut volontairement Bedrock pour cause d'incompatibilité avec les schémas JSON-strict du pipeline (incident 2026-05-15). Le diagramme et les sections §1 / §3.1 / §5.1 / §5.3 / §5.4 décrivent désormais le passthrough effectif vers OpenAI (US) + Anthropic (US) sous CCT UE et reclassent le routage Bedrock Paris / Mistral FR en option Enterprise roadmap.
