@mostajs/setup
v1.4.13
Published
Reusable setup wizard module — multi-dialect DB configuration, .env.local writer, seed runner
Maintainers
Readme
@mostajs/setup
Reusable setup wizard module — multi-dialect DB configuration, .env.local writer, seed runner, module discovery.
Part of the @mosta suite.
Table des matieres
- 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
1. Installation
npm install @mostajs/setup @mostajs/orm@mostajs/orm est un peer dependency requis (il fournit les dialectes DB).
2. Architecture du package
@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 exportsPrincipe : le package fournit des factory functions qui retournent des handlers { GET } ou { POST }. Votre app Next.js les expose en une ligne par route.
3. Didacticiel : integrer @mostajs/setup dans une nouvelle app
Prerequis
- Next.js 14+ (App Router)
- Node.js >= 18
@mostajs/orminstalle
Etape 1 — Installation des dependances
npm install @mostajs/setup @mostajs/orm bcryptjs
npm install -D @types/bcryptjsEtape 2 — Configurer le setup (lib/setup.ts)
Ce 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
Etape 3 — Creer les routes API
Creez 5 fichiers sous src/app/api/setup/ :
3.1 — Status (GET)
// 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 }
3.2 — Test connexion DB (POST)
// 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": "..." }
3.3 — Installation (POST)
// 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 },
})
}3.4 — Detection des modules (GET)
// 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"]
}3.5 — Installation des modules (POST)
// 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
Etape 4 — Creer la page Setup (frontend)
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',
}}
/>
)
}Props de SetupWizard
| 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.
Le wizard inclut :
- 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)
Etape 5 — Middleware : rediriger vers /setup
// 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).*)'],
}Etape 6 — Tester le flux complet
# 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 }4. API Reference
Fonctions principales
| 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 |
Factories API routes
| 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 |
Data exports
| 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 |
Types
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
}5. Les 13 dialectes supportes
| 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)6. Systeme de modules
Catalogue des 7 modules connus
| 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 |
Module standalone : @mostajs/face
@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.
Graphe de dependances
┌──────────┐
│ orm (R) │ R = requis
└────┬─────┘
┌────────┼────────┬──────────┐
v v v v
┌──────────┐ ┌──────┐ ┌──────────┐ ┌───────┐
│ auth (R) │ │audit │ │ settings │ │setup(R)│
└────┬─────┘ └──┬───┘ └──────────┘ └───────┘
│ │
v v
┌──────────────────┐
│ rbac │
└──────────────────┘
┌──────────────────────────┐
│ face (100% standalone) │ ← aucune dependance @mostajs
└──────────────────────────┘Liste statique vs decouverte dynamique
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 📦.
Resolution des dependances
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)Installation hybride (local + npm)
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.
7. Exemples avances
Utiliser runInstall sans le wizard UI
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: '[email protected]', 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'] }Ajouter des variables d'environnement personnalisees
const config: MostaSetupConfig = {
appName: 'MyApp',
extraEnvVars: {
SMTP_HOST: 'smtp.example.com',
STRIPE_KEY: 'sk_test_...',
},
}
// → .env.local contiendra aussi SMTP_HOST et STRIPE_KEYTester la connexion DB programmatiquement
import { 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' }Composer une URI manuellement
import { composeDbUri } from '@mostajs/setup'
composeDbUri('postgres', { host: 'db.example.com', port: 5432, name: 'prod', user: 'app', password: 's3cret' })
// → 'postgresql://app:[email protected]:5432/prod'
composeDbUri('sqlite', { host: '', port: 0, name: 'myapp', user: '', password: '' })
// → './data/myapp.db'Ecrire .env.local directement
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)8. Reconfiguration (post-installation)
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
Integration dans le projet hote
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.
1. Route API
src/app/api/setup/reconfig/route.ts
import { createReconfigHandlers } from '@mostajs/setup/api/reconfig'
const { GET, POST } = createReconfigHandlers()
export { GET, POST }2. Route API JAR Upload (drivers JDBC)
src/app/api/setup/upload-jar/route.ts
// Author: Dr Hamid MADANI [email protected]
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" })
3. Page de reconfiguration
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>
)
}3. Menu dynamique
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'4. Props de ReconfigPanel
| 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 |
5. Pourquoi le projet hote doit creer les pages ?
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.
9. FAQ / Troubleshooting
L'installation tourne en boucle (GET /setup se repete)
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).
E11000 duplicate key error (MongoDB)
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 }JSON.parse: unexpected character at line 1 column 1
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 }
}npm search timeout (pas d'internet)
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.
Comment ajouter un nouveau module a la liste statique ?
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
Related Packages
| 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) |
License
MIT — (c) 2025 Dr Hamid MADANI [email protected]
