Reusable setup wizard module — multi-dialect DB configuration, .env.local writer, seed runner, module discovery.
Part of the @mosta suite.
- Installation
- Architecture du package
- Didacticiel : integrer @mostajs/setup dans une nouvelle app
- API Reference
- Les 13 dialectes supportes
- Systeme de modules
- Exemples avances
- Reconfiguration (post-installation)
- FAQ / Troubleshooting
npm install @mostajs/setup @mostajs/orm@mostajs/orm est un peer dependency requis (il fournit les dialectes DB).
@mostajs/setup
├── data/
│ ├── dialects.ts # Metadata des 13 SGBD (icone, port, driver)
│ └── module-definitions.ts # Liste statique des modules @mostajs/*
├── lib/
│ ├── setup.ts # needsSetup() + runInstall()
│ ├── compose-uri.ts # Compose URI de connexion (mongo, pg, mysql...)
│ ├── db-test.ts # Test de connexion ephemere
│ ├── env-writer.ts # Ecriture/maj de .env.local
│ └── discover-modules.ts # Decouverte npm dynamique
├── api/
│ ├── status.route.ts # Factory GET /api/setup/status
│ ├── test-db.route.ts # Factory POST /api/setup/test-db
│ ├── install.route.ts # Factory POST /api/setup/install
│ ├── detect-modules.route.ts # Factory GET /api/setup/detect-modules
│ ├── install-modules.route.ts # Factory POST /api/setup/install-modules
│ ├── reconfig.route.ts # Factory GET+POST /api/setup/reconfig
│ └── upload-jar.route.ts # Factory GET+POST+DELETE /api/setup/upload-jar
├── components/
│ ├── SetupWizard.tsx # Wizard d'installation complet (6 etapes)
│ └── ReconfigPanel.tsx # UI reconfiguration (modules + DB)
├── types/
│ └── index.ts # Tous les types TypeScript
└── index.ts # Barrel exports
Principe : le package fournit des factory functions qui retournent des handlers { GET } ou { POST }. Votre app Next.js les expose en une ligne par route.
- Next.js 14+ (App Router)
- Node.js >= 18
@mostajs/orminstalle
npm install @mostajs/setup @mostajs/orm bcryptjs
npm install -D @types/bcryptjsCe fichier est le pont entre le package generique et votre application. Il definit :
- Comment compter les utilisateurs (pour
needsSetup) - Comment seeder les roles/permissions
- Comment creer l'admin
- Les seeds optionnels propres a votre app
// src/lib/setup.ts
import {
needsSetup as _needsSetup,
runInstall as _runInstall,
} from '@mostajs/setup/lib/setup'
import type {
DialectType,
MostaSetupConfig,
SeedDefinition,
InstallConfig,
} from '@mostajs/setup'
export type { DialectType }
// ─── needsSetup : verifie si la DB a 0 users ──────────────
export async function needsSetup(): Promise<boolean> {
return _needsSetup(async () => {
// Adaptez cette ligne a votre couche d'acces aux donnees
const { userRepo } = await import('@/dal/service')
const repo = await userRepo()
return repo.count()
})
}
// ─── Seeds optionnels (propres a votre app) ────────────────
const optionalSeeds: SeedDefinition[] = [
{
key: 'demoData',
label: 'Donnees de demonstration',
description: 'Quelques enregistrements pour tester',
run: async () => {
// Votre logique de seed
const { productRepo } = await import('@/dal/service')
const repo = await productRepo()
await repo.create({ name: 'Produit A', price: 1000 })
await repo.create({ name: 'Produit B', price: 2000 })
},
},
]
// ─── Configuration du setup ────────────────────────────────
const SETUP_CONFIG: MostaSetupConfig = {
appName: 'Mon Application',
defaultPort: 3000,
// Callback pour seeder les roles et permissions
seedRBAC: async () => {
const { roleRepo, permissionRepo } = await import('@/dal/service')
const pRepo = await permissionRepo()
const rRepo = await roleRepo()
// Creer les permissions
const readPerm = await pRepo.upsert(
{ name: 'read' },
{ name: 'read', description: 'Lecture' },
)
const writePerm = await pRepo.upsert(
{ name: 'write' },
{ name: 'write', description: 'Ecriture' },
)
// Creer les roles avec permissions
await rRepo.upsert(
{ name: 'admin' },
{ name: 'admin', description: 'Administrateur', permissions: [readPerm.id, writePerm.id] },
)
await rRepo.upsert(
{ name: 'viewer' },
{ name: 'viewer', description: 'Lecteur', permissions: [readPerm.id] },
)
},
// Callback pour creer le premier administrateur
// Le mot de passe est DEJA hashe par le package (bcrypt, 12 rounds)
createAdmin: async ({ email, hashedPassword, firstName, lastName }) => {
const { userRepo, roleRepo } = await import('@/dal/service')
const uRepo = await userRepo()
const rRepo = await roleRepo()
const adminRole = await rRepo.findOne({ name: 'admin' })
await uRepo.upsert(
{ email: email.toLowerCase() },
{
email: email.toLowerCase(),
password: hashedPassword,
firstName,
lastName,
roles: adminRole ? [adminRole.id] : [],
status: 'active',
},
)
},
optionalSeeds,
}
// ─── runInstall : expose au route handler ──────────────────
export async function runInstall(config: InstallConfig) {
return _runInstall(config, SETUP_CONFIG)
}Points cles :
needsSetup()retournetruesi 0 users en base → l'app doit s'installerrunInstall()execute les 6 etapes : ecriture.env.local, connexion DB, seed RBAC, creation admin, seeds optionnels- Le mot de passe admin est automatiquement hashe par le package (bcrypt, 12 rounds). Ne le hachez PAS vous-meme.
MOSTAJS_MODULESest ecrit dans.env.localsiconfig.modulesest fourni
Creez 5 fichiers sous src/app/api/setup/ :
// src/app/api/setup/status/route.ts
import { createStatusHandler } from '@mostajs/setup'
import { needsSetup } from '@/lib/setup'
export const { GET } = createStatusHandler(needsSetup)Reponse : { "needsSetup": true } ou { "needsSetup": false }
// src/app/api/setup/test-db/route.ts
import { createTestDbHandler } from '@mostajs/setup'
import { needsSetup } from '@/lib/setup'
export const { POST } = createTestDbHandler(needsSetup)Body attendu :
{
"dialect": "postgres",
"host": "localhost",
"port": 5432,
"name": "mydb",
"user": "postgres",
"password": "secret"
}Reponse : { "ok": true } ou { "ok": false, "error": "..." }
// src/app/api/setup/install/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { needsSetup, runInstall } from '@/lib/setup'
import { z } from 'zod'
const ALL_DIALECTS = [
'mongodb', 'sqlite', 'postgres', 'mysql', 'mariadb',
'oracle', 'mssql', 'cockroachdb', 'db2', 'hana',
'hsqldb', 'spanner', 'sybase',
] as const
const installSchema = z.object({
dialect: z.enum(ALL_DIALECTS),
db: z.object({
host: z.string().default('localhost'),
port: z.number().int().min(0).max(65535).default(0),
name: z.string().min(1),
user: z.string().default(''),
password: z.string().default(''),
}),
admin: z.object({
email: z.string().email(),
password: z.string().min(6),
firstName: z.string().min(1),
lastName: z.string().min(1),
}),
seed: z.record(z.boolean()).optional(),
modules: z.array(z.string()).optional(),
})
export async function POST(req: NextRequest) {
const setupNeeded = await needsSetup()
if (!setupNeeded) {
return NextResponse.json(
{ error: { code: 'FORBIDDEN', message: 'Installation deja effectuee' } },
{ status: 403 },
)
}
const body = await req.json()
const parsed = installSchema.safeParse(body)
if (!parsed.success) {
return NextResponse.json(
{ error: { code: 'VALIDATION_ERROR', details: parsed.error.flatten() } },
{ status: 400 },
)
}
const result = await runInstall(parsed.data)
if (!result.ok) {
return NextResponse.json(
{ error: { code: 'INSTALL_ERROR', message: result.error } },
{ status: 500 },
)
}
return NextResponse.json({
data: { ok: true, needsRestart: result.needsRestart, seeded: result.seeded },
})
}// src/app/api/setup/detect-modules/route.ts
import { createDetectModulesHandler } from '@mostajs/setup'
export const { GET } = createDetectModulesHandler()Reponse :
{
"modules": [
{ "key": "orm", "packageName": "@mostajs/orm", "label": "ORM", "required": true, ... },
{ "key": "auth", "packageName": "@mostajs/auth", ... },
{ "key": "new-plugin", "discovered": true, "icon": "📦", ... }
],
"installed": ["orm", "auth", "setup"]
}// src/app/api/setup/install-modules/route.ts
import { createInstallModulesHandler } from '@mostajs/setup'
import { needsSetup } from '@/lib/setup'
export const { POST } = createInstallModulesHandler(needsSetup)Body : { "modules": ["orm", "auth", "audit", "rbac"] }
Ce handler :
- Resout les dependances transitives (
rbac→auth+audit) - Installe via
npm install(localfile:./packages/...si present, sinon npm registry) - Ecrit
MOSTAJS_MODULES=orm,auth,audit,rbacdans.env.local
Le module fournit un composant SetupWizard pret a l'emploi avec inline styles (aucune dependance Tailwind/shadcn).
Votre page Next.js n'est qu'un wrapper d'une vingtaine de lignes :
// src/app/setup/page.tsx
'use client'
import { useRouter } from 'next/navigation'
import SetupWizard from '@mostajs/setup/components/SetupWizard'
import { t } from '@/i18n' // ou toute fonction de traduction
export default function SetupPage() {
const router = useRouter()
return (
<SetupWizard
t={t}
onComplete={() => router.push('/login')}
dbNamePrefix="secuaccessdb"
endpoints={{
detectModules: '/api/setup/detect-modules',
testDb: '/api/setup/test-db',
installModules: '/api/setup/install-modules',
install: '/api/setup/install',
uploadJar: '/api/setup/upload-jar',
}}
/>
)
}| Prop | Type | Default | Description |
|---|---|---|---|
t |
(key: string) => string |
(k) => k |
Fonction de traduction (recoit des cles setup.xxx) |
onComplete |
() => void |
— | Callback apres installation reussie (ex: router.push('/login')) |
dbNamePrefix |
string |
'mydb' |
Prefixe pour le nom de base par defaut |
persistState |
boolean |
true |
Persister l'etat du wizard dans sessionStorage |
endpoints |
object |
voir ci-dessous | URLs des routes API |
Endpoints par defaut :
{
"detectModules": "/api/setup/detect-modules",
"testDb": "/api/setup/test-db",
"installModules": "/api/setup/install-modules",
"install": "/api/setup/install",
"uploadJar": "/api/setup/upload-jar"
}Cles i18n attendues : setup.steps.*, setup.welcome.*, setup.modules.*, setup.dialect.*, setup.database.*, setup.admin.*, setup.summary.*, setup.back, setup.next.
- 6 etapes : Accueil → Modules → Dialecte → Base de donnees → Admin → Recapitulatif
- 13 dialectes avec distinction Premium (grises, non cliquables) et badges JDBC
- Upload JAR integre pour les dialectes JDBC (hsqldb, oracle, db2, hana, sybase)
- Persistence sessionStorage pour survivre aux hot-reloads Next.js
- Resolution des dependances entre modules
- Retry automatique apres npm install (le serveur peut redemarrer)
// src/middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export async function middleware(req: NextRequest) {
const { pathname } = req.nextUrl
// Laisser passer les routes publiques
if (
pathname.startsWith('/setup') ||
pathname.startsWith('/api/setup') ||
pathname.startsWith('/api/auth') ||
pathname.startsWith('/_next')
) {
return NextResponse.next()
}
// Verifier si l'app a besoin du setup
try {
const res = await fetch(new URL('/api/setup/status', req.url))
const data = await res.json()
if (data.needsSetup) {
return NextResponse.redirect(new URL('/setup', req.url))
}
} catch {
// Si la DB n'est pas accessible, rediriger vers setup
return NextResponse.redirect(new URL('/setup', req.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/((?!_next|favicon.ico|icons|manifest.json).*)'],
}# 1. Demarrer le serveur
npm run dev
# 2. Ouvrir http://localhost:3000
# → Redirige automatiquement vers /setup
# 3. Suivre le wizard :
# - Choisir les modules
# - Selectionner le dialecte (ex: MongoDB, SQLite, Postgres...)
# - Tester la connexion
# - Renseigner l'admin
# - Lancer l'installation
# 4. Verifier les resultats :
# - .env.local contient DB_DIALECT, SGBD_URI, MOSTAJS_MODULES
# - La DB contient les roles, permissions et l'admin
# - /api/setup/status retourne { needsSetup: false }| Export | Signature | Description |
|---|---|---|
needsSetup |
(countFn: () => Promise<number>) => Promise<boolean> |
Retourne true si 0 users en base |
runInstall |
(config: InstallConfig, setup: MostaSetupConfig) => Promise<Result> |
Flux complet : env → DB → seed → admin |
testDbConnection |
(config: DbTestConfig) => Promise<{ ok, error? }> |
Test ephemere (ne modifie pas la connexion globale) |
composeDbUri |
(dialect: DialectType, db: DbConfig) => string |
Compose l'URI de connexion |
writeEnvLocal |
(options: EnvWriterOptions) => Promise<boolean> |
Ecrit .env.local, retourne true si dialect change |
| Export | Route | Methode | Description |
|---|---|---|---|
createStatusHandler(needsSetup) |
/api/setup/status |
GET | Retourne { needsSetup: boolean } |
createTestDbHandler(needsSetup) |
/api/setup/test-db |
POST | Teste la connexion DB |
createInstallHandler(needsSetup, config) |
/api/setup/install |
POST | Lance l'installation complete |
createDetectModulesHandler() |
/api/setup/detect-modules |
GET | Liste modules (statiques + npm) + installes |
createInstallModulesHandler(needsSetup) |
/api/setup/install-modules |
POST | Installe les modules npm selectionnes |
| Export | Description |
|---|---|
DIALECT_INFO |
Record<DialectType, DialectInfo> — metadata de chaque SGBD |
ALL_DIALECTS |
DialectType[] — liste des 13 dialectes |
MODULES |
ModuleDefinition[] — liste statique des 7 modules connus |
resolveModuleDependencies(selected, modules?) |
Resout les dependances transitives |
discoverNpmModules() |
Decouvre les packages @mostajs/* sur npm |
interface InstallConfig {
dialect: DialectType
db: DbConfig
admin: { email: string; password: string; firstName: string; lastName: string }
seed?: SeedOptions // { activities: true, demoData: false, ... }
modules?: string[] // ['orm', 'auth', 'rbac'] → ecrit MOSTAJS_MODULES
}
interface MostaSetupConfig {
appName: string
defaultPort?: number
seedRBAC?: () => Promise<void>
createAdmin?: (admin: { email: string; hashedPassword: string; firstName: string; lastName: string }) => Promise<void>
optionalSeeds?: SeedDefinition[]
extraEnvVars?: Record<string, string>
}
interface SeedDefinition {
key: string
label: string
description: string
icon?: string
default?: boolean
run: (repos: any) => Promise<void>
}
interface ModuleDefinition {
key: string
packageName: string // '@mostajs/auth'
localDir?: string // 'mosta-auth' (sous packages/)
label: string
description: string
icon: string
required?: boolean
default?: boolean
dependsOn?: string[]
discovered?: boolean // true si trouve via npm search
}| Dialecte | Icone | Port | Categorie | Driver |
|---|---|---|---|---|
| MongoDB | 🍃 | 27017 | document | mongoose |
| SQLite | 📁 | — | file | better-sqlite3 |
| PostgreSQL | 🐘 | 5432 | sql | pg |
| MySQL | 🐬 | 3306 | sql | mysql2 |
| MariaDB | 🦭 | 3306 | sql | mariadb |
| Oracle | 🔴 | 1521 | enterprise | oracledb |
| SQL Server | 🟦 | 1433 | enterprise | tedious |
| CockroachDB | 🪳 | 26257 | distributed | pg |
| IBM DB2 | 🏢 | 50000 | enterprise | ibm_db |
| SAP HANA | 💎 | 39013 | enterprise | @sap/hana-client |
| HyperSQL | ⚡ | 9001 | legacy | — |
| Cloud Spanner | ☁️ | — | distributed | @google-cloud/spanner |
| Sybase ASE | 🔷 | 5000 | legacy | sybase |
Les URI sont composees automatiquement par composeDbUri() :
mongodb://user:pass@host:27017/mydb
postgresql://user:pass@host:5432/mydb
mysql://user:pass@host:3306/mydb
./data/mydb.db (SQLite)
spanner://projects/my-project (Cloud Spanner)
| Module | Package | Requis | Depend de | Standalone | Description |
|---|---|---|---|---|---|
| orm | @mostajs/orm |
oui | — | — | ORM multi-dialecte (13 SGBD), pattern Hibernate |
| auth | @mostajs/auth |
oui | orm | non | NextAuth, sessions, hashage mots de passe |
| audit | @mostajs/audit |
non | orm | non | Journalisation des actions, tracabilite |
| rbac | @mostajs/rbac |
non | auth, audit | non | Roles, permissions, matrice RBAC |
| settings | @mostajs/settings |
non | orm | non | Parametres cle-valeur, formulaire auto, provider React |
| face | @mostajs/face |
non | aucune | oui | Detection de visage, descripteurs, matching 1:N |
| setup | @mostajs/setup |
oui | orm | non | Wizard d'installation, test DB, seed runner |
@mostajs/face est 100% independant — il n'importe aucun package @mostajs/* et peut etre utilise dans n'importe quelle application React >= 18 sans @mostajs/orm ni base de donnees.
Dependance unique : @vladmandic/face-api (reconnaissance faciale TensorFlow.js)
npm install @mostajs/faceimport { useCamera, useFaceDetection, compareFaces } from '@mostajs/face'
// Hooks React pour camera et detection
const { videoRef, start, stop } = useCamera()
const { detect, result } = useFaceDetection()
// API bas niveau
import { loadModels, detectFace, extractDescriptor } from '@mostajs/face'
import { findMatch, descriptorToArray, arrayToDescriptor } from '@mostajs/face'Exports : loadModels, detectFace, detectAllFaces, extractDescriptor, compareFaces, findMatch, findAllMatches, descriptorToArray, arrayToDescriptor, isValidDescriptor, drawDetection, useCamera, useFaceDetection.
┌──────────┐
│ orm (R) │ R = requis
└────┬─────┘
┌────────┼────────┬──────────┐
v v v v
┌──────────┐ ┌──────┐ ┌──────────┐ ┌───────┐
│ auth (R) │ │audit │ │ settings │ │setup(R)│
└────┬─────┘ └──┬───┘ └──────────┘ └───────┘
│ │
v v
┌──────────────────┐
│ rbac │
└──────────────────┘
┌──────────────────────────┐
│ face (100% standalone) │ ← aucune dependance @mostajs
└──────────────────────────┘
Le package maintient une liste statique des 7 modules ci-dessus avec metadata riches (required, dependsOn, icon, description).
Au runtime, GET /api/setup/detect-modules interroge aussi npm (npm search @mostajs --json) pour trouver des packages publies apres le deploiement. Ces modules decouverts sont ajoutes avec discovered: true et l'icone 📦.
import { resolveModuleDependencies } from '@mostajs/setup'
resolveModuleDependencies(['rbac'])
// → ['rbac', 'auth', 'audit', 'orm', 'setup']
// (rbac depend de auth + audit, auth depend de orm, setup est requis)
resolveModuleDependencies(['face'])
// → ['face', 'orm', 'auth', 'setup']
// (face n'a pas de dependance @mostajs, mais orm/auth/setup sont requis)Le handler install-modules utilise une strategie hybride :
- Skip : si deja dans
node_modules/@mostajs/xxx→ pas denpm install(evite hot-reload) - Local : si
packages/mosta-xxx/existe →npm install file:./packages/mosta-xxx - npm registry : sinon →
npm install @mostajs/xxx
Cela evite les 404 npm pour les packages non encore publies et les hot-reloads Next.js inutiles.
import { runInstall } from '@mostajs/setup'
import { setupConfig } from './my-setup-config'
const result = await runInstall(
{
dialect: 'postgres',
db: { host: 'localhost', port: 5432, name: 'mydb', user: 'pg', password: 'secret' },
admin: { email: 'admin@example.com', password: 'Admin@123', firstName: 'Admin', lastName: 'User' },
seed: { demoData: true },
modules: ['orm', 'auth', 'rbac'],
},
setupConfig,
)
console.log(result)
// { ok: true, needsRestart: false, seeded: ['categories', 'permissions', 'roles', 'admin', 'demoData'] }const config: MostaSetupConfig = {
appName: 'MyApp',
extraEnvVars: {
SMTP_HOST: 'smtp.example.com',
STRIPE_KEY: 'sk_test_...',
},
}
// → .env.local contiendra aussi SMTP_HOST et STRIPE_KEYimport { testDbConnection } from '@mostajs/setup'
const result = await testDbConnection({
dialect: 'mongodb',
host: 'localhost',
port: 27017,
name: 'testdb',
user: '',
password: '',
})
// { ok: true } ou { ok: false, error: 'Connection refused' }import { composeDbUri } from '@mostajs/setup'
composeDbUri('postgres', { host: 'db.example.com', port: 5432, name: 'prod', user: 'app', password: 's3cret' })
// → 'postgresql://app:s3cret@db.example.com:5432/prod'
composeDbUri('sqlite', { host: '', port: 0, name: 'myapp', user: '', password: '' })
// → './data/myapp.db'import { writeEnvLocal } from '@mostajs/setup'
const dialectChanged = await writeEnvLocal({
dialect: 'mongodb',
uri: 'mongodb://localhost:27017/mydb',
port: 3000,
extraVars: { MOSTAJS_MODULES: 'orm,auth,rbac' },
})
// dialectChanged = true si le dialecte a change (necessite un redemarrage)Apres l'installation initiale, le module fournit un panneau de reconfiguration permettant de :
- Changer de base de donnees (dialecte, connexion, test)
- Activer / desactiver des modules @mostajs
- Optionnellement re-seeder la nouvelle base
Ce module exporte un composant React (ReconfigPanel) et une factory API (createReconfigHandlers),
mais ne cree pas de pages Next.js. Le projet hote doit creer la route API et la page.
src/app/api/setup/reconfig/route.ts
import { createReconfigHandlers } from '@mostajs/setup/api/reconfig'
const { GET, POST } = createReconfigHandlers()
export { GET, POST }src/app/api/setup/upload-jar/route.ts
// Author: Dr Hamid MADANI drmdh@msn.com
import { createUploadJarHandlers } from '@mostajs/setup/api/upload-jar'
const { GET, POST, DELETE } = createUploadJarHandlers()
export { GET, POST, DELETE }La logique d'upload est dans
@mostajs/orm(saveJarFile,deleteJarFile,listJarFiles). La route factory dans@mostajs/setupne fait que la deleguer.
- GET — liste les JARs et le statut des dialects JDBC
- POST — upload un fichier
.jar(multipart/form-data, champjar)- DELETE — supprime un JAR (
{ "fileName": "hsqldb-2.7.2.jar" })
src/app/dashboard/settings/reconfig/page.tsx
'use client'
import ReconfigPanel from '@mostajs/setup/components/ReconfigPanel'
export default function ReconfigPage() {
return (
<div className="space-y-6">
<h1 className="text-2xl font-bold">Reconfiguration</h1>
<ReconfigPanel
apiEndpoint="/api/setup/reconfig"
detectEndpoint="/api/setup/detect-modules"
jarEndpoint="/api/setup/upload-jar"
showSeedOption
onDbChanged={() => window.location.reload()}
onSeedRequested={async () => {
await fetch('/api/setup/install', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'seed-only' }),
})
}}
/>
</div>
)
}Le module exporte setupMenuContribution qui declare la route /dashboard/settings/reconfig
dans le groupe "Administration". Importez-le via le deep import :
import { setupMenuContribution } from '@mostajs/setup/lib/menu'| Prop | Type | Description |
|---|---|---|
apiEndpoint |
string |
URL de l'API reconfig (ex: /api/setup/reconfig) |
detectEndpoint |
string |
URL de l'API detect-modules (ex: /api/setup/detect-modules) |
t |
(key: string) => string |
Fonction de traduction (optionnel) |
showSeedOption |
boolean |
Afficher la checkbox "Re-seeder" lors d'un changement de DB |
onDbChanged |
() => void |
Callback apres changement de DB reussi |
onModulesChanged |
(modules: string[]) => void |
Callback apres maj des modules |
onSeedRequested |
() => Promise<void> |
Callback pour executer le seed |
Les modules @mostajs/* sont des bibliotheques npm (composants, hooks, utilitaires), pas des applications.
Next.js App Router exige que les fichiers page.tsx soient dans le dossier src/app/ du projet.
Un package npm ne peut pas injecter de pages dans le routeur — c'est donc au projet hote de creer ces fichiers wrapper, meme s'ils ne font qu'importer et afficher un composant du module.
Cause : npm install modifie package.json / node_modules, ce qui declenche un hot-reload Next.js et reinitialise le state React.
Solution : Le handler install-modules skip les packages deja installes dans node_modules/. Si le probleme persiste, ajoutez une persistence du state wizard dans sessionStorage (voir l'implementation de SecuAccess Pro).
Cause : Un champ unique: true sans required: true dans le schema. MongoDB indexe les null et refuse le doublon.
Solution : Ajoutez sparse: true au champ dans votre EntitySchema. Cela fonctionne avec MongoDB (index sparse) et est ignore sans risque par les dialectes SQL.
clientNumber: { type: 'string', unique: true, sparse: true }Cause : La reponse de l'API est du HTML (page 404 Next.js) au lieu de JSON, typiquement pendant un hot-reload du serveur.
Solution : Utilisez un safeJson() helper dans le frontend :
async function safeJson(res: Response) {
try { return JSON.parse(await res.text()) }
catch { return null }
}Le handler detect-modules a un timeout de 10 secondes sur npm search. En cas d'echec (offline, timeout), il retourne la liste statique des 7 modules connus. Aucune action necessaire.
Editez packages/mosta-setup/data/module-definitions.ts et ajoutez une entree a MODULES :
{
key: 'notifications',
packageName: '@mostajs/notifications',
localDir: 'mosta-notifications', // si disponible localement
label: 'Notifications',
description: 'Push, email, SMS',
icon: '🔔',
default: false,
dependsOn: ['orm'],
}Puis recompilez : cd packages/mosta-setup && npx tsc
| Package | Depend de orm | Standalone | Description |
|---|---|---|---|
| @mostajs/orm | — | — | Multi-dialect ORM, 13 SGBD (requis) |
| @mostajs/auth | oui | non | Authentication NextAuth, sessions |
| @mostajs/audit | oui | non | Audit logging, tracabilite |
| @mostajs/rbac | oui | non | Roles & Permissions RBAC |
| @mostajs/settings | oui | non | Parametres cle-valeur |
| @mostajs/face | non | oui | Reconnaissance faciale (independant) |
MIT — (c) 2025 Dr Hamid MADANI drmdh@msn.com