diff --git a/docs/DEV.md b/docs/DEV.md index 57847b9..d607faf 100644 --- a/docs/DEV.md +++ b/docs/DEV.md @@ -4,7 +4,7 @@ Ce document couvre les conventions de code, les règles de sécurité et la proc Pour les conventions de rédaction : [LANGUE.md](./dev/LANGUE.md) et [REDACTION.md](./dev/REDACTION.md). -Pour l'architecture partagée (modules, composants, icônes) : [ARCHITECTURE.md](./dev/ARCHITECTURE.md). +Pour l'architecture partagée (composants, icônes) : [ARCHITECTURE.md](./dev/ARCHITECTURE.md). Pour la procédure de publication du package : [PUBLICATION.md](./dev/PUBLICATION.md). diff --git a/docs/modules/EXTERNAL_MODULE.md b/docs/modules/EXTERNAL_MODULE.md deleted file mode 100644 index 6bc3a14..0000000 --- a/docs/modules/EXTERNAL_MODULE.md +++ /dev/null @@ -1,255 +0,0 @@ -# Créer un module externe - -Un module externe est un package npm indépendant qui s'intègre dans une app qui utilise `@zen/core`. Il n'a pas besoin de modifier le code source du CMS. - ---- - -## Convention de nommage - -``` -@scope/zen-nom-du-module -``` - -Exemples : `@zen/core-invoice`, `@zen/core-nuage`. - ---- - -## Structure du package - -``` -zen-invoice/ -├── index.js # Point d'entrée — exporte defineModule() -├── admin/ # Composants React pour l'admin -│ ├── InvoiceListPage.js -│ ├── InvoiceCreatePage.js -│ └── InvoiceEditPage.js -├── db.js # createTables() et dropTables() -├── actions.js # Server actions pour pages publiques -├── metadata.js # Générateurs de métadonnées SEO -├── package.json -└── .env.example -``` - ---- - -## index.js - -On utilise `defineModule()` importé depuis `@zen/core/modules/define`. - -```js -import { lazy } from 'react'; -import { defineModule } from '@zen/core/modules/define'; - -import { createTables, dropTables } from './db.js'; -import { getInvoiceByToken } from './actions.js'; -import { generatePaymentMetadata } from './metadata.js'; - -const InvoiceListPage = lazy(() => import('./admin/InvoiceListPage.js')); -const InvoiceCreatePage = lazy(() => import('./admin/InvoiceCreatePage.js')); -const InvoiceEditPage = lazy(() => import('./admin/InvoiceEditPage.js')); - -export default defineModule({ - name: 'invoice', - displayName: 'Facturation', - version: '1.0.0', - description: 'Gestion des factures et paiements.', - - dependencies: [], - envVars: ['STRIPE_SECRET_KEY', 'ZEN_INVOICE_TAX_RATE'], - - // Navigation dans le panneau admin - navigation: [ - { - id: 'invoice', - title: 'Facturation', - icon: 'Invoice03Icon', - items: [ - { name: 'Factures', href: '/admin/invoice/list', icon: 'Invoice03Icon' }, - { name: 'Nouvelle', href: '/admin/invoice/new', icon: 'Add01Icon' }, - ], - }, - ], - - // Pages admin avec leurs composants lazy - adminPages: { - '/admin/invoice/list': InvoiceListPage, - '/admin/invoice/new': InvoiceCreatePage, - '/admin/invoice/edit': InvoiceEditPage, - }, - - // Résolveur pour les routes dynamiques (ex: /admin/invoice/edit/123) - pageResolver(path) { - const parts = path.split('/').filter(Boolean); - if (parts[0] !== 'admin' || parts[1] !== 'invoice') return null; - if (parts[2] === 'list') return InvoiceListPage; - if (parts[2] === 'new') return InvoiceCreatePage; - if (parts[2] === 'edit') return InvoiceEditPage; - return null; - }, - - publicPages: {}, - publicRoutes: [ - { pattern: ':token', description: 'Page de paiement' }, - { pattern: ':token/pdf', description: 'Télécharger la facture PDF' }, - ], - - dashboardWidgets: [], - - // Base de données - db: { createTables, dropTables }, - - // Server actions pour les pages publiques (/zen/invoice/...) - actions: { getInvoiceByToken }, - - // Générateurs de métadonnées SEO - metadata: { - payment: generatePaymentMetadata, - }, - - // Appelé une fois au démarrage du serveur - // ctx donne accès aux services du CMS - async setup(ctx) { - const stripe = await ctx.payments.then(p => p.stripe); - // Initialiser des webhooks, vérifier la config, etc. - console.log('[invoice] Stripe prêt :', !!stripe); - }, -}); -``` - ---- - -## L'objet ctx dans setup() - -`setup(ctx)` reçoit un objet qui donne accès aux services du CMS. Chaque propriété retourne une promesse vers le module correspondant. - -```js -async setup(ctx) { - // Base de données PostgreSQL - const { query, queryOne, queryAll } = await ctx.db; - const rows = await query('SELECT * FROM zen_auth_users LIMIT 1'); - - // Envoi de courriels (Resend) - const { sendEmail } = await ctx.email; - await sendEmail({ to: 'test@example.com', subject: 'Test', html: '
ok
' }); - - // Stockage de fichiers (Cloudflare R2) - const { uploadFile, deleteFile } = await ctx.storage; - - // Stripe - const { stripe } = await ctx.payments; - - // Variables d'environnement - const apiKey = ctx.config.get('STRIPE_SECRET_KEY'); -} -``` - ---- - -## package.json du module externe - -```json -{ - "name": "@zen/core-invoice", - "version": "1.0.0", - "type": "module", - "main": "./index.js", - "exports": { - ".": "./index.js" - }, - "peerDependencies": { - "@zen/core": ">=1.0.0", - "react": ">=19.0.0" - } -} -``` - ---- - -## Intégration dans l'app consommatrice - -### 1. Installer le package - -```bash -npm install @zen/core-invoice -``` - -### 2. Créer zen.config.js à la racine de l'app - -```js -// zen.config.js -import invoiceModule from '@zen/core-invoice'; - -export default { - modules: [invoiceModule], -}; -``` - -### 3. Passer la config à initializeZen() - -```js -// instrumentation.js -import zenConfig from './zen.config.js'; - -export async function register() { - if (process.env.NEXT_RUNTIME === 'nodejs') { - const { initializeZen } = await import('@zen/core'); - await initializeZen(zenConfig); - } -} -``` - -### 4. Passer les modules à ZenProvider - -```jsx -// app/layout.js -import zenConfig from './zen.config.js'; -import { ZenProvider } from '@zen/core/provider'; - -export default function RootLayout({ children }) { - return ( - - -