Files
IPAM/ARCHITECTURE.md
Mathieu BOURBON fbb6138c28 first commit
2026-04-18 16:24:44 +02:00

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

  1. Modular monolith — un seul projet Next.js, mais des modules métier isolés sous src/modules/<domaine>/. 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/<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)

  1. Créer src/modules/vlans/ avec vlans.schema.ts, vlans.service.ts, index.ts
  2. Ajouter le modèle Prisma dans prisma/schema.prismanpm 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)