diff --git a/README.es.md b/README.es.md
new file mode 100644
index 0000000..9377fd8
--- /dev/null
+++ b/README.es.md
@@ -0,0 +1,231 @@
+#
Stupid Simple Network Inventory
+
+
+
+
+
+
+
+
+Aplicación web autoalojada para inventario manual de red y visualización de topología de red lógica.
+
+
+
+## Características
+
+- **Inventario manual** — añade y gestiona dispositivos (18 tipos) con IPs, VLANs, descripciones y enlaces web opcionales
+- **Vista de topología** — disposición en tarjetas por red (LAN / VLAN 802.1Q), con secciones WAN y puerta de enlace
+- **Ping ICMP** — comprueba la accesibilidad de todos los hosts conocidos con un clic
+- **Descubrimiento automático** — ping sweep + consulta PTR DNS en una subred para importar nuevos hosts
+- **Autenticación** — inicio de sesión JWT con cambio de contraseña obligatorio en el primer uso
+- **Modo oscuro** — alternancia entre tema claro y oscuro
+- **i18n** — francés, inglés, español
+
+## Stack
+
+| Capa | Tecnología |
+|------|-----------|
+| Backend | FastAPI + SQLAlchemy + SQLite (Python 3.11) |
+| Frontend | Vue 3 + Vite, servido por Nginx |
+| Auth | JWT HS256, expiración 24h |
+| Runtime | Docker Compose |
+
+---
+
+## Inicio rápido
+
+```bash
+# 1. Clonar y entrar en el proyecto
+git clone https://git.raspot.in/olivier/stupid-simple-network-inventory.git
+cd stupid-simple-network-inventory
+
+# 2. Crear el directorio de datos propiedad del usuario actual
+mkdir -p db_data
+
+# 3. Configurar el entorno (necesario para la propiedad correcta del bind-mount)
+cp .env.example .env
+# Editar .env:
+# DOCKER_UID / DOCKER_GID → resultado de: id -u && id -g
+# INITIAL_ADMIN_PASSWORD → definir para evitar el bootstrap admin/admin por defecto
+
+# 4. Construir e iniciar
+docker compose --env-file .env up --build -d
+
+# 5. Abrir http://localhost:8080 en el navegador
+```
+
+### Primer inicio de sesión
+
+| Caso | Credenciales | Comportamiento |
+|------|-------------|----------------|
+| `INITIAL_ADMIN_PASSWORD` definido | `admin` / `` | Inicio de sesión normal |
+| `INITIAL_ADMIN_PASSWORD` no definido | `admin` / `admin` | Cambio de contraseña obligatorio antes de acceder a la aplicación |
+
+---
+
+## Configuración
+
+Toda la configuración se realiza mediante variables de entorno. Ver `.env.example` para la lista completa con descripciones.
+
+| Variable | Por defecto | Descripción |
+|----------|-------------|-------------|
+| `SECRET_KEY` | auto-generada | Clave de firma JWT. Definir explícitamente en producción. |
+| `INITIAL_ADMIN_PASSWORD` | _(vacío)_ | Contraseña de bootstrap del admin. Si no se define, se usa `admin/admin` con cambio forzado. |
+| `ALLOWED_ORIGINS` | `*` | Orígenes CORS permitidos (separados por comas). Definir en tu dominio en producción. |
+| `BIND_ADDRESS` | `0.0.0.0` | Dirección IP de escucha. Definir en la interfaz frente al reverse proxy. |
+| `DOCKER_UID` / `DOCKER_GID` | `1000` | UID/GID para el proceso backend. Debe coincidir con el usuario propietario de `./db_data/`. |
+
+### Usar .env con Docker Compose
+
+```bash
+cp .env.example .env
+# Editar .env — definir como mínimo DOCKER_UID, DOCKER_GID, INITIAL_ADMIN_PASSWORD
+docker compose --env-file .env up --build -d
+```
+
+---
+
+## Seguridad
+
+### Gestión de secretos
+
+Dos opciones según sus requisitos de seguridad.
+
+#### Opción A — Secreto auto-generado (recomendado para nodo único)
+
+Dejar `SECRET_KEY` sin definir (o vacío) en `.env`. En el primer arranque, el backend genera una clave hexadecimal aleatoria de 64 caracteres, la escribe en `db_data/secret_key.txt` con permisos **0600** y la reutiliza en cada reinicio posterior. El secreto nunca aparece en una variable de entorno, un archivo compose o un log.
+
+```bash
+# .env — dejar la línea vacía o eliminarla
+SECRET_KEY=
+```
+
+El único requisito es que `db_data/` esté respaldado (ya contiene la base de datos).
+
+#### Opción B — Secreto mediante archivo Docker Compose
+
+Almacena el secreto en un archivo en el host, fuera del control de versiones, y lo monta en el contenedor. El valor nunca aparece en una variable de entorno.
+
+```bash
+# Generar y almacenar el secreto fuera del directorio del proyecto
+mkdir -p ~/.secrets
+python3 -c "import secrets; print(secrets.token_hex(32))" > ~/.secrets/topologie_secret_key
+chmod 600 ~/.secrets/topologie_secret_key
+```
+
+Luego descomentar los bloques `secrets:` en `docker-compose.yml` (ver los comentarios en ese archivo) y eliminar `SECRET_KEY` de `.env`. Docker Compose fusiona la anulación automáticamente:
+
+```bash
+docker compose up -d
+```
+
+---
+
+### Rotación de clave
+
+Para rotar el secreto JWT (invalida todas las sesiones activas):
+
+```bash
+# Opción A — variable de entorno (recomendado)
+# Definir un nuevo SECRET_KEY en la configuración de despliegue y reiniciar
+
+# Opción B — rotación por archivo
+docker compose stop backend
+rm db_data/secret_key.txt
+docker compose start backend
+# Todos los usuarios deberán iniciar sesión de nuevo
+```
+
+### HTTPS
+
+Esta aplicación no termina TLS. Para uso en producción, colócala detrás de un reverse proxy que gestione HTTPS:
+
+```nginx
+# Ejemplo de reverse proxy nginx (externo, en el host o en un contenedor dedicado)
+server {
+ listen 443 ssl;
+ server_name inventory.example.com;
+
+ ssl_certificate /etc/letsencrypt/live/inventory.example.com/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/inventory.example.com/privkey.pem;
+
+ location / {
+ proxy_pass http://127.0.0.1:8080;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+}
+```
+
+Para uso solo local, enlazar a loopback para evitar exposición accidental en la LAN:
+
+```yaml
+# docker-compose.override.yml
+services:
+ frontend:
+ ports:
+ - "127.0.0.1:8080:8080"
+```
+
+### Endurecimiento de contenedores
+
+Los contenedores se ejecutan con privilegios reducidos:
+
+| Medida | Backend | Frontend |
+|--------|---------|----------|
+| Usuario no-root | `DOCKER_UID:DOCKER_GID` (usuario host) | `nginx` (UID 101) |
+| `cap_drop: ALL` | ✓ | ✓ |
+| `cap_add: NET_RAW` | ✓ (ping) | — |
+| `no-new-privileges` | — ¹ | ✓ |
+| Healthcheck | ✓ | ✓ |
+
+¹ Omitido en el backend: el ping usa file capabilities (`cap_net_raw=ep`); `no-new-privileges` suprimiría el bit efectivo del archivo e impediría al subproceso adquirir `CAP_NET_RAW` en su conjunto efectivo aunque el padre lo tenga en su conjunto permitido.
+
+---
+
+## Persistencia de datos
+
+Todos los datos se almacenan en `./db_data/`:
+
+| Archivo | Descripción |
+|---------|-------------|
+| `topology.db` | Base de datos SQLite |
+| `secret_key.txt` | Secreto JWT auto-generado (permisos 0600) |
+
+**Copia de seguridad**: `cp -r db_data/ db_data.bak/`
+
+**Restauración**: detener la stack, reemplazar `db_data/`, reiniciar.
+
+---
+
+## Desarrollo
+
+### Tests del backend
+
+```bash
+cd backend
+pip install -r requirements.txt -r requirements-test.txt
+pytest tests/ -v
+```
+
+### Dev local (sin Docker)
+
+```bash
+# Backend
+cd backend
+pip install -r requirements.txt
+uvicorn main:app --reload
+
+# Frontend (terminal separada)
+cd frontend
+npm install
+npm run dev # Servidor dev Vite en :5173, proxifica /api/ hacia :8000
+```
+
+---
+
+## Arquitectura
+
+Ver [`docs/architecture.md`](docs/architecture.md) para el flujo de solicitudes detallado, la configuración Docker y el modelo de autenticación.
diff --git a/README.fr.md b/README.fr.md
new file mode 100644
index 0000000..2fe67f4
--- /dev/null
+++ b/README.fr.md
@@ -0,0 +1,231 @@
+#
Stupid Simple Network Inventory
+
+
+
+
+
+
+
+
+Application web auto-hébergée pour l'inventaire manuel de réseau et la visualisation de topologie réseau logique.
+
+
+
+## Fonctionnalités
+
+- **Inventaire manuel** — ajout et gestion d'équipements (18 types) avec IPs, VLANs, descriptions et liens web optionnels
+- **Vue topologie** — disposition en cards par réseau (LAN / VLAN 802.1Q), avec sections WAN et passerelle
+- **Ping ICMP** — vérification de l'accessibilité de tous les hôtes connus en un clic
+- **Découverte automatique** — ping sweep + lookup PTR DNS sur un sous-réseau pour importer de nouveaux hôtes
+- **Authentification** — connexion JWT avec changement de mot de passe forcé à la première utilisation
+- **Mode sombre** — bascule thème clair / sombre
+- **i18n** — français, anglais, espagnol
+
+## Stack
+
+| Couche | Technologie |
+|--------|------------|
+| Backend | FastAPI + SQLAlchemy + SQLite (Python 3.11) |
+| Frontend | Vue 3 + Vite, servi par Nginx |
+| Auth | JWT HS256, expiration 24h |
+| Runtime | Docker Compose |
+
+---
+
+## Démarrage rapide
+
+```bash
+# 1. Cloner et entrer dans le projet
+git clone https://git.raspot.in/olivier/stupid-simple-network-inventory.git
+cd stupid-simple-network-inventory
+
+# 2. Créer le répertoire de données appartenant à l'utilisateur courant
+mkdir -p db_data
+
+# 3. Configurer l'environnement (requis pour la propriété correcte du bind-mount)
+cp .env.example .env
+# Éditer .env :
+# DOCKER_UID / DOCKER_GID → résultat de : id -u && id -g
+# INITIAL_ADMIN_PASSWORD → à définir pour éviter le bootstrap admin/admin par défaut
+
+# 4. Construire et démarrer
+docker compose --env-file .env up --build -d
+
+# 5. Ouvrir http://localhost:8080 dans votre navigateur
+```
+
+### Première connexion
+
+| Cas | Identifiants | Comportement |
+|-----|-------------|--------------|
+| `INITIAL_ADMIN_PASSWORD` défini | `admin` / `` | Connexion normale |
+| `INITIAL_ADMIN_PASSWORD` non défini | `admin` / `admin` | Changement de mot de passe forcé avant d'accéder à l'application |
+
+---
+
+## Configuration
+
+Toute la configuration se fait via des variables d'environnement. Voir `.env.example` pour la liste complète avec descriptions.
+
+| Variable | Défaut | Description |
+|----------|--------|-------------|
+| `SECRET_KEY` | auto-générée | Clé de signature JWT. À définir explicitement en production. |
+| `INITIAL_ADMIN_PASSWORD` | _(vide)_ | Mot de passe admin de bootstrap. Si non défini, `admin/admin` est utilisé avec changement forcé. |
+| `ALLOWED_ORIGINS` | `*` | Origines CORS autorisées (séparées par des virgules). À définir sur votre domaine en production. |
+| `BIND_ADDRESS` | `0.0.0.0` | Adresse IP d'écoute. À définir sur l'interface face au reverse proxy. |
+| `DOCKER_UID` / `DOCKER_GID` | `1000` | UID/GID pour le processus backend. Doit correspondre à l'utilisateur propriétaire de `./db_data/`. |
+
+### Utilisation de .env avec Docker Compose
+
+```bash
+cp .env.example .env
+# Éditer .env — définir au minimum DOCKER_UID, DOCKER_GID, INITIAL_ADMIN_PASSWORD
+docker compose --env-file .env up --build -d
+```
+
+---
+
+## Sécurité
+
+### Gestion des secrets
+
+Deux options selon vos exigences de sécurité.
+
+#### Option A — Secret auto-généré (recommandé pour un nœud unique)
+
+Laisser `SECRET_KEY` non défini (ou vide) dans `.env`. Au premier démarrage, le backend génère une clé hexadécimale aléatoire de 64 caractères, l'écrit dans `db_data/secret_key.txt` avec les permissions **0600**, et la réutilise à chaque redémarrage. Le secret n'apparaît jamais dans une variable d'environnement, un fichier compose ou un log.
+
+```bash
+# .env — laisser la ligne vide ou la supprimer
+SECRET_KEY=
+```
+
+La seule exigence est que `db_data/` soit sauvegardé (il contient déjà la base de données).
+
+#### Option B — Secret via fichier Docker Compose
+
+Stocke le secret dans un fichier sur l'hôte, hors du contrôle de version, et le monte dans le conteneur. La valeur n'apparaît jamais dans une variable d'environnement.
+
+```bash
+# Générer et stocker le secret en dehors du répertoire du projet
+mkdir -p ~/.secrets
+python3 -c "import secrets; print(secrets.token_hex(32))" > ~/.secrets/topologie_secret_key
+chmod 600 ~/.secrets/topologie_secret_key
+```
+
+Décommenter ensuite les blocs `secrets:` dans `docker-compose.yml` (voir les commentaires dans ce fichier) et supprimer `SECRET_KEY` de `.env`. Docker Compose fusionne la surcharge automatiquement :
+
+```bash
+docker compose up -d
+```
+
+---
+
+### Rotation de clé
+
+Pour faire tourner le secret JWT (invalide toutes les sessions actives) :
+
+```bash
+# Option A — variable d'environnement (recommandé)
+# Définir un nouveau SECRET_KEY dans la configuration de déploiement et redémarrer
+
+# Option B — rotation par fichier
+docker compose stop backend
+rm db_data/secret_key.txt
+docker compose start backend
+# Tous les utilisateurs devront se reconnecter
+```
+
+### HTTPS
+
+Cette application ne termine pas TLS. Pour un usage en production, placez-la derrière un reverse proxy gérant HTTPS :
+
+```nginx
+# Exemple de reverse proxy nginx (externe, sur l'hôte ou un conteneur dédié)
+server {
+ listen 443 ssl;
+ server_name inventory.example.com;
+
+ ssl_certificate /etc/letsencrypt/live/inventory.example.com/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/inventory.example.com/privkey.pem;
+
+ location / {
+ proxy_pass http://127.0.0.1:8080;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+}
+```
+
+Pour un usage local uniquement, lier à la boucle locale pour éviter une exposition LAN accidentelle :
+
+```yaml
+# docker-compose.override.yml
+services:
+ frontend:
+ ports:
+ - "127.0.0.1:8080:8080"
+```
+
+### Durcissement des conteneurs
+
+Les conteneurs s'exécutent avec des privilèges réduits :
+
+| Mesure | Backend | Frontend |
+|--------|---------|----------|
+| Utilisateur non-root | `DOCKER_UID:DOCKER_GID` (utilisateur hôte) | `nginx` (UID 101) |
+| `cap_drop: ALL` | ✓ | ✓ |
+| `cap_add: NET_RAW` | ✓ (ping) | — |
+| `no-new-privileges` | — ¹ | ✓ |
+| Healthcheck | ✓ | ✓ |
+
+¹ Omis sur le backend : le ping utilise les file capabilities (`cap_net_raw=ep`) ; `no-new-privileges` supprimerait le bit effectif du fichier et empêcherait le sous-processus d'acquérir `CAP_NET_RAW` dans son ensemble effectif même si le parent le détient dans son ensemble permis.
+
+---
+
+## Persistance des données
+
+Toutes les données sont stockées dans `./db_data/` :
+
+| Fichier | Description |
+|---------|-------------|
+| `topology.db` | Base de données SQLite |
+| `secret_key.txt` | Secret JWT auto-généré (permissions 0600) |
+
+**Sauvegarde** : `cp -r db_data/ db_data.bak/`
+
+**Restauration** : arrêter la stack, remplacer `db_data/`, redémarrer.
+
+---
+
+## Développement
+
+### Tests backend
+
+```bash
+cd backend
+pip install -r requirements.txt -r requirements-test.txt
+pytest tests/ -v
+```
+
+### Dev local (sans Docker)
+
+```bash
+# Backend
+cd backend
+pip install -r requirements.txt
+uvicorn main:app --reload
+
+# Frontend (terminal séparé)
+cd frontend
+npm install
+npm run dev # Serveur dev Vite sur :5173, proxifie /api/ vers :8000
+```
+
+---
+
+## Architecture
+
+Voir [`docs/architecture.md`](docs/architecture.md) pour le flux de requêtes détaillé, la configuration Docker et le modèle d'authentification.