SPEC — Architecture fédérée (multi-instance, sync, fédération)
Périmètre : SPEC_ARCHITECTURE_FEDEREE
Références :
Références :
Références : §3.2
Date : 2026-06-05
Statut : Spécification technique v1
Contexte : L'application doit pouvoir interroger et synchroniser des données provenant de sources multiples : Baserow (base centralisée), instances fédérées (associations partenaires), cache local, services externes (Vespa, etc.). Chaque source a son propre domaine, ses propres règles d'authentification et son propre modèle de données. RAPPORT_ANALYSE_GAPS §3.2 identifie le besoin d'une doc topologie multi-instance, protocole sync, fédération identités.
Conformité au schéma directeur :
| § Schéma | Section du document |
|---|---|
| 1. Contexte & Objectif | §1 |
| 2. Description Fonctionnelle | §2 |
| 3. Architecture & Références | §3 |
| 4. Spécifications Techniques Détaillées | §4 |
| 5. Dépendances & Interactions | §5 |
| 6. Plan d'Implémentation | §6 |
| 7. Résultats Attendus | §7 |
1. Contexte & Objectif
1.1 Résumé du besoin
L'application calendrier-agenda doit supporter un modèle multi-instance où plusieurs déploiements indépendants (associations, partenaires) peuvent :
- Héberger leurs propres données Baserow
- Synchroniser sélectivement des événements et ressources
- Fédérer les identités utilisateur via un fournisseur OIDC commun ou par échange de tokens
- Découvrir dynamiquement les instances partenaires
1.2 Objectif métier
| Objectif | Valeur |
|---|---|
| Découplage | Chaque instance reste autonome ; une panne n'impacte pas les autres |
| Sync sélective | Les instances choisissent quels jeux de données partager (événements publics, ressources partagées) |
| Fédération progressive | Ajout d'une nouvelle instance sans arrêt ni migration |
| Performance | Les requêtes cross-instance sont parallélisées avec agrégation côté gateway |
| Sécurité | Chaque instance contrôle ses propres règles d'accès ; les tokens sont échangés via OAuth2 |
1.3 Périmètre
| Inclus | Exclu |
|---|---|
| Topologie multi-instance (hub-and-spoke) | Migration des données existantes vers le modèle fédéré |
| Découverte dynamique d'instances via registre Baserow | Synchronisation en temps réel (WebSocket cross-instance) |
| API Gateway avec routage, agrégation, cache, circuit breaker | Réplication complète de toutes les tables |
| Fédération des identités via OIDC / OAuth2 client-credentials | Interface d'administration de la fédération |
| Schéma canonique des événements partagés | Synchronisation bidirectionnelle temps réel |
| Cache local (IndexedDB) + TTL | Outil de monitoring de l'état des fédérations |
| Résolution de conflits (priorité source) |
2. Description Fonctionnelle
2.1 Topologie hub-and-spoke
┌──────────────────┐
│ Hub central │
│ (Baserow + Auth) │
└────────┬─────────┘
│ HTTPS
┌──────────────┼──────────────┐
│ │ │
┌────────▼───┐ ┌──────▼──────┐ ┌───▼────────┐
│ Instance A │ │ Instance B │ │ Instance C │
│ (Assoc. 1) │ │ (Assoc. 2) │ │ (Assoc. 3) │
│ Baserow+Qwik│ │ Baserow+Qwik │ │ Baserow+Qwik│
└─────────────┘ └─────────────┘ └────────────┘
Le Hub central héberge :
- Le registre des instances fédérées (table Baserow
instances_federees) - L'annuaire des identités partagées (via Authentik OIDC)
- La configuration de sync (quelles tables partager avec quelle instance)
- Un cache aggregé des données publiques
Chaque instance spoke :
- Héberge sa propre base Baserow et son frontend Qwik
- S'enregistre auprès du Hub via API
- Publie ses données partagées via des endpoints REST dédiés
- Consomme les données des autres instances via le Hub
2.2 Découverte dynamique
Les instances s'enregistrent via une API REST :
POST /api/federation/register
Content-Type: application/json
Authorization: Bearer <hub-token>
{
"instanceId": "assoc-1",
"name": "Association culturelle A",
"baseUrl": "https://agenda.assoc-a.fr",
"apiVersion": "1.0",
"publicKey": "-----BEGIN PUBLIC KEY-----...",
"capabilities": ["events:read", "resources:read", "contacts:read"],
"status": "active"
}
Le registre central est stocké dans une table Baserow instances_federees avec les champs :
field_nom: nom de l'instancefield_url_base: URL racinefield_cle_publique: clé publique pour vérification JWTfield_capacites: liste des capacités (JSON array)field_statut: active | inactive | maintenancefield_dernier_heartbeat: timestamp ISO
2.3 Synchronisation des données
Mode Pull (Hub vers Spoke) : Le Hub interroge périodiquement chaque instance pour récupérer les événements publics modifiés depuis la dernière sync.
Mode Push (Spoke vers Hub) : L'instance notifie le Hub via webhook quand des données partagées sont modifiées.
GET /api/federation/events?since=2026-01-01T00:00:00Z
Response:
{
"events": [
{
"id": "evt-assoc-a-123",
"title": "Concert de printemps",
"start": "2026-04-15T20:00:00Z",
"end": "2026-04-15T23:00:00Z",
"location": "Salle des fetes",
"source": "assoc-a",
"checksum": "sha256-abc123"
}
],
"nextSince": "2026-01-02T00:00:00Z"
}
2.4 Regles metier
- Souverainete : chaque instance reste proprietaire de ses donnees ; le Hub n'a qu'une copie cache
- Opt-in : le partage est active table par table, instance par instance
- Checksum : chaque evenement partage a un checksum SHA-256 pour detecter les conflits
- Horodatage : chaque modification porte un
updatedAtpour tri et resolution de conflits - TTL cache : les donnees agregees expirent apres 5 minutes (configurable par table)
- Heartbeat : chaque instance envoie un signal de vie toutes les 60 secondes ; apres 3 missed heartbeats -> statut
inactive - Retention : les evenements passes (date de fin < J-30) ne sont pas synchronises
- Rate limiting : max 100 requetes/minute par instance spoke
3. Architecture & References
3.1 Schema d'architecture
+--------------------------------------+
| API Gateway |
| (Edge Worker / Qwik Route) |
| +----------+ +------------------+ |
| Router | | Federation Proxy | |
| +----+-----+ +--------+---------+ |
| +----v------------------v---------+ |
| Service Registry (cache) | |
| +---------------------------------+ |
+----------+---------------------------+
+--------------------+--------------------+
+------v------+ +-------v-------+ +-------v-------+
| Baserow | | Instance A | | Instance B |
| (REST API) | | (REST API) | | (REST API) |
| token API | | OAuth2 CC | | OAuth2 CC |
+--------------+ +---------------+ +---------------+
3.2 Flux d'une requete cross-instance
1. Client Qwik -> GET /api/events?federation=true
2. Gateway recoit la requete
3. Gateway verifie le JWT client (Authentik OIDC)
4. Gateway consulte le registre des instances actives (cache 60s)
5. Gateway calcule les endpoints a interroger :
- Baserow local : GET /api/baserow/database/rows/table/548/
- Instance A : GET https://agenda.assoc-a.fr/api/federation/events
- Instance B : GET https://agenda.assoc-b.fr/api/federation/events
6. Gateway parallelise les appels (Promise.allSettled)
7. Gateway normalise chaque reponse dans le schema canonique
---
*Synthèse PRISME — 383 lignes dans la source complète.*
**Voir aussi PRISME :** IA fédérée Marty · Protocole PRISME-Mesh
- Client Qwik -> GET /api/events?federation=true
- Gateway recoit la requete
- Gateway verifie le JWT client (Authentik OIDC)
- Gateway consulte le registre des instances actives (cache 60s)
- Gateway calcule les endpoints a interroger :
- Baserow local : GET /api/baserow/database/rows/table/548/
- Instance A : GET https://agenda.assoc-a.fr/api/federation/events
- Instance B : GET https://agenda.assoc-b.fr/api/federation/events
- Gateway parallelise les appels (Promise.allSettled)
- Gateway normalise chaque reponse dans le schema canonique
Synthèse PRISME — 383 lignes dans la source complète.
Voir aussi PRISME : IA fédérée Marty · Protocole PRISME-Mesh