Produit & gouvernance
Partager le contenu. Garder la main sur chaque site.
Au départ…
Plusieurs sites partagent une partie de leur offre et de leur contenu. Copier les pages partout rend chaque correction plus difficile à suivre.
Ce que nous avons construit
Un modèle de pages reliées aux sites : chaque site possède ses domaines, son thème et son périmètre de publication. Une page partagée conserve ses liens de diffusion.
- Supabase
Contenu commun
Pages et versions
- Supabase
Périmètre de publication
Liens page × site
- Vercel
Rendu par domaine
Thème et navigation du site
Schéma simplifié du modèle examiné.
Ce que nous voulons changer
Réutiliser le contenu tout en rendant visibles les décisions de publication site par site.
Comment c’est construitModèle de données, code, contrôles et autonomie des équipes
Parcours utilisateur
- 01
Créer ou enrichir la page commune.
- 02
Prévisualiser son rendu dans le contexte de chaque site.
- 03
Publier la version approuvée sur les sites choisis.
Structure des données et des échanges
| Entité / table | Champs clés | Relations |
|---|---|---|
| Sites web & domaines | Hôte · thème · périmètre | Un site → plusieurs domaines |
| Pages | Blocs de contenu · version · statut | Une page → plusieurs liens de diffusion |
| Liens page/site | Site · page · slug local · publié | Publication explicite par site |
Implémentation technique
- Le domaine résout le site courant ; les pages sont reliées par une table de jonction.
- Les snapshots de préproduction et les versions publiées sont distingués.
- Les composants partagent un contrat de données et conservent des choix de présentation par site.
Décision d’ingénierie
Publier une même page de façon sélective sur plusieurs sites
Adapté de la branche publique du résolveur multisite. Le lien site/page et le statut de la page doivent tous deux autoriser la publication ; les surcharges SEO s’appliquent à cette association. Le client utilise les politiques de lecture publique. Prévisualisation et administration sont séparées, sans booléen contrôlé par le visiteur dans cet extrait.
import "server-only";import { createPublicClient } from "./database";import { parsePageContent } from "./content-schema";export async function resolvePublicPage(siteId: string, localSlug: string) { const db = await createPublicClient(); const { data: link, error } = await db.from("page_site_links") .select(` local_slug, is_published, seo_overrides, pages!inner(id, title, content, seo, status) `) .eq("web_site_id", siteId) .eq("local_slug", localSlug) .maybeSingle(); if (error) throw new Error("Page lookup failed"); if (!link?.is_published) return null; const page = link.pages; if (!page || page.status !== "prod") return null; return { id: page.id, title: page.title, content: parsePageContent(page.content), seo: { ...(page.seo ?? {}), ...(link.seo_overrides ?? {}) }, };}// siteId is resolved from the trusted hostname/site mapping.// Public row policies and a unique (web_site_id, local_slug) are required.Extrait adapté de l’implémentation
Contrôles et limites
- Les vérifications de périmètre sont nécessaires à chaque lecture et écriture.
- La prévisualisation privée doit contrôler l’accès aux contenus et aux médias.
- Rollback de code, version éditoriale et restauration de données se préparent séparément.
Qui peut contribuer
- Communication : contenu et publication.
- Administrateurs : sites, domaines et accès.
- Développeurs : composants, migrations et vérifications du périmètre.
Ce qui documente ce cas
Modèle multi-site, relations de publication et parcours de préproduction examinés dans le dépôt. Ce cas décrit l’implémentation, sans prétendre à un audit de sécurité complet.