7.1 KiB
7.1 KiB
Architecture
Ce document décrit la structure du projet et les principes qui la gouvernent, afin de garder l'application évolutive (facile à étendre, sans dette).
Principes
- Modular monolith — un seul projet Next.js, mais des modules métier isolés
sous
src/modules/<domaine>/. Chaque module expose sonservice; les routes API et l'UI n'accèdent JAMAIS directement à Prisma pour un domaine. - Validation à la frontière — tout input externe (API, formulaire, scanner) est validé via un schéma Zod avant d'atteindre le service.
- Registry pattern pour les scanners — ajouter une capacité de découverte se
fait en implémentant une interface
Scanneret en l'enregistrant dans le registre (aucune autre partie du code n'est touchée). - DB-agnostic — Prisma lit
DATABASE_PROVIDERetDATABASE_URLà l'exécution ; SQLite pour commencer, PostgreSQL plus tard sans refactor.
Arborescence
IPAM/
├── docker/ Dockerfile + docker-compose (profils sqlite/postgres)
├── prisma/
│ ├── schema.prisma Modèle de données (Network, Host, Port, Application, Scan)
│ ├── migrations/ Migrations SQL (créées par `db:migrate`)
│ └── seed.ts Données d'exemple
├── public/ Assets statiques
├── scripts/
│ └── run-discovery.ts CLI pour lancer une découverte hors UI
├── src/
│ ├── app/ Next.js App Router
│ │ ├── (dashboard)/ Route group → layout UI commun (sidebar, header)
│ │ │ ├── hosts/ Pages de gestion des hôtes
│ │ │ ├── networks/
│ │ │ ├── applications/
│ │ │ ├── scans/
│ │ │ └── settings/
│ │ ├── api/ Route Handlers — FINS, délèguent aux services
│ │ │ ├── hosts/
│ │ │ ├── networks/
│ │ │ ├── applications/
│ │ │ ├── ports/
│ │ │ ├── scans/
│ │ │ └── discovery/
│ │ ├── layout.tsx
│ │ └── page.tsx
│ │
│ ├── components/ Composants React
│ │ ├── ui/ Primitives (Button, Input, Dialog...)
│ │ ├── layout/ Sidebar, Header, Shell
│ │ ├── hosts/ networks/ ... Composants spécifiques par domaine
│ │ └── common/ Composants réutilisables (DataTable, Skeleton...)
│ │
│ ├── modules/ ★ Cœur métier — UN DOSSIER PAR DOMAINE
│ │ ├── hosts/
│ │ │ ├── hosts.schema.ts Validation Zod + types
│ │ │ ├── hosts.repository.ts Accès Prisma (seule frontière avec la DB)
│ │ │ ├── hosts.service.ts Logique métier
│ │ │ └── index.ts
│ │ ├── networks/
│ │ ├── applications/
│ │ ├── ports/
│ │ ├── scans/
│ │ └── discovery/ ★ Découverte réseau (pluggable)
│ │ ├── types.ts Interface `Scanner` + types résultats
│ │ ├── registry.ts Enregistrement des scanners
│ │ ├── discovery.service.ts Orchestrateur (persiste en DB)
│ │ ├── scanners/
│ │ │ ├── ping.scanner.ts
│ │ │ ├── port.scanner.ts
│ │ │ ├── arp.scanner.ts
│ │ │ └── mdns.scanner.ts
│ │ └── utils/
│ │ └── concurrency.ts Runner parallèle borné
│ │
│ ├── lib/ Utilitaires transverses
│ │ ├── db/prisma.ts Client Prisma (singleton)
│ │ ├── api/response.ts Helpers NextResponse (ok/badRequest/...)
│ │ ├── utils/cn.ts Merge classes Tailwind
│ │ └── utils/logger.ts Pino logger configuré
│ │
│ ├── config/env.ts Env vars typées via Zod (fail-fast)
│ ├── hooks/ Hooks React partagés (ex: useHosts)
│ ├── types/ Types globaux
│ └── styles/globals.css Tailwind + variables de thème
│
├── tests/ Unitaires + intégration (vitest)
├── .env.example
├── next.config.mjs output: standalone + ext pkgs réseau
├── tsconfig.json Aliases @/modules, @/lib, @/components…
└── tailwind.config.ts
Flux d'une requête
Client (RSC ou fetch)
→ src/app/api/<domaine>/route.ts (validation + handleError)
→ src/modules/<domaine>/service.ts (règles métier)
→ src/modules/<domaine>/repository (Prisma)
→ DB (SQLite | PostgreSQL)
Ajouter un module métier (ex: VLAN)
- Créer
src/modules/vlans/avecvlans.schema.ts,vlans.service.ts,index.ts - Ajouter le modèle Prisma dans
prisma/schema.prisma→npm run db:migrate - Créer les routes
src/app/api/vlans/route.ts(et[id]/route.ts) — copier le pattern des hôtes - Créer la page
src/app/(dashboard)/vlans/page.tsx - (Optionnel) Ajouter des composants UI dans
src/components/vlans/
Aucun fichier existant ne doit être modifié en dehors de schema.prisma.
Ajouter un scanner de découverte (ex: SNMP)
- Créer
src/modules/discovery/scanners/snmp.scanner.tsexportant une constante conforme à l'interfaceScanner(kind,label,enabled,run) - L'importer dans
src/modules/discovery/registry.tset l'ajouter auscannersRegistryavec sa cléScannerKind(mettre à jour le type union danstypes.ts) - Exposer la clé dans
bodySchemadesrc/app/api/discovery/route.ts
Il sera automatiquement disponible dans runSingle() et, si intégré à
runFull(), dans le scan complet.
Choix techniques clefs
- Prisma plutôt que Drizzle : meilleures migrations pour un homelab, Studio inclus. Drizzle serait envisageable plus tard si on a besoin de SQL brut.
- App Router (pas Pages Router) : server components, streaming, server actions disponibles quand on voudra simplifier des formulaires.
- Pas de framework "d'auth" pour l'instant : ajouter NextAuth/Auth.js quand
on exposera l'IPAM au-delà du LAN. Un emplacement naturel :
src/modules/auth/. - Pas de Redis/queue : tous les scans tournent dans le process. À prévoir (BullMQ + Redis) uniquement si on planifie des scans récurrents lourds.
Futures fonctionnalités envisagées
- Scans planifiés (cron-like, via BullMQ ou
node-cron) - Notifications (nouvel hôte, port qui change d'état)
- Export CSV / JSON des inventaires
- Synchronisation avec un reverse-proxy (Traefik, Nginx Proxy Manager) pour auto-remplir les applications
- API d'OUI lookup pour déduire le constructeur depuis la MAC
- Authentification multi-utilisateur + RBAC
- Topologie graphique (D3 ou React Flow)