feat(kernel): sync CORTEX kernel — sessions, modes, ADRs, clean personal files

Ajout : 11 session-*.yml, modes soft locks, coach-boot + time-anchor, ADR-008→024.
Retrait : focus.md, BRAIN-INDEX.md, SUPERVISOR-STATE.md, claims/, todo/.
brain-template = kernel distribuable propre.
This commit is contained in:
2026-03-17 23:14:04 +01:00
parent e87c24b06a
commit 60d9cf7332
36 changed files with 2451 additions and 191 deletions

View File

@@ -0,0 +1,78 @@
---
name: 008-superoauth-multitenant-identity-model
type: adr
context_tier: cold
---
---
id: ADR-008
title: SuperOAuth — Modèle d'identité multi-tenant
date: 2026-03-15
status: accepted
décideur: tetardtek
agents: tech-lead, security, coach
---
## Contexte
SuperOAuth est actuellement mono-tenant (OriginsDigital = seul client). La vision est de le transformer en SaaS multi-tenant vendable (modèle Auth0/Clerk). Les décisions d'identité prises maintenant sont irréversibles une fois qu'il y a des données réelles.
## Décisions tranchées
### 1. Scope UNIQUE sur linked_accounts
**Décision :** `UNIQUE(tenantId, provider, providerId)` — isolation complète par tenant.
**Pourquoi :** Un même compte Discord peut être utilisé sur deux apps différentes (deux tenants) sans conflit. Les utilisateurs sont scopés par service fourni. Alternative rejetée : UNIQUE global → un Discord ne peut être que sur un seul tenant → bloquant pour le SaaS.
**Conséquence :** Migration TypeORM requise. L'index actuel `UNIQUE(provider, providerId)` doit devenir `UNIQUE(tenantId, provider, providerId)`.
---
### 2. Email non vérifié en DB
**Décision :** Stocker `email + emailVerified=false`. Ne pas auto-linker. Bloquer le register classique si conflit → proposer le login à la place.
**Pourquoi :** Stocker `null` coupe l'ancre email définitivement. Stocker l'email avec le flag permet de retrouver le compte plus tard (link manuel depuis settings) et d'offrir un meilleur UX ("ce compte existe déjà, connecte-toi").
**Conséquence :** La route de register classique doit vérifier `emailVerified` avant de refuser — si email existe mais non vérifié → réponse spécifique `EMAIL_UNVERIFIED_EXISTS` au lieu de `EMAIL_ALREADY_TAKEN`.
---
### 3. Staleness users.email
**Décision :** Mettre à jour `users.email` si le provider retourne un email vérifié ET que ce provider était la source originale de `users.email`. Ne jamais écraser un email posé par une inscription classique.
**Pourquoi :** Évite les doublons quand un utilisateur change son email chez Discord. Protège l'email classique (posé volontairement par l'utilisateur) contre un écrasement involontaire par un provider.
**Conséquence :** Lors du callback OAuth, tracer l'origine de `users.email` (colonne `emailSource: 'classic' | 'provider:<name>'`).
---
## Architecture par tiers — plan produit
| Tier | Scope | Pattern clé | Repo |
|------|-------|-------------|------|
| 0 | Mono-tenant, 4 providers | UNIQUE(provider, providerId) global | superoauth-tier0 |
| 1 | Multi-tenant basic | tenantId + UNIQUE(tenantId, provider, providerId) | superoauth-tier1 |
| 2 | Identity features | Linking settings, merge, email verified gate, webhooks | superoauth-tier2 |
| 3 | Enterprise | Per-tenant providers, audit logs, custom JWT claims | superoauth-tier3 |
Chaque tier = sprint dédié = repo de démo autonome = reference implementation.
## Vision long terme — autonomous build
Le brain accumule les patterns (toolkit) et les décisions (ADRs). L'objectif est que des équipes d'agents spécialisées par tier puissent builder chaque tier depuis un brief sans intervention humaine sur le code.
Équipes cibles :
- Tier 1 : migration + security + tech-lead
- Tier 2 : + auth-specialist + testing
- Tier 3 : + enterprise-patterns + doc + optimizer-db
**Prérequis pour l'autonomie :** briefs de tier précis en todo/, toolkit suffisamment riche, orchestrator capable de décomposer un brief en sprint.
## Conséquences acceptées
- Migration Tier 0 → Tier 1 casse la compatibilité DB (acceptable : 0 utilisateurs réels)
- `emailSource` ajoute une colonne — migration légère mais requise
- Le délinkage n'est pas nécessaire avec l'isolation par tenant