Catalogue des composants
Inventaire interne des composants UI, règles d'aperçu et contrat de registre V2.
Vue d'ensemble
Yayaw inclut un catalogue interne de composants à :
/dashboard/content/components
Le catalogue prend en charge un inventaire mixte :
- composants locaux depuis
src/components/ui/* - composants importés stockés dans des snapshots DB (non exécutables)
Docs liées :
- Catalogue des sections pour la création de sections réutilisables depuis des recettes de composants
- Design tokens pour le comportement d'aperçu des tokens au runtime
- Plan de contrôle pour les attentes de sécurité d'automatisation
- Vue d'ensemble du CMS pour toute la pile de contenu
Rôle CMS
Le catalogue des composants est l'inventaire de rendu du CMS. Il documente et prévisualise les pièces UI bas niveau que les sections peuvent utiliser, y compris les composants locaux et les snapshots de source importés. Les composants ne sont pas du contenu édité en eux-mêmes ; ce sont les primitives de rendu sûres utilisées par les sections réutilisables et les références directes de page.
Gardez les imports de composants non exécutables, compilez-les en recettes validées et ne publiez que les entrées qui réussissent les contrôles de compilation et de smoke render.
Objectifs :
- lister les composants UI depuis
src/components/ui - lister les composants UI importés depuis les révisions DB
- prévisualiser les composants compatibles avec des contrôles de props vivants
- afficher les fichiers source utilisés par chaque entrée
- valider le rendu compatible tokens avec les design tokens runtime courants
Scope et conventions
La source de vérité locale reste explicite :
src/components/ui/catalog/registry.ts.
Scope actuel :
- fichiers de premier niveau dans
src/components/ui/*.tsx - entrées clés pour
src/components/ui/kibo-ui/*/index.tsx - entrée clé pour
src/components/ui/yayaw-table/index.ts - entrées importées depuis la DB (
ui_component_registry_items) fusionnées dans le même inventaire
Conventions :
- une entrée de catalogue par composant clé
- un composant clé par dossier pour les répertoires de composants imbriqués
- le point d'entrée cible est
index.tsxpour les dossiers imbriqués (les exceptions héritées sont explicites dans le registre) - les entrées importées sont des éléments de registre à scope global avec snapshots source uniquement
- la règle de collision est déterministe :
imported > localpour le même slug/id
Modèle d'aperçu
Le comportement d'aperçu est piloté par les recettes et partagé avec le rendu runtime :
src/lib/server/services/components/ui-component-recipe-compiler.tssrc/components/ui/catalog/ui-recipe-renderer-server.tsxsrc/components/ui/catalog/ui-recipe-renderer-client.tsx
Flux :
- Le snapshot source est compilé en
UiComponentRecipeV1. - L'aperçu du catalogue rend la recette avec des contrôles générés depuis
propSchema,apiSchemaetharnessSchema. - Le runtime de blocs résout les révisions de recettes publiées et utilise le même chemin de renderer.
creative-composition est volontairement plus strict : ses inputs runtime
passent uniquement par propSchema. apiSchema et harnessSchema doivent être
omis ou vides, fixtures doit être vide, et les réglages API, harness ou
fixtures associés ne peuvent pas servir de canaux runtime cachés.
Politique d'aperçu runtime uniquement :
- l'aperçu du catalogue utilise toujours le renderer de recettes interne
- aucune iframe de docs externe n'est intégrée dans le panneau d'aperçu
- les contrôles de parité d'aperçu passent par des onglets de variantes quand plusieurs bibliothèques exposent la même clé de composant
Garde de publication :
compiled + smoke render OK=>published(auto-publication pour imports ou recompilation)- sinon =>
draft_blocked
Suppression douce :
- les composants importés sont retirés du catalogue avec le statut de
publication
deleted - les snapshots source restent en DB pour audit/rejeu
Intégration AI SDK
Le fallback de compilation piloté par IA et la classification utilisent désormais Vercel AI SDK :
src/lib/server/services/components/ui-component-ai-client.tssrc/lib/server/services/components/ui-component-recipe-ai-fallback.tssrc/lib/server/services/components/ui-component-import-classifier.ts
Règles :
- toutes les sorties IA sont validées avec des schémas
zodstricts - l'utilisation des modèles suit une chaîne de fallback résiliente intégrée ; les builders de pages/blocs peuvent encore demander un modèle préféré depuis les contrôles UI
- un fallback déterministe est toujours disponible si l'IA est indisponible
- aucun échec IA ne bloque les pipelines d'import ou de compilation
Classification par bibliothèque et catégorie
Les composants importés sont classifiés avec une stratégie hybride :
- cache par
sourceHash(réutilise les métadonnées de classification précédentes) - heuristiques déterministes (bibliothèque + groupe)
- enrichissement AI SDK (affinage bibliothèque/catégorie)
Métadonnées persistées sur les lignes de registre :
librarygroupclassificationSourceclassificationVersionclassificationModel(quand l'IA est utilisée)
Politique de catégorie :
- normalisation en kebab-case minuscule
- les nouvelles catégories sont acceptées automatiquement après normalisation
Politique de bibliothèque :
- valeurs contrôlées :
shadcn-ui,kibo-ui,yayaw,ai-sdk,custom
Composants vendoriés AI Elements
AI Elements est vendorié sous un namespace dédié :
src/components/ui/ai-elements/*- les ids du registre local de catalogue utilisent
ai-elements-*pour éviter les collisions avec les ids shadcn principaux
Script d'installation/mise à jour :
bun run components:install-ai-elements
Comportement du script :
- résout l'index de registre
@ai-elements - installe chaque élément de registre dans
src/components/ui/ai-elements - ignore les fichiers existants par défaut (
--allpour réinstaller chaque élément) - régénère
src/components/ui/ai-elements/index.ts - régénère les surcharges déterministes d'aperçu composite dans
src/lib/server/services/components/ui-component-ai-elements-preview-overrides.generated.ts - continue en cas d'échec par élément et rapporte un résumé
Comportement du catalogue :
- les fichiers AI Elements vendoriés sont listés dans
src/components/ui/catalog/registry.ts - ils sont tagués comme bibliothèque
ai-sdk - les familles AI Elements inconnues compilent en recettes
compositepar défaut afin de garder les aperçus disponibles - les recettes composites locales
ai-elements-*sont enrichies par des surcharges déterministes générées depuis les snapshots source (components:generate-ai-elements-previews) - les éléments AI Elements importés utilisent automatiquement le préfixe de slug
ai-elements-*quand leur slug de base entrerait en collision avec un id de catalogue local existant - quand plusieurs bibliothèques exposent la même clé canonique de composant, des onglets d'aperçu permettent aux utilisateurs de changer de variante et indiquent si leurs sources normalisées sont identiques ou différentes
- le dashboard ne charge d'abord que les résumés de catalogue ; la recette et la source de la variante sélectionnée sont chargées à la demande afin que l'ouverture de la page Components ne compile ni ne transfère tous les aperçus de composants
Entrées unifiées et onglets de variantes
L'inventaire est groupé par clé logique de composant, pas par id brut de registre.
Règles :
- une ligne d'inventaire par clé canonique de composant
- chaque ligne peut exposer plusieurs variantes de bibliothèque (onglets dans l'aperçu)
- sélectionner un filtre de bibliothèque garde une ligne visible quand elle a au moins une variante de cette bibliothèque
- sélectionner un filtre de catégorie garde une ligne visible quand au moins une variante correspond à cette catégorie
Règles de regroupement par clé canonique
La résolution de clé canonique est définie dans :
src/components/ui/catalog/catalog-identity.ts
Normalisation actuelle :
- les ids
ai-elements-*sont groupés sous leur clé de base sans préfixe - tous les autres ids conservent leur valeur d'origine comme clé canonique
L'ordre des variantes de bibliothèque est déterministe :
shadcn-uiai-sdkkibo-uiyayawcustom
Flux d'import et synchronisation de registre
La V2 prend en charge la gestion de composants depuis l'UI du catalogue pour les
utilisateurs avec components:manage.
Flux d'ajout pris en charge :
- entrée de commande shadcn
- import de synchronisation d'alias de registre complet (
onlyNew=truepar défaut) - collage de snapshot source (
name,sourceFile,sourceSnapshot) - import de snapshot source MCP via
yayaw_component_import - import de recette déclarative MCP via
yayaw_component_recipe_import
Action de synchronisation de registre :
syncRegistryAliasComponents(registryAlias, { onlyNew: true })
Politique non bloquante pour les nouvelles versions de bibliothèques :
- la découverte du registre utilise les candidats de payload d'index
(
index.jsonetregistry.json) - les éléments pas encore vendoriés localement peuvent quand même être importés via le pipeline de snapshots DB
- la validation allowlist reste appliquée pour les domaines source
Les outils MCP de composants exposent la même frontière de catalogue adossée à la base :
yayaw_components_listetyayaw_component_getinspectent l'inventaire de composants ;includeSchemas=truerenvoie les schémas de props/API/harness, les capacités runtime, les indications d'usage et les références directement utilisablesyayaw_component_importstocke et compile un snapshot sourceyayaw_component_recipe_importvalide et stocke uneUiComponentRecipeV1déclarative avec le statutdraft_ready, sans exécuter de code fourniyayaw_component_recompilerecompile un snapshot stockéyayaw_component_publishpublie une révision compilée et smoke-renderableyayaw_component_deletesoft-delete une entrée importée
Ces outils ne mutent pas les fichiers source locaux du dépôt en production. Si un agent doit ajouter ou modifier des fichiers React first-party, c'est un changement de code qui doit passer par une branche et une pull request.
Les imports déclaratifs sont limités aux kinds de recettes first-party rendus
par le runtime présent dans le dépôt. Le payload complet, les valeurs par défaut,
les fixtures et les valueShape récursifs doivent être du JSON borné. La
publication reste une opération explicite séparée. Pour
design_system_extension, importer et publier ne suffit pas : le plan final
doit référencer la révision publiée exacte depuis une nouvelle composition. Un
import portant designContextId n'est accepté qu'après la sélection explicite
du prototype dans ce contexte. Le compilateur inscrit cet ID sur la révision de
recette immuable ; l'inventaire lit la provenance depuis cette révision publiée
exacte, jamais depuis les métadonnées mutables du registre. Une recompilation ou
la publication d'une autre révision n'hérite donc pas accidentellement de cette
provenance.
Pour creative-composition, l'autorisation générique des fixtures ne
s'applique pas : fixtures doit être vide, tandis que apiSchema et
harnessSchema doivent être omis ou vides.
Une référence runtime exacte slug@revision n'est acceptée qu'après au moins
une publication de cette révision. La provenance immuable publishedAt
maintient une ancienne référence approuvée après l'avancement du pointeur du
catalogue, tandis qu'un brouillon compilé ne peut pas être injecté dans une
page générique.
Les recettes creative-composition peuvent exprimer une topologie artistique
bornée : ratios de grille personnalisés, ordre et spans responsives,
superposition dans un canvas, récits sticky avec repli mobile linéaire,
recadrages focaux et masques d'image, rôles typographiques display, formes
décoratives, fallback d'upload explicite par e-mail et mouvement intentionnel
avec état de réduction du mouvement piloté par le runtime. Les nœuds de
formulaire et d'upload natif sont fermés par défaut derrière un registre
versionné de handlers CMS publics exacts. Le registre contient un handler
multipart : POST /api/cms/forms/personalization-request. Ses contrôles
obligatoires sont email (email), firstName (text), consent
(checkbox) et photo (upload natif images) ; birthDate (date) et
message (textarea) sont optionnels. Les noms, types et indicateurs
obligatoires doivent respecter exactement ce contrat littéral. La photo doit
être au format JPEG, PNG ou WebP et ne pas dépasser 8 Mo. Le serveur applique
l'orientation, la réencode sans les métadonnées source, réinspecte les octets
canoniques et ne stocke que cette image canonique dans le stockage privé, sans
la promouvoir dans les médias CMS. Les états d'upload et de suppression forment
un ledger durable en base ; les demandes non prêtes ou expirées ne sont jamais
exposées aux lectures opérateur. Cet endpoint crée une demande de
personnalisation destinée au suivi par un opérateur. Ce n'est pas un endpoint de
checkout, de confirmation de commande ou de paiement.
honest_form_controls exige aussi des champs et un bouton submit dans ce
formulaire actionnable enregistré ; file_upload exige son contrat POST
multipart exact. Les actions same-origin arbitraires restent refusées. Pour
tout autre handler ou action, seul email-fallback représente honnêtement la
collecte de fichiers. Les opérateurs admin traitent les demandes privées avec
yayaw_cms_personalization_requests_list,
yayaw_cms_personalization_request_get,
yayaw_cms_personalization_request_status_update,
yayaw_cms_personalization_request_delete et
yayaw_cms_personalization_requests_prune. Le prune prend en charge le dry-run
et retire les demandes dont la rétention de 180 jours est expirée. Le worker
Page AI long-lived exécute une maintenance bornée indépendamment des runs IA en
attente : il récupère les objets interrompus pendant l'upload ou la suppression
et applique la rétention. Le petit prune best-effort après une soumission
réussie ne fait que compléter cette voie worker durable. Une capacité
typographique display exige un style display autorisé
et un rôle family explicite (brand-sans, brand-serif ou brand-mono) qui
correspond à la famille de police des design tokens actifs. Les props de surface
utilisent des rôles sémantiques stables comme background, foreground,
card, muted, primary, accent et border ; elles sont résolues par le
thème actif et ne promettent pas une couleur littérale. Les anciens noms de
surface évoquant des couleurs restent des alias de compatibilité et ne prouvent
pas semantic_surfaces. Les props fonctionnelles ont aussi des types bornés et
des champs obligatoires : une chaîne comme "true" ne remplace pas un
comportement booléen au runtime. Le serveur infère creativeCapabilities
uniquement depuis un arbre déclaratif exact valide et refuse un manifeste fourni
qui prétend utiliser des primitives que l'arbre n'implémente pas. Un prototype
sélectionné déclare requiredCapabilities ; avant la persistance de la page,
chaque région mappée doit utiliser la révision publiée exacte dont les
manifestes de structure et d'implémentation dérivés côté serveur correspondent
à la topologie et aux noms/schéma/arbre canoniques enregistrés pour cette
région. Cette révision exacte doit être le composant
publié racine de la section mappée, et les bindings résolus de son instance
doivent correspondre au manifeste de rendu enregistré. new_recipe exige une
révision créée dans le même contexte et ne peut pas reprendre une topologie
compositionHash déjà présente sur une creative-composition publiée dans
l'inventaire préparé ; un nouvel ID, slug ou numéro de révision ne rend pas un
clone inédit. reuse_published exige son composant publié déclaré. Une
occurrence imbriquée du composant promis ne satisfait pas le contrat.
Le runtime versionné expose aussi les primitives de fidélité bornées suivantes
via yayaw_components_list(includeSchemas=true) :
canvas.heightacceptecontentpour une hauteur pilotée par le contenu etbandpour une scène compacte ;canvas.mobileGapcontrôle l'espacement borné lorsque les enfants s'empilent sur mobileimage.aspect,image.mobileAspectetimage.desktopAspectacceptentauto,cinema,landscape,panorama,portrait,square,strip,tallouvideo;image.heightaccepteauto,band,panelouherodecoration.treatmentacceptesolid,outlineouwash;washrend un accent pigmenté en couches et ne remplace jamais une image requiseframe.materialaccepteclean,paper,deckleoutaped;frame.rotationetplacement.rotationacceptent les valeurs bornées-6,-3,0,3ou6, ettext.style: "note"fournit un traitement de note manuscritetext.weightacceptenormal,medium,semibold,boldoublackvisibility.showaccepteall,mobileoudesktop, tandis quedisclosurerend un contrôle sémantique bornédetails/summaryaveclabelobligatoire etalign,appearance: "bare" | "framed"etsurfaceoptionnels
Ces nœuds infèrent compact_band, responsive_media, watercolor_wash,
paper_collage, typographic_weight, responsive_recomposition et
responsive_navigation uniquement depuis un comportement matériel :
compact_band exige height: "band", responsive_media exige des ratios
mobile et desktop non-auto distincts sans hauteur fixe, et
responsive_navigation exige un disclosure mobile avec une branche desktop
non vide. La planification d'un prototype conserve un ledger de faisabilité par
région. Les props d'ordre responsive (desktopOrder ou mobileOrder) exigent
un parent direct grid ou stack ; les props de span responsive
(desktopSpan ou mobileSpan) exigent un parent direct grid. Un ancêtre
compatible ne suffit pas. Chaque région déclare les nœuds allowlistés exacts, leurs chemins
canoniques (tree, puis tree.children.N récursivement), leurs props bornées,
le recipePropSchema déclaratif exact, une liste recipePropNames possédant
exactement les mêmes clés et les recipePropBindings exacts de l'instance de
section prévue. Les props requises sans défaut exigent un binding, chaque clé de
binding appartient au schéma et chaque image.src doit être exactement
$props.<identifier>, avec cette prop liée comme media_asset ou
localized_media_asset à un média durable de l'inventaire préparé.
mediaAssetIds égale l'ensemble exact et dédupliqué des IDs utilisés par tous
les bindings média. Le serveur reconstruit puis valide la recette avec le
contrat runtime canonique. Il calcule compositionHash depuis les noms de
nœuds, chemins canoniques et props structurelles uniquement, après exclusion du
contenu, des médias, actions, choix de palette surface/tone et autres props
non structurelles, avec normalisation des références runtime. Il calcule
séparément implementationHash depuis les noms/schéma/arbre et
renderManifestHash depuis cette implémentation et ses bindings, puis compare
les trois manifestes produits par le serveur à l'instance publiée exacte
utilisée à la racine de la section mappée. Un arbre différent aux mêmes
capacités grossières, un substitut imbriqué ou des bindings modifiés échouent.
Une union globale de
capacités ne peut pas masquer une région irréalisable. Pour
design_system_extension, chaque candidat A/B/C doit mapper visiblement au
moins une région vers new_recipe.
Les textes, liens, labels, placeholders, textes alternatifs et messages
d'upload visibles dans un prototype doivent chacun être un sink direct
$props.<identifier>. Les bindings de texte sont des littéraux localisés exacts
pour toutes les locales préparées ; les liens sont des cibles littérales ou
localisées sûres et bornées. Les bindings global-data critiques pour le
prototype sont refusés au lieu d'être considérés comme figés. repeat, $item
et $index sont aussi refusés : le contenu répété visible doit être développé
en nœuds planifiés explicites afin que la topologie et les bindings enregistrés
correspondent au runtime revu.
L'enregistrement du prototype exige aussi les comparaisons A/B, A/C et B/C
complètes, avec des preuves artefact-région exactes pour les deux candidats
dans chaque région stable. Les compositionHash régionaux ordonnés forment la
signature structurelle du candidat. Le manifeste normalisé du page shell est
épinglé séparément et doit correspondre exactement au candidat sélectionné dans
le plan et le runtime ; il ne fait pas partie de la signature de distinction
entre candidats. Les implementationHash et renderManifestHash régionaux
ordonnés forment les signatures d'implémentation et de rendu. Les trois
signatures A/B/C de chaque type doivent être distinctes. Des changements de
contenu, média, palette, défauts de schéma ou bindings ne transforment pas une
topologie inchangée en direction séparée. Une empreinte normalisée de matrice
d'arêtes en niveaux de gris 16 × 16, calculée côté serveur, rejette aussi les
planches clonées ou insuffisamment différentes. Ce garde-fou grossier de la
structure de la planche complète ne prouve jamais à lui seul une direction ou
une fidélité distincte ; il complète les trois signatures, la critique par
paires, l'inspection visuelle et une Visual QA substantielle.
L'enregistrement exact-runtime utilise kind: "generated_set_v2". Avant cet
enregistrement, chaque image de récit ou de recette utilisée par ces bindings
est finalisée avec MIME image, dimensions et provenance SHA-256, puis ajoutée
par l'unique refresh média-only de présélection. Les planches et les captures
runtime post-enregistrement sont interrogées directement par ID et ne doivent
pas déclencher d'autre refresh d'inventaire. Chaque candidat fournit un
pageShell exact (layout et designTokens de page bornés ou null) et des
artifactBounds entiers pour chaque région visible. Une région mesure au moins
200 × 120 pixels et 2 % de la planche, leur union couvre au moins 40 %, et le
chevauchement de deux régions ne dépasse pas 50 % de la plus petite. Hors du
scope d'une page globale, les tokens de page valent obligatoirement null. Pour
chaque paire de candidats, au moins une empreinte de région correspondante doit
être matériellement distincte ; le chrome de la planche seul ne suffit pas.
Le client fournit les arbres, schémas, bindings et bounds prévus, jamais les
hashes dérivés de composition, implémentation, rendu, page shell, fingerprint ou
runtime. Le serveur calcule ces champs et résout chaque candidat via les
runtimes canoniques de page et de recette. L'enregistrement renvoie les aperçus
runtime signés et un runtimeHash par candidat. Le Visual QA compare chaque
planche pour toutes les locales préparées en desktop/mobile et clair/sombre,
uploade chaque capture pleine page distincte avec le contexte, le hash runtime
et le rôle exacts renvoyés, puis appelle
yayaw_cms_prototype_runtime_review_complete. La valeur visual_qa est un rôle
logique de l'acteur courant, pas la preuve d'un reviewer authentifié
indépendamment. Les planches et les aperçus runtime restent des artefacts
visuels séparés : manifestes et hashes détectent substitution ou dérive, sans
prouver une équivalence de pixels.
En production, la résolution runtime échoue de façon fermée sans fingerprint
immuable fourni par NEXT_DEPLOYMENT_ID, le gitCommitSha résolu tel que
DEPLOYMENT_GIT_COMMIT_SHA, ou le deploymentId résolu ; "local" est un
fallback réservé aux environnements hors production. Le fingerprint de
déploiement et la version du contrat renderer entrent dans runtimeHash : un
changement de build renderer invalide donc la revue antérieure.
La sélection est bloquée tant que cette revue runtime n'est pas courante. Une modification du renderer, du déploiement, d'une recette, d'un média, d'une capture ou des tokens peut la rendre périmée. Un changement de design tokens après l'enregistrement impose un nouveau contexte préparé et trois nouveaux candidats. Après sélection, les révisions de recettes exactes peuvent être importées et publiées, puis un refresh avec les mêmes tokens précède le plan strict version 2. Ce plan reproduit exactement le layout du page shell et la couche de tokens de page du candidat sélectionné.
En production, l'enregistrement v2 n'est activé qu'après le rollout
reader-first : CMS_PROTOTYPE_RUNTIME_V2_WRITES_ENABLED est désactivé par
défaut et reste à false pendant que le build reader-compatible remplace et
draine toutes les instances antérieures. Il ne passe à true qu'une fois ce
build devenu le rollback floor. Le champ v2 séparé ne sécurise pas à lui seul
une flotte mixte. Dès qu'un contexte v2 existe, ne jamais rollback vers un build
antérieur au reader ; avancer uniquement en roll-forward jusqu'au retrait ou à
la migration de ces contextes. L'enregistrement legacy reste lisible et
écrivable pendant cette phase pour la compatibilité de transition, mais un
nouveau workflow exact ne doit pas s'y rabattre. Le writer désactivé renvoie
cms_design_prototype_runtime_rollout_pending. En local et dans les autres
environnements hors production, les écritures v2 sont activées par défaut
lorsque la variable est absente.
Indications d'usage pour le planificateur de blocs
Le planificateur IA de blocs consomme les indications d'usage du catalogue quand elles sont disponibles :
- court extrait d'exemple depuis le contexte CLI/persisté
- dépendances clés de registre
- liens docs/exemples
Ces métadonnées sont en lecture seule et passées dans le payload de prompt pour améliorer la sélection de composants et de props dans les arbres de blocs générés. Elles n'exécutent aucun code source DB.
Enrichissement de contexte CLI-first
Les imports résolvent maintenant le contexte depuis la CLI shadcn officielle en premier, puis appliquent des fallbacks déterministes.
Points d'implémentation :
src/lib/server/actions/components/component-registry-actions.tssrc/lib/server/services/components/ui-component-shadcn-cli-context.tssrc/lib/server/services/components/shadcn-cli-runner.tssrc/lib/server/services/components/ui-component-recipe-import-enrichment.tssrc/lib/server/services/components/ui-component-import-preview-evidence.ts
Comportement :
- le runner CLI est local-first (
bunx shadcn) avec fallbacknpx -y shadcn@latest, timeout, retry et logs structurés - le résolveur agrège :
- métadonnées/fichiers de payload
shadcn view - liens
shadcn docs --jsonpour les composants shadcn principaux shadcn search+shadcn viewpour les blocs d'exemples de registre
- métadonnées/fichiers de payload
- le contexte résolu inclut :
sourceTitle/sourceDescriptionexampleSnippetsregistryDependencies- liens de docs (
docs,examples) - indice d'interaction (
click-trigger,selectionou fallback inline)
- la priorité des preuves d'aperçu est déterministe :
CLI -> payload -> web -> source snapshot - le contexte est mis en cache dans les métadonnées d'import par
sourceHash(contextVersion, liens, extraits, dépendances), ce qui évite les appels CLI répétés lors des imports répétés - quand le contexte CLI est indisponible, l'import reste non bloquant et le comportement de garde compilation/publication ne change pas
- aucun code source externe n'est exécuté ; seules les métadonnées et snapshots sont parsés
Politique interaction-first :
- les aperçus de type overlay doivent préférer des déclencheurs de clic explicites plutôt que des états toujours ouverts
- les blueprints IA composites sont neutres par défaut (pas de microcopy spécifique IA/chat sauf si les preuves source l'exigent explicitement)
Comportement des design tokens
L'aperçu du catalogue ne dépend pas uniquement du CSS de base.
Il résout les tokens runtime effectifs pour la session courante (surcharges globales + organisation) et applique des variables CSS scopées à la surface d'aperçu. Cela permet aux utilisateurs du dashboard de valider les composants UI contre les mêmes valeurs de tokens sémantiques que celles utilisées au runtime.
Validation
La cohérence du registre est validée par des tests :
- unicité des ids d'entrée
- existence des fichiers source
- références
demoIdrésolues par la carte de démo
Gardes runtime/catalogue :
- aucune exécution de code DB (les snapshots source ne sont jamais évalués)
- publication bloquée quand les diagnostics de compilation ou le smoke render échouent
- les extensions du design system importent les nouvelles recettes seulement
après la sélection du prototype avec le
designContextIdactif ; l'inventaire actualisé lit cette provenance sur la révision publiée immuable exacte created_component_not_newbloque un composant déjà présent dans la baseline initiale etcreated_component_context_mismatchun composant importé par un autre workflowcreated_component_not_usedbloque un composant déclaré comme créé mais absent des nouvelles compositions, y compris si une autre révision du même slug est utilisée
Commandes utiles :
bun test src/components/ui/catalog/registry.test.ts
bun test src/lib/server/services/components/ui-component-recipe-compiler.test.ts
bun test src/lib/server/services/components/ui-component-catalog-query.test.ts
bun run components:generate-ai-elements-previewsVariables d'environnement
OPENAI_API_KEYOPENAI_COMPONENTS_AI_FALLBACK
Ces variables OpenAI sont optionnelles et n'affectent que l'enrichissement AI SDK
pour les composants importés. Les surcharges locales d'aperçu AI Elements sont
entièrement déterministes et ne requièrent pas OPENAI_API_KEY.
Direction du contrat
- scope produit global
- stockage de snapshot source pour audit/rejeu
- aucune exécution runtime de code stocké en DB
Type de référence :
UiComponentRegistryItemV1danssrc/components/ui/catalog/types.ts
Tables DB :
ui_component_registry_itemsui_component_recipe_revisionsui_component_publications