Initial commit — Stupid Simple Network Inventory
Application web d'inventaire réseau manuel avec FastAPI, Vue 3 et Docker. Inclut l'authentification JWT, la découverte ICMP, et la topologie en cards CSS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
# Data Model
|
||||
|
||||
## Schema Overview
|
||||
|
||||
```
|
||||
users
|
||||
id PK
|
||||
username UNIQUE NOT NULL
|
||||
hashed_password NOT NULL
|
||||
|
||||
vlans
|
||||
id PK
|
||||
vlan_id UNIQUE NULL ← NULL = plain LAN (no 802.1Q tag)
|
||||
name NOT NULL
|
||||
cidr NULL
|
||||
color NULL
|
||||
|
||||
devices
|
||||
id PK
|
||||
name NOT NULL
|
||||
type
|
||||
description
|
||||
is_gateway BOOL
|
||||
is_livebox BOOL
|
||||
virt_type NULL ← null | baremetal | lxc | qemu
|
||||
url NULL
|
||||
|
||||
device_interfaces
|
||||
id PK
|
||||
device_id FK → devices.id NOT NULL
|
||||
vlan_id FK → vlans.id NULL ← NULL = no network assignment
|
||||
ip_address NULL
|
||||
name
|
||||
is_upstream BOOL
|
||||
|
||||
links
|
||||
id PK
|
||||
source_device_id FK → devices.id NOT NULL
|
||||
target_device_id FK → devices.id NOT NULL
|
||||
link_type
|
||||
description
|
||||
```
|
||||
|
||||
## Relationships
|
||||
|
||||
- `Device` 1 → N `DeviceInterface` (cascade delete-orphan)
|
||||
- `Vlan` 1 → N `DeviceInterface` (nullable FK — deleting a VLAN sets `vlan_id` to NULL on its interfaces)
|
||||
- `Link` references `Device` twice (source, target) — links are deleted explicitly in `delete_device` before removing the device
|
||||
|
||||
## Key Design Decisions
|
||||
|
||||
### `vlan_id` is nullable
|
||||
|
||||
A network with `vlan_id = NULL` is a plain LAN without 802.1Q tagging. This allows modelling both tagged and untagged networks in the same table. The UI distinguishes them with "LAN" vs "VLAN X" badges.
|
||||
|
||||
The `vlans` table was originally created with `vlan_id NOT NULL`. The migration `_migrate_vlan_nullable()` recreates it (SQLite cannot `ALTER COLUMN`).
|
||||
|
||||
### Interfaces as a separate table
|
||||
|
||||
A device can belong to multiple networks simultaneously. The `device_interfaces` table is a join table with extra attributes (IP, name, is_upstream). A device appears in every topology card that corresponds to one of its interfaces.
|
||||
|
||||
### `is_gateway` and `is_livebox`
|
||||
|
||||
These boolean flags drive the special WAN and Gateway cards in the topology view. They are independent of network membership — a gateway device can also have interfaces in various VLANs.
|
||||
|
||||
### No foreign key enforcement at the SQLite level
|
||||
|
||||
SQLAlchemy's `ForeignKey` declarations define the schema, but SQLite does not enforce FK constraints unless `PRAGMA foreign_keys=ON` is set per-connection. The application does not enable this pragma, so referential integrity is maintained by application logic (explicit deletes in the routers).
|
||||
|
||||
## SQLite Migrations
|
||||
|
||||
Migrations are idempotent Python functions that run at startup before `Base.metadata.create_all`. They check for the presence of columns or tables before acting, so they are safe to run on every container start.
|
||||
|
||||
Pattern for adding a nullable column:
|
||||
```python
|
||||
def _migrate_my_column():
|
||||
with engine.connect() as conn:
|
||||
if not conn.execute(text(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='devices'"
|
||||
)).fetchone():
|
||||
return
|
||||
cols = [row[1] for row in conn.execute(text("PRAGMA table_info(devices)")).fetchall()]
|
||||
if 'my_column' not in cols:
|
||||
conn.execute(text("ALTER TABLE devices ADD COLUMN my_column VARCHAR"))
|
||||
conn.commit()
|
||||
```
|
||||
|
||||
## Device Types
|
||||
|
||||
18 valid values for `devices.type`:
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `server` | Physical or virtual server |
|
||||
| `switch` | Network switch |
|
||||
| `router` | Network router |
|
||||
| `nas` | Network-attached storage |
|
||||
| `gateway` | Internet gateway / firewall |
|
||||
| `livebox` | ISP-provided box (WAN) |
|
||||
| `access_point` | Wi-Fi access point |
|
||||
| `camera` | IP camera |
|
||||
| `temperature` | Temperature sensor |
|
||||
| `sensor` | Generic sensor |
|
||||
| `hub` | Network hub |
|
||||
| `smart_plug` | Smart power plug |
|
||||
| `alarm` | Alarm system |
|
||||
| `light` | Smart light |
|
||||
| `doorbell` | Smart doorbell |
|
||||
| `desktop` | Desktop computer |
|
||||
| `laptop` | Laptop computer |
|
||||
| `other` | Anything else |
|
||||
|
||||
`url` is hidden in the device form for `desktop` and `laptop` — these types have no web UI.
|
||||
|
||||
## Virtualisation Types
|
||||
|
||||
`devices.virt_type` valid values:
|
||||
|
||||
| Value | Display | Badge |
|
||||
|-------|---------|-------|
|
||||
| `null` | (not shown) | — |
|
||||
| `baremetal` | Bare metal | — |
|
||||
| `lxc` | LXC container | blue "LXC" |
|
||||
| `qemu` | QEMU/KVM VM | purple "VM" |
|
||||
Reference in New Issue
Block a user