/docs

Documentation North

Ce produit est un socle SaaS. Les pages techniques (compte, espaces, modules) sont des parcours terminés. Ajoutez uniquement le métier. Un seul catalogue décrit le statut : pas de pourcentage global. Un runtime-pass prouve un scénario, pas toute une fonctionnalité.

Compte, espace, produit, admin et configuration suivent la navigation groupée. Langue et thème se changent depuis le menu utilisateur. La preuve par scénario reste dans FEATURE_MATRIX ; le statut par fonctionnalité est ci-dessous.

Démarrage produit

  1. 1. Clone et install figé

    Node 22+, pnpm 10.33.3, OpenSSL, Docker Compose. Ce checkout fournit le CLI (`pnpm north:create`). Ne pas copier les .env d’un autre produit.

    pnpm install --frozen-lockfile
  2. 2. Générer un produit hors checkout

    Construire une candidate puis `north create`. Destination neuve, hors worktree. Presets reçus : personal-free, organization-free, hybrid-free, billing-test, enterprise-test, mobile-smoke. Les presets free gardent billing, API, webhooks, SSO, SCIM, MCP OFF. Détail : docs/CREATE.md. Le legacy `pnpm create:product` reste jusqu’à NR-26.

    pnpm release:qualified -- --out .data/release-candidate-qualified --allow-dirty
    pnpm north:create -- --destination ../acme --app-id acme --name Acme --preset personal-free --manifest .data/release-candidate-qualified
  3. 3. Secrets

    Le générateur écrit un .env.local distinct (mode 0600) : AUTH_SECRET, audience, ports et base nouveaux. Infisical possède les secrets d’environnement. La console n’accepte aucun secret. NORTH_SKIP_INFISICAL=1 est local uniquement.

    See docs/INFISICAL.md and docs/ENV_CATALOG.md
  4. 4. Services locaux et Portly

    Dans le produit généré : inspecter Portly avant tout start. `local-up` refuse 3000/3001/3210/3211/8025/1025/5432 et n’adopte pas un processus étranger. Checkout North : ports développeur 3000/3001/3210/3211 — n’arrêter que les PID enregistrés de ce checkout. Protocole : docs/UPGRADING_STARTER.md §8 et docs/OPERATIONS.md.

    node scripts/portly.mjs status
    node scripts/local-up.mjs
    node scripts/local-down.mjs
    portly status --json
    pnpm run setup --mode autonomous
    pnpm run doctor
    bash scripts/stop-stack.sh
  5. 5. Premier compte et owner

    S’inscrire, vérifier l’e-mail dans Mailpit, terminer l’onboarding. Le premier utilisateur n’est pas administrateur plateforme. Bootstrap admin seulement sur un compte déjà existant.

    pnpm --filter @north/auth exec tsx src/bootstrap-admin.ts [email protected]
    Open http://localhost:3000/configure
  6. 6. Publier modules et quotas

    Config effective = preset Git + overrides SQL + secrets Infisical. Un save peut rester restart_required jusqu’à ACK Auth, ou migration_required s’il y a des données. NORTH_CONFIG_FILE pointe sur config/<app-id>.json.

    pnpm config:apply --patch config/acme.json
  7. 7. Première fonctionnalité métier

    Dans le produit : table, permission `product.<slug>.*`, page, quota, notification et handler lifecycle — sans éditer vendor/ ni les packages North. Recettes : docs/RECIPES.md.

    node scripts/add-feature.mjs --id notes --title-fr Notes --title-en Notes
  8. 8. Tests

    Les suites d’intégration créent un stack QA isolé. Elles refusent les ports 3000/3001/3210/3211/8025. NORTH_ENV_FILE explicite. Un typecheck n’est pas un build natif.

    pnpm test:unit
    pnpm test:integration
    pnpm test:e2e
    pnpm test:mobile-contract
  9. 9. Mettre à jour le produit

    Lecture seule puis apply local. Compatibilité N−1, reprise `.north/upgrade-apply.json`, rollback par revert des writes — jamais git reset. Registre : vendor/*.tgz tant que `publisher.registry` reste `unspecified`. Voir docs/UPGRADING_STARTER.md et docs/UPGRADE.md. Nettoyage du schéma Convex après une mise à jour North (par exemple l’ancienne table `extracteurJobs`) : [EXTRACTEUR-SPLIT.md](EXTRACTEUR-SPLIT.md#mise-à-niveau-dune-stack-qui-contient-déjà-des-jobs-extracteur).

    pnpm north:doctor -- --product ../acme --manifest .data/release-candidate-qualified
    pnpm north:plan -- --product ../acme --manifest .data/release-candidate-qualified
    pnpm north:apply -- --product ../acme --manifest .data/release-candidate-qualified
  10. 10. Exploitation

    deploy-check, backup chiffré, restore isolé. Candidates locales expérimentales (NR-05) et qualifiées (NR-29) : pas de publication ni d’activation payante. Voir docs/RELEASE.md et docs/OPERATIONS.md. Preuve notifications A→B : bash tests/reuse/notifications-upgrade/run.sh. Réception mixte tâches/dossiers + hybrid (NR-27) : bash tests/reuse/acceptance/run.sh. Candidate complète (NR-29) : bash tests/reuse/release-candidate/run.sh.

    pnpm deploy:check
    pnpm backup
    pnpm restore:verify
    pnpm release:validate -- .data/release-candidate-qualified

Statut par fonctionnalité

Couches séparées : implémentation, UX, tests locaux, cloud, natif, CI, déploiement.

Déjà fusionné (ne plus marquer ouvert)

  • #24–#36 — Invitations, fichiers, webhooks, preuves de confidentialité, OAuth localhost, avatar, notifications, droits, cycle de vie d’organisation (#37, #38, #39, #40, #41, #42, #43, #44, #45, #46, #47, #48, #49)
  • #51 — Rejeu de sécurité / pont Auth → Convex (#51)
  • #52 — Hooks Git Lefthook (pre-commit / commit-msg / pre-push) (#52)
  • #20 — Navigation groupée, locale initiale, thème light/dark/system, destination /docs (#53)

Écarts produit restants

  • #21 — Uploads, MFA et grants produit (travail profond). Les parcours locaux TOTP, fichiers et droits existent. Le ticket couvre un approfondissement produit, pas une absence totale.

Compte e-mail / mot de passe

Identité

Inscription, vérification Mailpit, restriction des comptes non vérifiés, récupération.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Magic link et politiques d’auth

Identité

Magic link, changement d’e-mail, modes passwordless / vérification optionnelle persistés en SQL.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

OAuth local et fournisseurs cloud

Identité

Stub local + canonisation localhost / 127.0.0.1. Google/GitHub/Discord/Apple restent sans clés.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
optionnel-externe
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

TOTP, codes de récupération, passkeys

Identité

Parcours Chromium réels. Invites OS passkeys et approfondissement MFA : voir #21.

Implémentation
disponible
UX
en cours
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Écarts: #21

Sessions, révocation, historique

Identité

Deux appareils, révocation distante, déconnexion globale, historique isolé de PostHog.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
disponible
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Pont JWT Auth → Convex

Identité

aud/iss, JWT expiré, refresh concurrent, JWKS, projection manquante, rejeu, crash mid-revoke.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
disponible
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Tenancy personnel / organisation / hybride

Espaces

Modes, switcher, matrice de rôles, isolation, dernier owner, départ / transfert / fermeture.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Invitations d’espace et de plateforme

Espaces

E-mail, acceptation, refus, resend, jetons plateforme vs membres Convex.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=off · organization-free=on · hybrid-free=on · billing-test=off · enterprise-test=on · mobile-smoke=off

Fichiers privés et quotas

Modules

Tickets one-use, pagination, capabilities liées au membership, module OFF. Uploads avancés : #21.

Implémentation
disponible
UX
en cours
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Écarts: #21

Avatar de profil

Compte

Stockage Convex personnel, magic-bytes, jetons de vue. Parcours navigateur isolé encore non exécuté.

Implémentation
disponible
UX
non testé
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Export / suppression et preuves d’identité

Compte

UI /account/privacy, preuves HMAC, JWT renouvelé ≠ preuve.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Notifications

Modules

Inbox paginée, préférences, producteurs, pas de canal Push fantôme, module OFF.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Blog, changelog et référencement

Modules

Contenu versionné local, brouillons noindex, sitemap/robots, JSON-LD seulement avec des prix réels. OFF par défaut.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=off · organization-free=off · hybrid-free=off · billing-test=off · enterprise-test=off · mobile-smoke=off

Écarts: #23

E-mail local et Resend

Intégrations

Mailpit, retry SMTP, webhook Svix local. Quota Resend Cloud et domaine non exercés.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
optionnel-externe
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

PostHog consentement / redaction

Intégrations

SDK réel intercepté, refus/retrait, PII masquée. Projet PostHog Cloud EU non contacté.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
optionnel-externe
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=off

Facturation test et droits

Facturation

Checkout local, événements signés, catalogue versionné. Stripe Cloud non exercé. OFF sur presets free.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
optionnel-externe
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=off · organization-free=off · hybrid-free=off · billing-test=on · enterprise-test=on · mobile-smoke=off

Écarts: #21#91

Clés API

Modules

Portée, expiry, rotate, journal borné. OFF sur presets free.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=off · organization-free=off · hybrid-free=off · billing-test=off · enterprise-test=on · mobile-smoke=off

Webhooks sortants

Modules

SSRF local, test send, historique, récepteur HTTPS QA. Livraison Internet publique non revendiquée.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
optionnel-externe
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=off · organization-free=off · hybrid-free=off · billing-test=off · enterprise-test=on · mobile-smoke=off

Écarts: #86

SSO / SCIM locaux

Entreprise

Keycloak OIDC/SAML + SCIM officiel. IdP cloud non exercé. Restart Auth requis.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
optionnel-externe
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=off · organization-free=off · hybrid-free=off · billing-test=off · enterprise-test=on · mobile-smoke=off

MCP authentifié

Entreprise

Outils lecture, refus cross-workspace, écritures non publiées refusées. OFF sur presets free.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=off · organization-free=off · hybrid-free=off · billing-test=off · enterprise-test=on · mobile-smoke=off

Console propriétaire et config effective

Configuration

SQL + presets Git + Infisical. États applied / restart_required / migration_required. Premier user ≠ admin.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Génération de produit

Configuration

north create (NR-22/23) génère depuis une release immuable (liste positive, north.json). Six presets reçus. create:product legacy reste jusqu’à NR-26. Parcours agent : GETTING_STARTED, RECIPES, UPGRADING_STARTER.

Implémentation
disponible
UX
n/a
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Backup, restore, doctor, hooks

Exploitation

Snapshot chiffré local, restore isolé, Lefthook. Scan Secret GitHub sur main : limite de dépense, pas une fuite.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
optionnel-externe
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Réutilisation native

Mobile

SDKs partagés, iOS simulateur Release. Android et appareils physiques non exécutés.

Implémentation
disponible
UX
non testé
Tests locaux
disponible
Cloud
n/a
Natif
disponible
CI
disponible
Déploiement
non testé

Presets: personal-free=n/a · organization-free=n/a · hybrid-free=n/a · billing-test=n/a · enterprise-test=n/a · mobile-smoke=on

a11y, responsive, locales, thèmes

Interface

FR/EN, 375/642, dark, clavier, axe 0 sur les parcours de réception. PR #53 a livré la nav groupée, le thème light/dark/system et la locale initiale. Rejeu 3 presets du chrome neuf : voir U01/U02, pas un écart produit ouvert.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
disponible
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Système de design Untitled UI

Interface

Interface sur les composants Untitled UI. Contrat : docs/design-system/UNTITLED-UI.md. @north/untitled-ui est le miroir épinglé ; @north/web-ui porte les compositions.

Implémentation
disponible
UX
disponible
Tests locaux
disponible
Cloud
n/a
Natif
n/a
CI
non testé
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Déploiement production

Exploitation

Compose + Caddy documentés, images locales testées. Aucun déploiement DNS/prod ni activation payante.

Implémentation
disponible
UX
n/a
Tests locaux
disponible
Cloud
optionnel-externe
Natif
n/a
CI
optionnel-externe
Déploiement
non testé

Presets: personal-free=on · organization-free=on · hybrid-free=on · billing-test=on · enterprise-test=on · mobile-smoke=on

Recettes métier

Domaine / table / permission

Schéma Convex, garde d’autorisation backend, contrat partagé.

Produit généré : 1) table dans convex/schema.product.ts (refs = strings publiques north.workspace_id / north.user_id). 2) permissions `product.<slug>.*` dans src/lib/extensions.ts — ne pas éditer PERMISSIONS North. 3) mutation dans convex/product.ts : establishPermission / assertModule côté serveur, jamais args.userId client. 4) `node scripts/add-feature.mjs --id notes --title-fr Notes --title-en Notes` écrit ces fichiers et pose coreEdited=false. 5) Ne pas toucher vendor/ ni packages/*.

  • convex/schema.product.ts
  • convex/product.ts
  • src/lib/extensions.ts
  • docs/adr/contracts/09-product-feature-examples.md
  • packages/backend/convex/lib/authz.ts
  • packages/backend/convex/lib/facade.ts

Authz uniquement dans les helpers backend. Les clients natifs appellent les mêmes fonctions.

Page web

Route fichier, navigation, états, i18n.

Produit : src/routes/_app/<feature>.tsx (createFileRoute) + entrée PRODUCT_SHELL_NAV dans src/lib/navigation.ts (`group: "product"`, module `product.<slug>.<id>`). États loading / vide / erreur / interdit. Overlay i18n/thème produit. add-feature crée la route mince. Checklist avant de déclarer terminé. Un écran North se monte par ports ; un fork devient code produit.

  • src/routes/_app/
  • src/lib/navigation.ts
  • docs/PAGE_CHECKLIST.md
  • packages/web/workspace/INTEGRATOR.md

La page web n’est pas le contrat mobile. Toute écriture métier passe par Convex.

Upload

Fichiers d’espace vs avatar de profil.

Documents d’espace : api.files.generateUploadUrl → POST CONVEX_SITE_URL/files/upload avec le ticket one-use → createDownloadToken pour lire. Quota via resolveWorkspaceEntitlements (plan, puis grant, puis cap déploiement). Avatar : packages/backend/convex/avatars.ts, stockage personnel, indépendant du module files et du workspace actif. Le parcours navigateur avatar isolé n’est pas encore une preuve runtime.

  • packages/backend/convex/files.ts
  • packages/backend/convex/avatars.ts
  • apps/web/src/routes/_app/files.tsx
  • apps/web/src/routes/_app/account.profile.tsx

Les tokens de vue sont courts. Ne pas persister d’URL publique de fichier dans le client natif.

Notification

Émettre depuis n’importe quel module métier.

Depuis une mutation produit déjà autorisée : emitNotification / emit via le port (`type` métier libre, catégorie security | account | system). Ne pas éditer `@north/convex-notifications`. Prefs et module OFF sont relus à l’émission. Module notifications OFF = no-op, la ligne métier reste écrite. Preuve A→B sans réécrire les fichiers produit : bash tests/reuse/notifications-upgrade/run.sh.

  • convex/product.ts
  • packages/convex-notifications/src/index.ts
  • packages/backend/convex/lib/notify.ts
  • packages/backend/convex/lib/coreNotificationPrefs.ts
  • tests/reuse/notifications-upgrade/README.md

L’inbox est une query Convex. Un client Expo peut s’abonner sans passer par le routeur web.

E-mail

Auth essentiel vs notifications optionnelles.

Vérification, reset, magic link : mailer Auth (Mailpit local, Resend en production). Invitations d’espace : invitations.deliverEmail. Notifications optionnelles : queueNotificationEmail. Un échec SMTP ne casse pas le produit (E01). Le quota Resend Cloud n’a pas été exercé (E02).

  • apps/auth/src/
  • packages/backend/convex/lib/notifyQueue.ts
  • docs/INTEGRATIONS.md

Les clients n’envoient pas d’e-mail. Ils déclenchent des mutations qui filettent le travail.

Quota / entitlement

Catalogue versionné, pas des compteurs démo.

Produit : déclarer la clé `product.<slug>.*` dans src/lib/extensions.ts (quotas + plan overlay). reserveQuota / releaseQuota / confirmQuota dans la même mutation que l’insert (convex/product.ts). Ne pas activer billing dans un preset free pour « tester » un compteur. Catalogue North : plan, puis grants, puis cap déploiement via `@north/convex-core`. Preuve concurrence table métier : bash tests/reuse/convex-core-entitlements/run.sh. Stripe Cloud n’est pas cette vérification.

  • src/lib/extensions.ts
  • convex/product.ts
  • packages/contracts/src/entitlements.ts
  • packages/convex-core/src/entitlements-engine.ts
  • packages/backend/convex/lib/coreEntitlements.ts

Le catalogue vit dans @north/contracts, donc web et mobile voient les mêmes plafonds.

Job d’arrière-plan

Planifier, relire config, respecter module OFF.

Utiliser ctx.scheduler.runAfter depuis une mutation. Exemples : notifications.deliverEmail, files.cleanupAbandoned, privacy chunks, invitations.deliverEmail, feedback.deliver. Le job doit rappeler runtimeModuleOn / préférences avant une livraison optionnelle. Les e-mails d’auth restent dans le service Auth, pas dans Convex.

  • packages/backend/convex/notifications.ts
  • packages/backend/convex/files.ts
  • packages/backend/convex/privacy.ts
  • packages/backend/convex/invitations.ts

Pas de cron Node dans apps/web. Le mobile ne déclenche pas les jobs directement.

Module optionnel

Preset, console, garde backend, UI.

Déclarer le flag dans @north/contracts MODULE_IDS et packages/config. Preset free = OFF pour billing/api/webhooks/SSO/SCIM/MCP. assertModule aux points d’entrée et runtimeModuleOn dans les producteurs. L’UI utilise ModuleOff sur l’URL directe. Publier via /configure ou pnpm config:apply, puis restart Auth si des plugins froids changent.

  • packages/config/src/presets.ts
  • packages/backend/convex/lib/authz.ts
  • packages/backend/convex/lib/runtimeConfig.ts
  • apps/web/src/components/PublicChrome.tsx

Les clients lisent publicCapabilities. Un flag client ne doit jamais autoriser une mutation.

Blog / changelog / SEO

Publier un article et une nouveauté sans CMS externe.

1) Activer modules.marketing (ou --with-marketing à la génération). 2) Ajouter un fichier `apps/web/content/blog/{slug}.{fr|en}.md` et `changelog/{slug}.{fr|en}.md` avec frontmatter validé. 3) `draft: true` sert la page en noindex et l’exclut du sitemap et des listes. 4) site.url alimente canonical, Open Graph, sitemap.xml et robots.txt. 5) JSON-LD SoftwareApplication seulement si /pricing affiche des prix réels. Les pages légales restent des modèles, pas un avis juridique.

  • apps/web/content/
  • apps/web/src/lib/seo.ts
  • apps/web/src/routes/blog.index.tsx
  • packages/config/src/content.ts
  • packages/config/src/seo.ts

Le contenu marketing est web-only. Pas de table Convex ni de client natif.

Extensions produit typées

Permissions, modules, plans et quotas namespacés sans éditer les sources North.

1) Déclarer un overlay `product.<slug>.*` via composeProductExtensions / applyProductExtensions. 2) Ne pas éditer PERMISSIONS, MODULE_IDS ni PLANS North. 3) Une collision avec un nom North ou le remplacement d’un guard (requireValidSession, requireMembership) est rejeté. 4) Les presets free gardent billing, SSO, SCIM et MCP à OFF. 5) publicCapabilities reste filtré : aucun secret Infisical/Stripe.

  • packages/contracts/src/extensions.ts
  • packages/config/src/extensions.ts
  • packages/modules/src/extensions.ts
  • docs/adr/contracts/05-permissions-and-modules.md

Les packages publics n’importent ni DOM ni Node serveur. Un consommateur externe installe les tarballs, pas workspace:*.

Cycle de vie métier

Export / purge produit enregistrés côté serveur, reprise par cursor.

Enregistrer `product.<slug>.<feature>` dans convex/lifecycle.ts (PRODUCT_LIFECYCLE_HANDLERS). exportChunk / purgeChunk paginent par workspaceId ou createdBy. Module OFF n’empêche pas export/purge. Un handler qui lève laisse remainingSteps ; privacyRequests n’est pas completed. Ne pas marcher les tables dans privacy.ts. Ne pas purger SQL depuis une mutation métier.

  • convex/lifecycle.ts
  • docs/adr/contracts/04-lifecycle.md
  • docs/adr/contracts/09-product-feature-examples.md

L’enregistrement est serveur uniquement. Un client n’ajoute pas de handler.

Support et fork d’écran

Monter un écran North par ports, ou le forker hors garantie.

Support : route mince + overlay nav/i18n/thème ; apply continue de livrer @north/web-account et @north/web-workspace. Fork : copier l’écran dans le dépôt produit — plus de garantie visuelle ; invitations/files/prefs restent les API core. Masquer une entrée n’est pas assertModule. Détail : docs/UPGRADING_STARTER.md §7.

  • src/lib/navigation.ts
  • src/lib/theme.ts
  • packages/web/workspace/INTEGRATOR.md
  • docs/UPGRADING_STARTER.md

Les packages UI n’importent pas `_generated`. Le host mappe les IDs publics.

Checklist de page / module

  • Clavier, nom accessible, axe-core 0 sur la vue (exclure uniquement les overlays documentés).
  • 375px et ≥642px sans overflow du shell ; menus refermables (Escape).
  • FR/EN via t() ; thème clair/sombre/système ; dates dans le fuseau utilisateur.
  • États loading, vide, erreur (role=alert) et succès ; pas de bouton mort.
  • Permission Convex réelle ; un viewer ne passe pas par l’UI cachée.
  • Module OFF : nav absente, URL directe → Module unavailable, mutation/query/job refusés.
  • Preuve de parcours contre le stack isolé (NORTH_ENV_FILE), pas un screenshot ni un fetch simulé.

Documents du dépôt

Besoin d’aide ? Ouvrir le support