EngineeringBlueprint des apps de la famille

Blueprint des apps de la famille

Le tronc commun que chaque app du produit doit porter, l’état d’Orbit contre les dépôts de référence et la liste P0/P1/P2.

Statut (2026-10-02) : première version. Elle fixe ce que chaque app du produit doit porter, où Orbit en est, et ce qu'il reste à faire, avec une priorité et un effort. Elle se lit avec les skills .claude/skills/ (procédure pour les agents) : new-app-blueprint, launch-attribution, billing-stripe, transactional-email, seo-aeo-geo, platform-ops, admin-structure.

Pourquoi ce document existe

Le fondateur exploite plusieurs apps. Deux dépôts de référence, en lecture seule, portent ce qui a déjà été appris :

RepèreDépôtCe qu'on y lit
ABoostEcom/boostecom.apple système le plus optimisé : mesure, attribution, Stripe, e-mail, SEO/AEO, exploitation, gardes
BBoostEcom/easyconnector.appla structure d'admin et d'app (onglets par groupe de routes)

Orbit n'a aucune plateforme parente (AGENTS.md, règle 1) : on copie des patterns avec leur garde, jamais des fichiers, jamais des valeurs, jamais des secrets. Ces dépôts ne sont jamais modifiés depuis ici.

La culture à reprendre (le vrai blueprint)

Toute règle écrite est tenue par un test, un script, un hook ou un workflow CI. Une règle qui ne vit que dans la prose se périme. Quand on ajoute une règle à AGENTS.md ou à un skill, on ajoute sa garde dans la même PR, ou on dit pourquoi aucune garde ne peut la tenir (par exemple : « seule la relecture peut refuser une valeur copiée », règle 2).

Gardes de ce blueprint : apps/web/src/test/blueprint-claims.test.ts (chaque chemin cité par les skills existe, les deux shas de référence sont enregistrés) et audit-orbit-claims.mjs (dossier scripts de ce dépôt de documentation : chaque chemin cité par cette page existe dans le dépôt applicatif), apps/web/src/test/workflow-pins.test.ts (chaque action des workflows est épinglée par SHA), .github/workflows/secret-scan.yml, .github/workflows/dependency-watch.yml, .github/workflows/blueprint-watch.yml.

Les forces d'Orbit à ne pas régresser

ForceOùLes références font moins bien
Migrations Prisma versionnées, fichier PHASE, pnpm db:drift, garde « base étrangère »packages/db, skill databaseA synchronise le schéma avec prisma db push et un « schema guard » ; la base unique sert de prod
Proxy fail-closed + CSP à nonce par requête (strict-dynamic)apps/web/src/proxy.ts, apps/web/src/lib/security/headers.tsB garde 'unsafe-inline'
Stripe par lookup_key, script de catalogue avec dry-run, table StripeEvent idempotenteapps/web/src/modules/billing, apps/web/scripts/stripe-catalog.mjsB : webhooks sans table d'idempotence
Back-office séparé (projet Vercel à part, Vercel Authentication, 503 par défaut)apps/adminA et B mêlent l'admin à l'app
Environnement qui refuse les secrets d'un autre produitapps/web/src/env/schema.ts, apps/admin/src/env/schema.tsaucun équivalent
Thème sombre par jetons, aucune classe hexapps/web/src/test/dark-only.test.tsB : couleurs hex
Un seul ci.yml épinglé par SHA, concurrency: cancel-in-progress.github/workflows/ci.ymlB : aucune CI
Nommage d'infra = slug du projet VercelAGENTS.md « Infrastructure naming »variable selon les apps

À ne pas copier

prisma db push, le schema guard généré, ignoreBuildErrors, la base unique qui sert de prod, l'absence de CI, 'unsafe-inline' dans la CSP, les webhooks sans table d'idempotence, les couleurs hex, le mélange db:migrate / db:push, un utm_source égal au nom du produit, et tout secret ou identifiant d'un autre produit (variables Orbit : préfixe ORBIT_*).

Tableau d'écarts : Orbit contre les références

Priorité : P0 = avant le lancement (il manque une mesure ou une protection) ; P1 = dans le mois qui suit ; P2 = quand le besoin se confirme. Effort : S (< 1 jour), M (1 à 3 jours), L (> 3 jours).

#DomaineÉtat d'OrbitRéférencePrioEffortStatut
aMesureapps/web/src/lib/analytics/datafast.ts servait le script sans cookie et affirmait « no Stripe checkout » : faux depuis la facturation. Pas de barrière de consentement (état avant ce lot)A : variante cookie derrière ThirdPartyConsentGate, datafast_visitor_id en métadonnées du checkout, gardes dans les deux sensP0Mcode fait (launch-p0) : variante cookie première partie, bannière + ThirdPartyConsentGate, datafast_visitor_id en métadonnées du checkout ; reste l'action propriétaire (site DataFast, objectifs, Stripe connecté : la checklist de lancement)
bAttributionaucune capture de premier contactA : acquisition.ts (cookie premier contact après consentement, jamais écrasé, ref + UTM)P0Mcode fait : cookie premier contact après consentement, jamais écrasé, persisté à l'inscription (Workspace.acquisition, migration 20261002160000), lu par l'app admin, objectifs serveur signup / checkout_started / subscription_started, constructeur utmFor
cFacturationcycle de vie des abonnements et invoice.payment_failed seulement ; pas de Stripe Tax ; ni remboursement, ni litige, ni invoice.paid, ni invoice.payment_action_requiredA : services/webhooks.ts (liste complète, crédits depuis la métadonnée nette), cron de réconciliationP0Lcode fait (rebase sur le flux lot1 à surveiller : mêmes fichiers) : Stripe Tax derrière ORBIT_STRIPE_TAX, invoice.paid, invoice.payment_action_required, charge.refunded, litiges, politique de retenue testée, cron reconcile-stripe ; reste l'action propriétaire (endpoint, Tax)
dE-mailResend via l'intégration Vercel, sans domaine d'envoi authentifié propre à Orbit pour les codes OTPA : apex authentifié (SPF, DKIM, DMARC), sous-domaine séparé pour le marketingP0S (action propriétaire : DNS + Resend) puis S (code)code fait : quatre e-mails de facturation, une mise en page, jetons, deux langues ; reste le domaine d'envoi authentifié (propriétaire, runbook section 4)
eSecretsaucune analyse de secrets en CIA : secret-scan.yml (gitleaks épinglé, historique complet)P0Sfait dans cette branche (.github/workflows/secret-scan.yml)
fDépendancesrien entre deux PRA : dependency-watch hebdomadaireP1Sfait dans cette branche (.github/workflows/dependency-watch.yml)
gBlueprintaucune détection de dérive des références(nouveau)P1Sfait dans cette branche (.github/workflows/blueprint-watch.yml, scripts/blueprint-drift.mjs)
hFunnel exactpas de table de jalons ; le funnel dépendrait de DataFastA : UserMilestone écrit dans la même transaction que le fait métierP1Mà planifier
iLiens sortantspas de constructeur d'UTM uniqueA : un constructeur unique, utm_source = la plateformeP1Sfait avec (b) (apps/web/src/lib/analytics/utm.ts)
jRéconciliationpas de cron de réconciliation StripeA : api/cron/reconcile-stripeP1Mfait avec (c) (/api/cron/reconcile-stripe)
kE-mailpas de gabarits React Email partagés, pas de webhook ResendA : modules/email (un client, mise en page, jetons, désabonnement, Svix)P1Laprès (d)
lSEO / AEO / GEOrobots.ts à une règle ; sitemap = la home ; ni llms.txt, ni JSON-LD, ni images OG dynamiquesA : robots-policy, llms*.txt, JSON-LD, OGP1Mles pages marketing relèvent du flux « landing » ; la politique de crawl demande la décision du propriétaire
mExploitationpas de moniteur externe sur /api/health, pas de checklist du tableau de bord Vercel, pas de runbook de rotation des secretsA : A:docs/ops/vercel-dashboard-checklist.md, A:docs/ops/secret-rotation.mdP1Sskill platform-ops ; cases à cocher par le propriétaire
nAdminapps/admin couvre vue d'ensemble, espaces, admins ; pas de changelog, roadmap, FAQ, retours, couponsB : onglets par groupe de routesP1Lpar module, voir skill admin-structure
oDonnées personnellesni suppression de compte, ni export des donnéesA : gdpr-erasureP1Là planifier
pBudget d'AGENTS.mdaucun plafond de tailleA : A:src/test/claude-md-budget.test.tsP2Snon fait : le fichier est court ; à ajouter si les lots le font grossir
qCitations IAaucune mesureA : cron aeo-citationP2Mà planifier
rLancementpas de phases de lancement (liste d'attente, bêta) ni de couponsA : launch-tick, couponsP2Mà planifier
sCode mortpas de détectionA : deadcode.yml, knip.jsonP2Sà planifier

La liste P0

Statut (2026-10-02) : le code de (a), (b), (c) et la partie code de (d) est livré sur la branche launch-p0 ; ce qu'il reste est côté propriétaire et tient dans la checklist de lancement (site DataFast et objectifs, endpoint webhook Stripe avec les nouveaux événements, Stripe Tax, domaine d'envoi Resend, CRON_SECRET).

  1. (a) Variante cookie de DataFast, barrière de consentement, datafast_visitor_id (et datafast_session_id) dans les métadonnées du checkout, sur la session et sur subscription_data, gardes dans les deux sens ; corriger le commentaire de lib/analytics/datafast.ts.
  2. (b) Capture du premier contact (cookie après consentement, jamais écrasé, ref et UTM) et persistance sur le Workspace (migration versionnée).
  3. (c) Stripe Tax ; événements remboursement, litige, invoice.paid, invoice.payment_action_required ; crédits accordés depuis la métadonnée nette.
  4. (d) Domaine d'envoi Resend authentifié (SPF, DKIM, DMARC) pour les codes OTP.
  5. (e) Analyse de secrets : fait dans cette branche.

Qui fait quoi pour éviter les doublons. Le flux « facturation / Brain / admin / i18n de l'app » travaille dans modules/billing (plans et quotas) : (c) et la partie checkout de (a) attendent sa fusion. Le flux « landing » travaille dans (marketing) et i18n : (l) et la bannière de consentement de (a) passent par lui. Cette branche ne touche ni l'un ni l'autre.

Dernière synchronisation

La sha de HEAD lue pour chaque dépôt de référence, et la date de la lecture, sont enregistrées dans le fichier de données .github/blueprint-shas.json du dépôt applicatif : c'est l'unique enregistrement, lu par scripts/blueprint-drift.mjs et par le workflow blueprint-watch. Cette page ne les recopie pas.

Les dépôts de référence sont privés : blueprint-watch a besoin d'un jeton en lecture seule (voir .github/workflows/blueprint-watch.yml). Ne modifier le fichier de shas qu'après avoir relu les changements entre la sha enregistrée et la nouvelle (skill new-app-blueprint, section 5).

Mettre à jour le blueprint

  • Une PR qui ajoute une garde à une app met aussi ce fichier à jour (une ligne du tableau d'écarts, ou la liste des forces).
  • Quand blueprint-watch ouvre l'issue « Blueprint drift » : lire (lecture seule) les changements des références, porter ce qui vaut la peine avec sa garde, mettre à jour .github/blueprint-shas.json (dépôt applicatif) et cette page dans leurs PR respectives.
  • Les références restent en lecture seule : aucun commit, aucune branche, aucune configuration.