# 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 1. **Modular monolith** — un seul projet Next.js, mais des modules métier isolés sous `src/modules//`. Chaque module expose son `service` ; les routes API et l'UI n'accèdent JAMAIS directement à Prisma pour un domaine. 2. **Validation à la frontière** — tout input externe (API, formulaire, scanner) est validé via un schéma Zod avant d'atteindre le service. 3. **Registry pattern** pour les scanners — ajouter une capacité de découverte se fait en implémentant une interface `Scanner` et en l'enregistrant dans le registre (aucune autre partie du code n'est touchée). 4. **DB-agnostic** — Prisma lit `DATABASE_PROVIDER` et `DATABASE_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//route.ts (validation + handleError) → src/modules//service.ts (règles métier) → src/modules//repository (Prisma) → DB (SQLite | PostgreSQL) ``` ## Ajouter un module métier (ex: VLAN) 1. Créer `src/modules/vlans/` avec `vlans.schema.ts`, `vlans.service.ts`, `index.ts` 2. Ajouter le modèle Prisma dans `prisma/schema.prisma` → `npm run db:migrate` 3. Créer les routes `src/app/api/vlans/route.ts` (et `[id]/route.ts`) — copier le pattern des hôtes 4. Créer la page `src/app/(dashboard)/vlans/page.tsx` 5. (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) 1. Créer `src/modules/discovery/scanners/snmp.scanner.ts` exportant une constante conforme à l'interface `Scanner` (`kind`, `label`, `enabled`, `run`) 2. L'importer dans `src/modules/discovery/registry.ts` et l'ajouter au `scannersRegistry` avec sa clé `ScannerKind` (mettre à jour le type union dans `types.ts`) 3. Exposer la clé dans `bodySchema` de `src/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)