# Réservoir backlink — catalogue global curé + vue god-mode

**Date:** 2026-06-10 · **Origine:** `docs/project/bug-fix.md` (reliquats 4-5) — « seulement admin god mode peut voir tous les ajouts des clients et org ; le réservoir est commun que celui que je choisis de mettre visible globale ».

**Périmètre v1 :**
1. **Flag `global`** (migration 0022) : `link_sources.global boolean notNull default false`. Seul le **super-admin** (`assertSuperAdmin`, pattern DR) peut le poser/retirer, sur les sources de son org active. Une source `global=true` fait partie du **catalogue commun**.
2. **Provisioning** : `createOrgForUser` copie le **catalogue global** (sources `global=true`, tous orgs confondus — en pratique l'org du super-admin) au lieu des fixtures statiques ; **fallback fixtures** si le catalogue est vide (zéro régression). Ids re-namespacés `${newOrgId}__${suffix}` (suffix = partie après `__` de l'id source, ou l'id complet).
3. **Vue god-mode « Toutes les orgs »** : sur `/backlink/reservoir`, un switch visible **uniquement super-admin** bascule la table sur l'ensemble des sources de **toutes les orgs** (colonne « Org » ajoutée, lecture seule — pas d'actions d'édition dans cette vue). Action read `assertSuperAdmin`.
4. **Badge « 🌐 » + toggle** : en vue normale, le super-admin voit l'état global de chaque source (badge) et peut le basculer (bouton inline god-mode) ; les utilisateurs normaux ne voient rien de tout ça.
5. **Isolation client confirmée** (déjà vraie, re-testée) : une org ne voit jamais les sources d'une autre.

**Hors scope v1 :** rétro-propagation du catalogue aux orgs existantes (les nouvelles orgs seulement ; backfill manuel possible) · promotion d'une source client → catalogue (copier dans l'org admin d'abord) · édition cross-org.

## Données

- Migration 0022 : `ALTER TABLE link_sources ADD COLUMN "global" boolean NOT NULL DEFAULT false;`
- `LinkSource` type + mappers : champ `global: boolean`.
- Backfill dev (one-off psql, PAS dans la migration) : flag `global=true` sur les sources de l'org du super-admin (elevaseo) → le catalogue initial = ses 380+ sources.

## Actions (`src/lib/backlink/global-actions.ts`, "use server")

- `setSourceGlobalAction(sourceId: string, global: boolean)` — `assertSuperAdmin()` ; update scoped `(id AND org_id = org active)` ; `revalidatePath("/backlink/reservoir")`.
- `getAllOrgsSourcesAction(): Promise<(LinkSource & { orgName: string })[]>` — `assertSuperAdmin()` ; join `organization` pour le nom ; tri org puis platform.

## Provisioning (`org-bootstrap.ts`)

```ts
const catalog = await tx.select().from(linkSources).where(eq(linkSources.global, true));
const rows = catalog.length
  ? catalog.map((s) => ({ ...pick(s), id: `${orgId}__${suffixOf(s.id)}`, orgId, global: false }))
  : BACKLINK_SOURCES.map(/* existant */);
```
`suffixOf(id)` = partie après le premier `__`, sinon l'id. Les copies clients ne sont **pas** globales.

## UI (`reservoir-container` + colonnes)

- Prop RSC `isSuperAdmin` (via `isCurrentUserSuperAdmin()` existant) descendue au container.
- Super-admin seulement : switch « Toutes les orgs » (à côté des boutons d'import) → charge `getAllOrgsSourcesAction`, affiche la table en lecture seule avec colonne « Org » (réutilise les colonnes existantes + colonne org, masque les actions d'édition).
- Vue normale super-admin : colonne « 🌐 » (badge si global) + toggle inline (`setSourceGlobalAction`).

## Tests

- **DB** : `setSourceGlobalAction` (flag posé, scope org active, refus implicite hors org) ; `createOrgForUser` copie le catalogue quand il existe (ids re-namespacés, `global=false` sur les copies) et retombe sur les fixtures sinon ; `getAllOrgsSourcesAction` retourne plusieurs orgs. Le garde super-admin est mocké permissif dans les tests (pattern assert-site).
- **Live** : flag 2 sources en global (god-mode), vue « Toutes les orgs » liste Acieb/ADVMFR/…, signup d'une org de test ? (lourd — à défaut : test DB du bootstrap suffit), isolation re-vérifiée avec un compte non-admin si disponible (sinon assertion serveur).
