# MODULE PÉRIPHÉRIQUES - Spécifications Complètes
## Linux BenchTools - Extension Inventaire Matériel

**Version**: 1.0
**Date**: 2025-12-30
**Auteur**: Analyse collaborative
**Projet**: serv_benchmark - Module Périphériques

---

## 📋 TABLE DES MATIÈRES

1. [Vue d'ensemble](#vue-densemble)
2. [Objectifs et Portée](#objectifs-et-portée)
3. [Types de Périphériques](#types-de-périphériques)
4. [Caractéristiques des Données](#caractéristiques-des-données)
5. [Architecture Base de Données](#architecture-base-de-données)
6. [Architecture Backend](#architecture-backend)
7. [Architecture Frontend](#architecture-frontend)
8. [Fonctionnalités Principales](#fonctionnalités-principales)
9. [Système de Localisation](#système-de-localisation)
10. [Système de Prêt](#système-de-prêt)
11. [Appareils Complets](#appareils-complets)
12. [Configuration YAML](#configuration-yaml)
13. [Plan de Déploiement](#plan-de-déploiement)
14. [Prompt de Développement](#prompt-de-développement)

---

## 🎯 VUE D'ENSEMBLE

### Contexte

Le projet **Linux BenchTools** est une application web existante permettant de :
- Benchmarker des machines Linux (CPU, RAM, Disque, Réseau, GPU)
- Stocker l'historique des benchmarks
- Gérer un inventaire de machines (devices)

### Besoin

Ajouter un **module complet de gestion d'inventaire de périphériques** pour :
- Cataloguer tous les périphériques informatiques (USB, Bluetooth, PCIe, câbles, etc.)
- Gérer leur localisation physique (pièces, placards, tiroirs)
- Suivre les prêts/emprunts
- Lier certains périphériques aux machines benchmarkées
- Gérer stock, photos, documents, garanties

### Architecture Existante

**Backend**:
- FastAPI + SQLAlchemy ORM
- Base de données: SQLite (`data.db`)
- Structure: `/backend/app/` avec models/, schemas/, api/, core/
- Authentification par token

**Frontend**:
- Vanilla JavaScript (pas de framework)
- Thème: Monokai dark
- Layout: Two-panel design
- Pages: Dashboard, Devices, Settings

**Base de données existante** (`data.db`):
- `devices` - Machines inventoriées
- `hardware_snapshots` - Snapshots matériel
- `benchmarks` - Résultats benchmarks
- `documents` - Documents devices
- `manufacturer_links` - Liens

---

## 🎯 OBJECTIFS ET PORTÉE

### Objectifs Principaux

1. **Inventaire Complet**
   - Cataloguer TOUS les périphériques informatiques possibles
   - USB, Bluetooth, Wi-Fi, PCIe, HDMI, Câbles, Visserie, etc.
   - Appareils complets (Laptops, Desktops, Smartphones, Tablettes, Serveurs, Consoles)

2. **Gestion Physique**
   - Localisation précise (Pièce > Placard > Tiroir > Étagère)
   - Tracking des déplacements
   - QR codes pour identification rapide

3. **Gestion de Prêt**
   - Prêter périphériques à des personnes
   - Suivre les retours
   - Gérer cautions
   - Alertes et rappels automatiques

4. **Intégration Benchmarks**
   - Lier appareils complets aux devices benchmarkés
   - Afficher historique benchmarks
   - Sync automatique des specs

5. **Gestion Avancée**
   - Stock et quantités
   - Photos et documents
   - Évaluation qualité (0-5 étoiles)
   - Configuration YAML flexible
   - Compression d'images automatique

### Architecture

**BASE DE DONNÉES SÉPARÉE**: `peripherals.db`
- Isolation des données
- Performance optimale
- Backups indépendants
- Module activable/désactivable

---

## 📦 TYPES DE PÉRIPHÉRIQUES

### 1. CONNECTIVITÉ FILAIRE

#### USB (Universal Serial Bus)
- **Types**: USB Type-A (2.0, 3.0, 3.1, 3.2), USB Type-C, Thunderbolt 3/4, Mini/Micro
- **Périphériques**:
  - Clés USB / Disques externes
  - Souris / Claviers
  - Webcams
  - Imprimantes / Scanners
  - Adaptateurs réseau (Ethernet, Wi-Fi)
  - Cartes son externes / DAC
  - Dongles (Bluetooth, Wi-Fi, DVB-T)
  - Lecteurs de cartes
  - Contrôleurs de jeux
  - Microphones / Interfaces audio
  - Hubs USB

#### PCIe (Peripheral Component Interconnect Express)
- Cartes graphiques (GPU)
- Cartes son
- Cartes réseau (Ethernet, Wi-Fi, Fibre)
- Cartes d'acquisition vidéo
- Contrôleurs RAID
- Adaptateurs NVMe
- Cartes USB/Thunderbolt d'extension
- Cartes TV/DVB

#### SATA / M.2 / NVMe
- Disques durs (HDD)
- SSD SATA
- SSD M.2 (SATA/NVMe)
- Lecteurs optiques (CD/DVD/Blu-ray)

#### Audio / Vidéo
- **Audio**: Jack 3.5mm/6.35mm, XLR, Optique S/PDIF, Coaxial
- **Vidéo**: HDMI (1.4, 2.0, 2.1), DisplayPort, DVI, VGA, Mini DisplayPort
- **Périphériques**: Écrans, Projecteurs, Casques, Enceintes, Microphones

### 2. CONNECTIVITÉ SANS-FIL

#### Wi-Fi
- Normes: 802.11 a/b/g/n/ac/ax (Wi-Fi 4/5/6/6E/7)
- Bandes: 2.4 GHz, 5 GHz, 6 GHz
- Adaptateurs USB, Cartes PCIe/M.2, Points d'accès

#### Bluetooth
- Versions: 2.0 à 5.3
- Profils: A2DP, HFP, HSP, HID
- Casques, Claviers, Souris, Enceintes, Adaptateurs

#### Autres
- NFC, RF propriétaire, Infrarouge

### 3. RÉSEAU

#### Ethernet
- Vitesses: 10/100/1000 Mbps, 2.5G, 5G, 10G, 25G, 40G
- Cartes NIC, Switches, Routeurs, Modems

#### Fibre Optique
- Cartes SFP/SFP+, Convertisseurs

### 4. CÂBLES

#### Types de Câbles
- **HDMI**: Versions 1.4, 2.0, 2.1 (Standard, Premium, Ultra)
- **DisplayPort**: Versions 1.2, 1.4, 2.0
- **USB**: USB-A, USB-C, Mini, Micro (différentes longueurs)
- **Ethernet**: Cat5e, Cat6, Cat6a, Cat7, Cat8 (blindé/non-blindé)
- **Audio**: Jack 3.5mm, XLR, RCA, Optique
- **Alimentation**: C13, C14, Secteur, USB-C PD
- **Vidéo**: DVI, VGA, Composite

**Caractéristiques spécifiques**:
- Longueur (mètres)
- Certification (pour HDMI)
- Blindage (pour Ethernet)
- Puissance supportée (pour USB-C)

### 5. VISSERIE ET FIXATIONS

#### Types
- **Vis**: M2, M3, M4 (différentes longueurs, têtes: plate, fraisée, bombée)
- **Entretoises (Standoffs)**: M2, M3, M4 (différentes hauteurs)
- **Écrous**, **Rondelles**
- **Clips plastiques**, **Attaches câbles**

**Caractéristiques**:
- Diamètre/Norme
- Longueur
- Matériau (Acier, Inox, Laiton, Plastique)
- Type de tête

### 6. BOÎTIERS PC

#### Formats
- Mini-ITX
- Micro-ATX
- ATX
- E-ATX
- Full Tower

**Caractéristiques**:
- Emplacements 3.5" / 2.5"
- Ventilateurs inclus/supportés
- Fenêtre latérale
- RGB
- Dimensions

### 7. STOCKAGE

- Disques durs externes
- SSD externes
- NAS (Network Attached Storage)
- Lecteurs de bandes
- Stations d'accueil

### 8. ENTRÉE / SORTIE

#### Entrée
- Claviers (USB, Bluetooth, PS/2)
- Souris / Trackballs / Tablettes graphiques
- Scanners
- Lecteurs de codes-barres
- Lecteurs biométriques
- Webcams
- Microphones

#### Sortie
- Imprimantes (USB, réseau, sans-fil)
- Imprimantes 3D
- Enceintes
- Projecteurs

### 9. APPAREILS COMPLETS

#### Desktop (PC de Bureau)
**Caractéristiques**:
- CPU (marque, modèle, cores, threads, fréquence)
- RAM (capacité, type DDR, fréquence)
- GPU (intégré/dédié, modèle, VRAM)
- Stockage (type, capacité)
- Carte mère (marque, modèle, chipset)
- Alimentation (wattage, certification 80+)
- Boîtier (format, modèle)
- Refroidissement (Air/AIO/Watercooling)
- Système d'exploitation

#### Laptop (Ordinateur Portable)
**Caractéristiques**:
- Écran (taille, résolution, tactile, taux rafraîchissement)
- CPU (marque, modèle, génération)
- RAM (capacité, extensible, max)
- Stockage (type, capacité, slots M.2 libres)
- GPU (intégré/dédié/hybrid)
- Batterie (Wh, autonomie)
- Connectique (USB-A, USB-C, Thunderbolt, HDMI, Ethernet, SD)
- Webcam (résolution)
- Poids

#### Tablette
**Caractéristiques**:
- OS (iOS/iPadOS, Android, Windows)
- Écran (taille, résolution, type: LCD/OLED)
- Processeur
- RAM, Stockage
- Batterie (mAh)
- Stylet (inclus, modèle)
- Clavier (inclus)
- 4G/5G
- Poids

#### Smartphone
**Caractéristiques**:
- OS (iOS, Android)
- Écran (taille, résolution, type, fréquence Hz)
- Processeur
- RAM, Stockage
- Caméras (principale MP, ultra-wide, téléphoto, frontale)
- Batterie (mAh, charge rapide W, sans-fil)
- 5G, Dual SIM, eSIM
- Résistance (IP67/IP68)
- Lecteur d'empreintes
- IMEI

#### Serveur
**Caractéristiques**:
- Format (Tour, Rack 1U/2U/4U, Blade)
- OS (Windows Server, Linux, ESXi, Proxmox)
- CPU (nombre, modèle, cores total)
- RAM (capacité, type ECC)
- RAID (contrôleur, niveau)
- Baies (3.5", 2.5")
- Alimentation (redondante, wattage)
- IPMI/iLO/iDRAC

#### Console de Jeu
**Caractéristiques**:
- Type: Console de salon, Portable, Hybrid
- Marque: PlayStation, Xbox, Nintendo, Steam, Autre
- Modèle: PS5, Xbox Series X, Switch OLED, Steam Deck, etc.
- Génération: PS5 (9ème gen), PS4 (8ème gen), etc.
- Stockage (capacité, type, extensible)
- Résolution max (1080p, 4K, 8K)
- FPS max
- Ray tracing
- VR compatible
- Lecteur disque physique
- Rétrocompatibilité
- Manettes incluses
- Connectique (HDMI version, USB, Ethernet)
- Dimensions
- Poids

**Exemple de configuration YAML**:
```yaml
- id: console_gaming
  nom: "Console de Jeu"
  icon: "gamepad"
  is_complete_device: true

  champs_specifiques:
    - type_console:
        type: "select"
        options: ["Salon", "Portable", "Hybrid"]
        label: "Type de console"
    - marque:
        type: "select"
        options: ["PlayStation", "Xbox", "Nintendo", "Steam", "Autre"]
    - modele:
        type: "text"
        placeholder: "ex: PlayStation 5, Xbox Series X, Switch OLED"
    - generation:
        type: "text"
        label: "Génération"
    - stockage_go:
        type: "number"
        label: "Stockage (Go)"
    - stockage_type:
        type: "select"
        options: ["SSD", "HDD", "Cartouche"]
    - stockage_extensible:
        type: "boolean"
    - resolution_max:
        type: "select"
        options: ["720p", "1080p", "1440p", "4K", "8K"]
    - fps_max:
        type: "number"
        label: "FPS maximum"
    - ray_tracing:
        type: "boolean"
    - vr_compatible:
        type: "boolean"
        label: "Compatible VR"
    - lecteur_disque:
        type: "boolean"
        label: "Lecteur disque physique"
    - retrocompatibilite:
        type: "text"
        label: "Rétrocompatibilité"
        placeholder: "ex: PS4, Xbox One"
    - manettes_incluses:
        type: "number"
        label: "Manettes incluses"
    - hdmi_version:
        type: "select"
        options: ["1.4", "2.0", "2.1"]
    - ports_usb:
        type: "number"
    - ethernet_gbps:
        type: "select"
        options: ["1", "2.5", "10"]
    - wifi:
        type: "select"
        options: ["Wi-Fi 5", "Wi-Fi 6", "Wi-Fi 6E"]
    - bluetooth:
        type: "select"
        options: ["4.0", "5.0", "5.1", "5.2"]
    - poids_kg:
        type: "number"
        step: 0.1
```

### 10. AUTRES

- Onduleurs (UPS)
- Alimentations PC
- Cartes d'acquisition (DAQ)
- Dispositifs KVM
- Contrôleurs MIDI
- GPS USB
- Dongles de sécurité

---

## 🔧 CARACTÉRISTIQUES DES DONNÉES

### Caractéristiques GLOBALES (tous périphériques)

```
📝 IDENTIFICATION
├── id (auto-increment)
├── nom (user-defined name)
├── type_principal (USB, Bluetooth, PCIe, etc.)
├── sous_type (Clé USB, Souris, GPU, etc.)
├── marque (manufacturer)
├── modele (model number)
├── numero_serie (serial number)
└── ean_upc (barcode)

💰 ACHAT
├── boutique (store name)
├── date_achat (purchase date)
├── prix (price)
├── devise (currency, default: EUR)
├── garantie_duree_mois (warranty duration)
└── garantie_expiration (warranty expiration date)

⭐ ÉVALUATION
├── rating (0-5 étoiles, float)
└── notes (free text review)

📦 STOCK
├── quantite_totale (total quantity)
├── quantite_disponible (available)
├── seuil_alerte (alert threshold)
└── emplacement_stockage (storage location)

📷 MÉDIAS
├── photos[] (array of image paths)
├── pdf_manuels[] (manuals)
├── pdf_factures[] (invoices)
└── pdf_autres[] (other docs)

🔗 LIENS & RÉFÉRENCES
├── url_fabricant (manufacturer page)
├── url_support (support page)
├── url_drivers (drivers download)
├── url_documentation
└── liens_personnalises[] (custom links)

📋 MÉTADONNÉES
├── date_creation (record creation)
├── date_modification (last update)
├── etat (Neuf, Bon, Usagé, Défectueux, Retiré)
├── localisation (physical location)
├── proprietaire (owner)
├── tags[] (custom tags, JSON)
└── notes (free text)

🐧 IDENTIFICATION LINUX
├── device_path (e.g., /dev/sda, /dev/input/mouse0)
├── sysfs_path (e.g., /sys/devices/pci0000:00/...)
├── vendor_id (USB: VID, PCI: vendor ID)
├── product_id (USB: PID, PCI: device ID)
├── class_id (device class)
├── driver_utilise (kernel driver in use)
├── modules_kernel[] (required kernel modules, JSON)
├── udev_rules (custom udev rules)
└── identifiant_systeme (lsusb, lspci output)

⚙️ INSTALLATION & PROBLÈMES
├── installation_auto (auto-detected: bool)
├── driver_requis (required drivers)
├── firmware_requis (required firmware)
├── paquets_necessaires[] (required packages, JSON)
├── commandes_installation (installation commands)
├── problemes_connus (known issues)
├── solutions (solutions/workarounds)
└── compatibilite_noyau (kernel version compatibility)

🔌 CONNECTIVITÉ
├── interface_connexion (USB, PCIe, Bluetooth, etc.)
├── connecte_a (connected to which device/port)
└── consommation_electrique_w (power consumption)

📍 LOCALISATION PHYSIQUE
├── location_id (FK vers locations)
├── location_details (détails supplémentaires)
└── location_auto (bool: suit le device assigné)

🤝 PRÊT / EMPRUNT
├── en_pret (bool)
├── pret_actuel_id (FK vers peripheral_loans)
└── prete_a (nom de l'emprunteur, pour affichage rapide)

💻 APPAREIL COMPLET
├── is_complete_device (bool)
├── device_type (desktop, laptop, tablet, smartphone, server, console)
├── linked_device_id (→ devices.id dans data.db, pour benchmarks)
└── device_id (→ devices.id dans data.db, assignation actuelle)

🎨 DONNÉES SPÉCIFIQUES
└── caracteristiques_specifiques (JSON flexible par type)
```

### Caractéristiques SPÉCIFIQUES (exemples par type)

#### Stockage USB
```json
{
  "capacite_go": 128,
  "type_memoire": "Flash NAND",
  "usb_version": "3.2 Gen 1",
  "vitesse_lecture_mbs": 150,
  "vitesse_ecriture_mbs": 50,
  "systeme_fichiers": "exFAT",
  "chiffrement": true,
  "chiffrement_type": "AES 256-bit"
}
```

#### Souris
```json
{
  "connexion": "Bluetooth 5.0",
  "capteur_type": "Optique",
  "dpi_max": 16000,
  "dpi_reglable": true,
  "nombre_boutons": 8,
  "boutons_programmables": 6,
  "autonomie_heures": 200,
  "type_batterie": "Rechargeable Li-ion",
  "eclairage_rgb": true
}
```

#### Câble HDMI
```json
{
  "longueur_m": 2,
  "version_hdmi": "2.1",
  "certification": "Premium",
  "debit_max_gbps": 48,
  "support_4k_120hz": true,
  "support_8k": true,
  "arc_earc": "eARC"
}
```

#### Desktop PC
```json
{
  "systeme_exploitation": "Windows 11 Pro",
  "cpu_marque": "Intel",
  "cpu_modele": "Core i7-12700K",
  "cpu_cores": 12,
  "cpu_threads": 20,
  "ram_total_go": 32,
  "ram_type": "DDR5",
  "ram_freq_mhz": 5600,
  "gpu_type": "Dédié",
  "gpu_modele": "NVIDIA RTX 4070",
  "gpu_vram_go": 12,
  "stockage_principal": "1TB NVMe SSD",
  "carte_mere_marque": "ASUS",
  "carte_mere_modele": "ROG STRIX Z690-F",
  "alimentation_w": 850,
  "alimentation_certification": "80+ Gold",
  "boitier_format": "ATX",
  "refroidissement": "AIO 280mm"
}
```

#### Console de Jeu
```json
{
  "type_console": "Salon",
  "marque": "PlayStation",
  "modele": "PlayStation 5",
  "generation": "9ème génération",
  "stockage_go": 825,
  "stockage_type": "SSD",
  "stockage_extensible": true,
  "resolution_max": "4K",
  "fps_max": 120,
  "ray_tracing": true,
  "vr_compatible": true,
  "lecteur_disque": true,
  "retrocompatibilite": "PS4",
  "manettes_incluses": 1,
  "hdmi_version": "2.1",
  "ports_usb": 4,
  "ethernet_gbps": "1",
  "wifi": "Wi-Fi 6",
  "bluetooth": "5.1",
  "poids_kg": 4.5
}
```

---

## 🗄️ ARCHITECTURE BASE DE DONNÉES

### Stratégie: Deux Bases de Données Séparées

```
/backend/data/
├── data.db                    # DB PRINCIPALE (existante)
│   ├── devices                # Machines benchmarkées
│   ├── hardware_snapshots     # Snapshots hardware
│   ├── benchmarks             # Résultats benchmarks
│   ├── documents              # Documents devices
│   ├── manufacturer_links     # Liens devices
│   └── disk_smart             # Données SMART
│
└── peripherals.db             # DB PÉRIPHÉRIQUES (nouvelle)
    ├── peripherals            # Périphériques
    ├── peripheral_photos      # Photos
    ├── peripheral_documents   # Documents
    ├── peripheral_links       # Liens
    ├── peripheral_loans       # Prêts
    ├── peripheral_location_history  # Historique déplacements
    ├── peripheral_attachments # Relations périph ↔ périph
    ├── locations              # Emplacements physiques
    └── borrower_blacklist     # Liste noire emprunteurs
```

### Pourquoi Séparé ?

✅ **Isolation** - Données indépendantes
✅ **Performance** - Pas de contention
✅ **Scalabilité** - Peut grossir indépendamment
✅ **Backups** - Stratégies distinctes
✅ **Migration** - Plus facile
✅ **Modularité** - Activable/désactivable

### Schéma Table `peripherals`

```sql
CREATE TABLE peripherals (
    -- IDENTIFICATION
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    nom VARCHAR(255) NOT NULL,
    type_principal VARCHAR(100) NOT NULL,
    sous_type VARCHAR(100),
    marque VARCHAR(100),
    modele VARCHAR(255),
    numero_serie VARCHAR(255),
    ean_upc VARCHAR(50),

    -- ACHAT
    boutique VARCHAR(255),
    date_achat DATE,
    prix DECIMAL(10, 2),
    devise VARCHAR(10) DEFAULT 'EUR',
    garantie_duree_mois INTEGER,
    garantie_expiration DATE,

    -- ÉVALUATION
    rating FLOAT DEFAULT 0,  -- 0-5 étoiles

    -- STOCK
    quantite_totale INTEGER DEFAULT 1,
    quantite_disponible INTEGER DEFAULT 1,
    seuil_alerte INTEGER DEFAULT 0,

    -- MÉTADONNÉES
    date_creation TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    date_modification TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    etat VARCHAR(50) DEFAULT 'Neuf',
    localisation VARCHAR(255),
    proprietaire VARCHAR(100),
    tags TEXT,  -- JSON array
    notes TEXT,

    -- LINUX IDENTIFICATION
    device_path VARCHAR(255),
    sysfs_path VARCHAR(500),
    vendor_id VARCHAR(20),
    product_id VARCHAR(20),
    class_id VARCHAR(20),
    driver_utilise VARCHAR(100),
    modules_kernel TEXT,  -- JSON
    udev_rules TEXT,
    identifiant_systeme TEXT,

    -- INSTALLATION
    installation_auto BOOLEAN DEFAULT FALSE,
    driver_requis TEXT,
    firmware_requis TEXT,
    paquets_necessaires TEXT,  -- JSON
    commandes_installation TEXT,
    problemes_connus TEXT,
    solutions TEXT,
    compatibilite_noyau VARCHAR(100),

    -- CONNECTIVITÉ
    interface_connexion VARCHAR(100),
    connecte_a VARCHAR(255),
    consommation_electrique_w DECIMAL(6, 2),

    -- LOCALISATION PHYSIQUE
    location_id INTEGER,
    location_details VARCHAR(500),
    location_auto BOOLEAN DEFAULT TRUE,

    -- PRÊT
    en_pret BOOLEAN DEFAULT FALSE,
    pret_actuel_id INTEGER,
    prete_a VARCHAR(255),

    -- APPAREIL COMPLET
    is_complete_device BOOLEAN DEFAULT FALSE,
    device_type VARCHAR(50),

    -- LIEN VERS DB PRINCIPALE (logique, pas FK SQL)
    linked_device_id INTEGER,  -- → devices.id dans data.db (benchmarks)
    device_id INTEGER,         -- → devices.id dans data.db (assignation)

    -- DONNÉES SPÉCIFIQUES
    caracteristiques_specifiques TEXT  -- JSON
);

CREATE INDEX idx_peripherals_type ON peripherals(type_principal);
CREATE INDEX idx_peripherals_sous_type ON peripherals(sous_type);
CREATE INDEX idx_peripherals_marque ON peripherals(marque);
CREATE INDEX idx_peripherals_device ON peripherals(device_id);
CREATE INDEX idx_peripherals_etat ON peripherals(etat);
CREATE INDEX idx_peripherals_complete_device ON peripherals(is_complete_device);
CREATE INDEX idx_peripherals_en_pret ON peripherals(en_pret);
```

### Table `peripheral_photos`

```sql
CREATE TABLE peripheral_photos (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    peripheral_id INTEGER NOT NULL,
    filename VARCHAR(255) NOT NULL,
    stored_path VARCHAR(500) NOT NULL,
    mime_type VARCHAR(100),
    size_bytes INTEGER,
    uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    description TEXT,
    is_primary BOOLEAN DEFAULT FALSE,
    FOREIGN KEY (peripheral_id) REFERENCES peripherals(id) ON DELETE CASCADE
);

CREATE INDEX idx_peripheral_photos_pid ON peripheral_photos(peripheral_id);
```

### Table `peripheral_documents`

```sql
CREATE TABLE peripheral_documents (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    peripheral_id INTEGER NOT NULL,
    doc_type VARCHAR(50) NOT NULL,  -- manual, warranty, invoice, datasheet, other
    filename VARCHAR(255) NOT NULL,
    stored_path VARCHAR(500) NOT NULL,
    mime_type VARCHAR(100),
    size_bytes INTEGER,
    uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    description TEXT,
    FOREIGN KEY (peripheral_id) REFERENCES peripherals(id) ON DELETE CASCADE
);

CREATE INDEX idx_peripheral_documents_pid ON peripheral_documents(peripheral_id);
CREATE INDEX idx_peripheral_documents_type ON peripheral_documents(doc_type);
```

### Table `peripheral_links`

```sql
CREATE TABLE peripheral_links (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    peripheral_id INTEGER NOT NULL,
    link_type VARCHAR(50) NOT NULL,  -- manufacturer, support, drivers, documentation, custom
    label VARCHAR(255) NOT NULL,
    url TEXT NOT NULL,
    FOREIGN KEY (peripheral_id) REFERENCES peripherals(id) ON DELETE CASCADE
);

CREATE INDEX idx_peripheral_links_pid ON peripheral_links(peripheral_id);
```

### Table `peripheral_loans`

```sql
CREATE TABLE peripheral_loans (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    peripheral_id INTEGER NOT NULL,

    -- Emprunteur
    emprunte_par VARCHAR(255) NOT NULL,
    email_emprunteur VARCHAR(255),
    telephone VARCHAR(50),

    -- Dates
    date_pret DATE NOT NULL,
    date_retour_prevue DATE NOT NULL,
    date_retour_effectif DATE,

    -- Statut
    statut VARCHAR(50) NOT NULL DEFAULT 'en_cours',  -- en_cours, retourne, en_retard

    -- Caution
    caution_montant DECIMAL(10, 2),
    caution_rendue BOOLEAN DEFAULT FALSE,

    -- État
    etat_depart VARCHAR(50),
    etat_retour VARCHAR(50),
    problemes_retour TEXT,

    -- Informations
    raison_pret TEXT,
    notes TEXT,
    created_by VARCHAR(100),

    -- Rappels
    rappel_envoye BOOLEAN DEFAULT FALSE,
    date_rappel TIMESTAMP,

    FOREIGN KEY (peripheral_id) REFERENCES peripherals(id) ON DELETE CASCADE
);

CREATE INDEX idx_loans_peripheral ON peripheral_loans(peripheral_id);
CREATE INDEX idx_loans_statut ON peripheral_loans(statut);
CREATE INDEX idx_loans_emprunteur ON peripheral_loans(emprunte_par);
CREATE INDEX idx_loans_retour_prevue ON peripheral_loans(date_retour_prevue);
```

### Table `locations`

```sql
CREATE TABLE locations (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    nom VARCHAR(255) NOT NULL UNIQUE,
    type VARCHAR(50) NOT NULL,  -- piece, placard, tiroir, etagere, meuble, boite
    parent_id INTEGER,  -- Hiérarchie
    description TEXT,
    image_path VARCHAR(500),
    qr_code_path VARCHAR(500),
    ordre_affichage INTEGER DEFAULT 0,
    FOREIGN KEY (parent_id) REFERENCES locations(id) ON DELETE CASCADE
);

CREATE INDEX idx_locations_parent ON locations(parent_id);
CREATE INDEX idx_locations_type ON locations(type);
```

### Table `peripheral_location_history`

```sql
CREATE TABLE peripheral_location_history (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    peripheral_id INTEGER NOT NULL,
    from_location_id INTEGER,
    to_location_id INTEGER,
    from_device_id INTEGER,
    to_device_id INTEGER,
    action VARCHAR(50) NOT NULL,  -- moved, assigned, unassigned, stored
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    notes TEXT,
    user VARCHAR(100),
    FOREIGN KEY (peripheral_id) REFERENCES peripherals(id) ON DELETE CASCADE,
    FOREIGN KEY (from_location_id) REFERENCES locations(id) ON DELETE SET NULL,
    FOREIGN KEY (to_location_id) REFERENCES locations(id) ON DELETE SET NULL
);

CREATE INDEX idx_peripheral_history_pid ON peripheral_location_history(peripheral_id);
```

### Organisation Fichiers Uploads

```
/uploads/peripherals/
├── photos/
│   ├── {hash16}_{peripheral_id}_1.jpg
│   ├── {hash16}_{peripheral_id}_2.png
│   └── ...
├── documents/
│   ├── manuals/
│   │   └── {hash16}_{peripheral_id}_manual.pdf
│   ├── invoices/
│   │   └── {hash16}_{peripheral_id}_invoice.pdf
│   ├── warranties/
│   │   └── {hash16}_{peripheral_id}_warranty.pdf
│   └── datasheets/
│       └── {hash16}_{peripheral_id}_datasheet.pdf
└── thumbnails/
    └── {hash16}_{peripheral_id}_thumb.webp
```

---

## ⚙️ ARCHITECTURE BACKEND

### Configuration (`/backend/app/core/config.py`)

```python
class Settings(BaseSettings):
    # ... config existante ...

    # DATABASE PRINCIPALE (benchmarks)
    DATABASE_URL: str = os.getenv(
        "DATABASE_URL",
        "sqlite:///./backend/data/data.db"
    )

    # DATABASE PÉRIPHÉRIQUES (nouvelle)
    PERIPHERALS_DB_URL: str = os.getenv(
        "PERIPHERALS_DB_URL",
        "sqlite:///./backend/data/peripherals.db"
    )

    # Upload directories
    UPLOAD_DIR: str = "./uploads"
    PERIPHERALS_UPLOAD_DIR: str = "./uploads/peripherals"

    # Module peripherals enabled/disabled
    PERIPHERALS_MODULE_ENABLED: bool = os.getenv(
        "PERIPHERALS_MODULE_ENABLED",
        "true"
    ).lower() == "true"

    # Image compression
    IMAGE_COMPRESSION_ENABLED: bool = True
    IMAGE_COMPRESSION_QUALITY: int = 85
    IMAGE_MAX_WIDTH: int = 1920
    IMAGE_MAX_HEIGHT: int = 1080
    THUMBNAIL_SIZE: int = 300
    THUMBNAIL_QUALITY: int = 75
    THUMBNAIL_FORMAT: str = "webp"
```

### Sessions DB (`/backend/app/db/session.py`)

```python
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session

# DB Principale
engine_main = create_engine(settings.DATABASE_URL, ...)
SessionLocalMain = sessionmaker(bind=engine_main)

# DB Périphériques
engine_peripherals = create_engine(settings.PERIPHERALS_DB_URL, ...)
SessionLocalPeripherals = sessionmaker(bind=engine_peripherals)

# Dependency Injection
def get_db() -> Session:
    """Session DB principale"""
    db = SessionLocalMain()
    try:
        yield db
    finally:
        db.close()

def get_peripherals_db() -> Session:
    """Session DB périphériques"""
    db = SessionLocalPeripherals()
    try:
        yield db
    finally:
        db.close()
```

### Modèles SQLAlchemy

**Base**:
```python
# /backend/app/db/base.py
Base = declarative_base()  # DB principale
BasePeripherals = declarative_base()  # DB périphériques
```

**Modèle Peripheral**:
```python
# /backend/app/models/peripheral.py
from app.db.base import BasePeripherals

class Peripheral(BasePeripherals):
    __tablename__ = "peripherals"
    # ... tous les champs définis plus haut
```

### Schémas Pydantic

```python
# /backend/app/schemas/peripheral.py

class PeripheralBase(BaseModel):
    nom: str
    type_principal: str
    sous_type: Optional[str] = None
    marque: Optional[str] = None
    modele: Optional[str] = None
    # ... tous les champs

class PeripheralCreate(PeripheralBase):
    pass

class PeripheralUpdate(BaseModel):
    nom: Optional[str] = None
    # ... tous les champs optionnels

class PeripheralDetail(PeripheralBase):
    id: int
    date_creation: datetime
    photos: List[PeripheralPhotoSchema]
    documents: List[PeripheralDocumentSchema]
    links: List[PeripheralLinkSchema]
    loan: Optional[PeripheralLoanSchema]
    location: Optional[LocationSchema]

    class Config:
        from_attributes = True

class PeripheralSummary(BaseModel):
    id: int
    nom: str
    type_principal: str
    sous_type: Optional[str]
    marque: Optional[str]
    etat: str
    rating: float
    prix: Optional[float]
    photo_principale: Optional[str]
    en_pret: bool

    class Config:
        from_attributes = True

class PeripheralListResponse(BaseModel):
    items: List[PeripheralSummary]
    total: int
    page: int
    page_size: int
    total_pages: int
```

### Routes API (`/backend/app/api/peripherals.py`)

```python
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File
from sqlalchemy.orm import Session
from app.db.session import get_db, get_peripherals_db
from app.services.peripheral_service import PeripheralService

router = APIRouter(prefix="/api/peripherals", tags=["peripherals"])

# CRUD Périphériques
@router.get("/", response_model=PeripheralListResponse)
async def list_peripherals(
    page: int = 1,
    page_size: int = 50,
    search: Optional[str] = None,
    type_principal: Optional[str] = None,
    marque: Optional[str] = None,
    etat: Optional[str] = None,
    en_pret: Optional[bool] = None,
    is_complete_device: Optional[bool] = None,
    db: Session = Depends(get_peripherals_db)
):
    """Liste périphériques avec pagination et filtres"""
    pass

@router.get("/{peripheral_id}", response_model=PeripheralDetail)
async def get_peripheral(
    peripheral_id: int,
    db_peripherals: Session = Depends(get_peripherals_db),
    db_main: Session = Depends(get_db)
):
    """Détail périphérique avec relations"""
    return PeripheralService.get_peripheral_with_device(
        peripheral_id, db_peripherals, db_main
    )

@router.post("/", response_model=PeripheralDetail)
async def create_peripheral(
    peripheral: PeripheralCreate,
    db: Session = Depends(get_peripherals_db)
):
    """Créer périphérique"""
    pass

@router.put("/{peripheral_id}")
async def update_peripheral(
    peripheral_id: int,
    data: PeripheralUpdate,
    db: Session = Depends(get_peripherals_db)
):
    """Mettre à jour périphérique"""
    pass

@router.delete("/{peripheral_id}")
async def delete_peripheral(
    peripheral_id: int,
    db: Session = Depends(get_peripherals_db)
):
    """Supprimer périphérique"""
    pass

# Photos
@router.post("/{peripheral_id}/photos")
async def upload_photo(
    peripheral_id: int,
    file: UploadFile = File(...),
    compress: bool = True,
    db: Session = Depends(get_peripherals_db)
):
    """Upload photo avec compression optionnelle"""
    pass

@router.get("/{peripheral_id}/photos")
async def get_photos(
    peripheral_id: int,
    db: Session = Depends(get_peripherals_db)
):
    """Liste photos"""
    pass

@router.delete("/photos/{photo_id}")
async def delete_photo(
    photo_id: int,
    db: Session = Depends(get_peripherals_db)
):
    """Supprimer photo"""
    pass

# Documents
@router.post("/{peripheral_id}/documents")
async def upload_document(
    peripheral_id: int,
    file: UploadFile = File(...),
    doc_type: str = "other",
    db: Session = Depends(get_peripherals_db)
):
    """Upload document"""
    pass

@router.get("/{peripheral_id}/documents")
async def get_documents(
    peripheral_id: int,
    db: Session = Depends(get_peripherals_db)
):
    """Liste documents"""
    pass

@router.get("/documents/{doc_id}/download")
async def download_document(doc_id: int, db: Session = Depends(get_peripherals_db)):
    """Télécharger document"""
    pass

# Liens
@router.post("/{peripheral_id}/links")
@router.get("/{peripheral_id}/links")
@router.put("/links/{link_id}")
@router.delete("/links/{link_id}")

# Prêts
@router.post("/{peripheral_id}/loan")
async def create_loan(
    peripheral_id: int,
    loan: LoanCreate,
    db: Session = Depends(get_peripherals_db)
):
    """Créer un prêt"""
    pass

@router.post("/loans/{loan_id}/return")
async def return_loan(
    loan_id: int,
    return_data: LoanReturn,
    db: Session = Depends(get_peripherals_db)
):
    """Enregistrer retour"""
    pass

@router.get("/loans/active")
@router.get("/loans/overdue")
@router.post("/loans/{loan_id}/reminder")

# Localisation
@router.post("/{peripheral_id}/assign")
@router.post("/{peripheral_id}/unassign")
@router.get("/{peripheral_id}/history")

# Appareils complets
@router.post("/{peripheral_id}/link-device")
@router.delete("/{peripheral_id}/unlink-device")
@router.get("/{peripheral_id}/benchmarks")

# Recherche avancée
@router.get("/search")
async def advanced_search(
    q: str,
    filters: dict,
    db: Session = Depends(get_peripherals_db)
):
    """Recherche multi-critères"""
    pass

# Config
@router.get("/types")
async def get_peripheral_types():
    """Liste types depuis YAML"""
    pass
```

### Service Layer (`/backend/app/services/peripheral_service.py`)

```python
class PeripheralService:
    @staticmethod
    def get_peripheral_with_device(
        peripheral_id: int,
        db_peripherals: Session,
        db_main: Session
    ):
        """Récupère périphérique avec device lié"""
        peripheral = db_peripherals.query(Peripheral).get(peripheral_id)

        result = {
            "peripheral": peripheral,
            "linked_device": None,
            "benchmarks": []
        }

        if peripheral.linked_device_id:
            device = db_main.query(Device).get(peripheral.linked_device_id)
            result["linked_device"] = device
            if device:
                result["benchmarks"] = device.benchmarks

        return result

    @staticmethod
    def compress_image(file_path: str, quality: int = 85):
        """Compresse une image"""
        from PIL import Image
        img = Image.open(file_path)
        # ... compression logic
        pass

    @staticmethod
    def generate_thumbnail(file_path: str, size: int = 300):
        """Génère thumbnail"""
        pass
```

### Main App (`/backend/app/main.py`)

```python
from app.api import peripherals, locations, loans

if settings.PERIPHERALS_MODULE_ENABLED:
    app.include_router(peripherals.router)
    app.include_router(locations.router)
    app.include_router(loans.router)
```

---

## 🎨 ARCHITECTURE FRONTEND

### Pages HTML

```
/frontend/
├── peripherals.html        # Page principale périphériques
├── peripheral_detail.html  # Détail périphérique (optionnel)
├── locations.html          # Gestion emplacements
├── loans.html              # Gestion prêts
└── (pages existantes)
```

### JavaScript

```
/frontend/js/
├── api.js                  # Extension BenchAPI.Peripherals.*
├── peripherals.js          # Logique page principale
├── peripheral_detail.js    # Logique détail
├── locations.js            # Gestion emplacements
├── loans.js                # Gestion prêts
├── components/
│   ├── PhotoGallery.js     # Galerie photos
│   ├── DocumentList.js     # Liste documents
│   ├── PeripheralFilters.js # Filtres avancés
│   ├── LocationSelector.js  # Sélecteur arborescence
│   ├── RatingStars.js      # Système étoiles
│   ├── TypeManager.js      # Gestion types YAML
│   ├── StockManager.js     # Gestion stock
│   └── ImageUploader.js    # Upload images
└── utils.js                # (existant, étendre si besoin)
```

### Extension API Client (`/frontend/js/api.js`)

```javascript
window.BenchAPI = window.BenchAPI || {};

window.BenchAPI.Peripherals = {
    // CRUD
    getPeripherals: async (page = 1, filters = {}) => {
        const params = new URLSearchParams({ page, ...filters });
        return await fetch(`${API_URL}/peripherals?${params}`).then(r => r.json());
    },

    getPeripheral: async (id) => {
        return await fetch(`${API_URL}/peripherals/${id}`).then(r => r.json());
    },

    createPeripheral: async (data) => {
        return await fetch(`${API_URL}/peripherals`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(data)
        }).then(r => r.json());
    },

    updatePeripheral: async (id, data) => {
        return await fetch(`${API_URL}/peripherals/${id}`, {
            method: 'PUT',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(data)
        }).then(r => r.json());
    },

    deletePeripheral: async (id) => {
        return await fetch(`${API_URL}/peripherals/${id}`, {
            method: 'DELETE'
        });
    },

    // Photos
    uploadPhoto: async (peripheralId, file, compress = true) => {
        const formData = new FormData();
        formData.append('file', file);
        formData.append('compress', compress);

        return await fetch(`${API_URL}/peripherals/${peripheralId}/photos`, {
            method: 'POST',
            body: formData
        }).then(r => r.json());
    },

    getPhotos: async (peripheralId) => {
        return await fetch(`${API_URL}/peripherals/${peripheralId}/photos`)
            .then(r => r.json());
    },

    // Documents
    uploadDocument: async (peripheralId, file, docType) => {
        const formData = new FormData();
        formData.append('file', file);
        formData.append('doc_type', docType);

        return await fetch(`${API_URL}/peripherals/${peripheralId}/documents`, {
            method: 'POST',
            body: formData
        }).then(r => r.json());
    },

    // Liens
    addLink: async (peripheralId, link) => {
        return await fetch(`${API_URL}/peripherals/${peripheralId}/links`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(link)
        }).then(r => r.json());
    },

    // Prêts
    createLoan: async (peripheralId, loanData) => {
        return await fetch(`${API_URL}/peripherals/${peripheralId}/loan`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(loanData)
        }).then(r => r.json());
    },

    returnLoan: async (loanId, returnData) => {
        return await fetch(`${API_URL}/peripherals/loans/${loanId}/return`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(returnData)
        }).then(r => r.json());
    },

    getActiveLoans: async () => {
        return await fetch(`${API_URL}/peripherals/loans/active`)
            .then(r => r.json());
    },

    // Benchmarks (appareils complets)
    linkDevice: async (peripheralId, deviceId) => {
        return await fetch(`${API_URL}/peripherals/${peripheralId}/link-device`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ device_id: deviceId })
        }).then(r => r.json());
    },

    getBenchmarks: async (peripheralId) => {
        return await fetch(`${API_URL}/peripherals/${peripheralId}/benchmarks`)
            .then(r => r.json());
    },

    // Recherche
    search: async (query, filters = {}) => {
        const params = new URLSearchParams({ q: query, ...filters });
        return await fetch(`${API_URL}/peripherals/search?${params}`)
            .then(r => r.json());
    },

    // Config
    getTypes: async () => {
        return await fetch(`${API_URL}/peripherals/types`)
            .then(r => r.json());
    }
};

// Locations
window.BenchAPI.Locations = {
    getLocations: async () => {
        return await fetch(`${API_URL}/locations`).then(r => r.json());
    },

    getLocationTree: async () => {
        return await fetch(`${API_URL}/locations/tree`).then(r => r.json());
    },

    createLocation: async (data) => {
        return await fetch(`${API_URL}/locations`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(data)
        }).then(r => r.json());
    }
};
```

### Composants Réutilisables

#### PhotoGallery.js
```javascript
class PhotoGallery {
    constructor(containerId, peripheralId) {
        this.container = document.getElementById(containerId);
        this.peripheralId = peripheralId;
        this.photos = [];
    }

    async load() {
        this.photos = await BenchAPI.Peripherals.getPhotos(this.peripheralId);
        this.render();
    }

    render() {
        // Grid layout avec lightbox
        this.container.innerHTML = `
            <div class="photo-grid">
                ${this.photos.map(p => `
                    <div class="photo-item" data-id="${p.id}">
                        <img src="${p.thumbnail_path || p.stored_path}"
                             alt="${p.description}"
                             onclick="PhotoGallery.openLightbox('${p.stored_path}')">
                        ${p.is_primary ? '<span class="badge-primary">Principal</span>' : ''}
                        <button onclick="PhotoGallery.delete(${p.id})">×</button>
                    </div>
                `).join('')}
                <div class="photo-upload">
                    <input type="file" id="upload-photo" accept="image/*" multiple>
                    <label for="upload-photo">+ Ajouter photos</label>
                </div>
            </div>
        `;
    }

    static openLightbox(imagePath) {
        // Lightbox overlay
    }
}
```

#### RatingStars.js
```javascript
class RatingStars {
    constructor(containerId, currentRating = 0, editable = true) {
        this.container = document.getElementById(containerId);
        this.rating = currentRating;
        this.editable = editable;
        this.render();
    }

    render() {
        const stars = [];
        for (let i = 1; i <= 5; i++) {
            const filled = i <= Math.round(this.rating);
            stars.push(`
                <span class="star ${filled ? 'filled' : ''}"
                      data-rating="${i}"
                      ${this.editable ? `onclick="this.setRating(${i})"` : ''}>
                    ★
                </span>
            `);
        }

        this.container.innerHTML = `
            <div class="rating-stars">
                ${stars.join('')}
                <span class="rating-value">${this.rating.toFixed(1)}/5</span>
            </div>
        `;
    }

    setRating(value) {
        this.rating = value;
        this.render();
        // Trigger event
        this.container.dispatchEvent(new CustomEvent('ratingChange', {
            detail: { rating: value }
        }));
    }
}
```

### CSS Additions (`/frontend/css/components.css`)

```css
/* Périphériques */
.peripheral-card {
    background: var(--card-bg);
    border-radius: 8px;
    padding: 1rem;
    margin-bottom: 1rem;
    transition: transform 0.2s;
}

.peripheral-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}

.peripheral-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.peripheral-type-badge {
    background: var(--color-info);
    color: #000;
    padding: 0.25rem 0.5rem;
    border-radius: 4px;
    font-size: 0.875rem;
}

.peripheral-status {
    display: flex;
    gap: 0.5rem;
}

.status-badge {
    padding: 0.25rem 0.5rem;
    border-radius: 4px;
    font-size: 0.75rem;
}

.status-neuf { background: #a6e22e; color: #000; }
.status-bon { background: #66d9ef; color: #000; }
.status-use { background: #fd971f; color: #000; }
.status-defectueux { background: #f92672; color: #fff; }

/* Rating Stars */
.rating-stars {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.star {
    font-size: 1.5rem;
    color: #666;
    cursor: pointer;
    transition: color 0.2s;
}

.star.filled {
    color: #ffd700;
}

.star:hover {
    color: #ffd700;
}

/* Photo Gallery */
.photo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 1rem;
}

.photo-item {
    position: relative;
    aspect-ratio: 1;
    border-radius: 8px;
    overflow: hidden;
    cursor: pointer;
}

.photo-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.photo-upload {
    border: 2px dashed var(--border-color);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: border-color 0.2s;
}

.photo-upload:hover {
    border-color: var(--color-info);
}

/* Location Tree */
.location-tree {
    list-style: none;
    padding-left: 0;
}

.location-tree li {
    padding-left: 1.5rem;
    position: relative;
}

.location-tree li:before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--border-color);
}

.location-item {
    padding: 0.5rem;
    cursor: pointer;
    border-radius: 4px;
}

.location-item:hover {
    background: rgba(255,255,255,0.1);
}

.location-item.selected {
    background: var(--color-info);
    color: #000;
}
```

---

## ⚙️ FONCTIONNALITÉS PRINCIPALES

### 1. GESTION STOCK

- **Quantités**: Totale, Disponible, Seuil d'alerte
- **Alertes**: Notification si stock bas
- **Mouvements**: Tracking ajouts/retraits
- **Emplacement**: Stockage physique

### 2. COMPRESSION D'IMAGES

**Configuration** (`image_processing.yaml`):
```yaml
compression:
  enabled: true
  original:
    keep: true
    path: "originals/"
  optimized:
    format: "webp"
    quality: 85
    max_width: 1920
    max_height: 1080
  thumbnail:
    enabled: true
    format: "webp"
    quality: 75
    width: 300
    height: 300
    fit: "cover"
  max_upload_size_mb: 10
```

### 3. RATING SYSTÈME (0-5 ÉTOILES)

- Interface clickable
- Affichage visuel (★★★★☆)
- Stockage float (précision 0.1)
- Filtrage par rating

### 4. RECHERCHE AVANCÉE

**Critères de recherche**:
- Texte libre (nom, marque, modèle)
- Type principal / Sous-type
- Marque
- État (Neuf, Bon, Usagé, Défectueux)
- Prix (range)
- Date d'achat (range)
- Tags
- Localisation
- En prêt / Disponible
- Rating minimum
- Vendor ID / Product ID (Linux)

**Résultats**:
- Temps réel (<200ms)
- Pagination
- Tri multi-colonnes
- Export CSV/JSON

### 5. IMPORT/EXPORT

**Export**:
- CSV (Excel compatible)
- JSON (backup complet)
- PDF (fiche périphérique)
- Labels (impression étiquettes)

**Import**:
- CSV en masse
- Auto-détection colonnes
- Validation données
- Preview avant import

### 6. QR CODES

- Génération automatique par périphérique
- Lien vers fiche web
- Impression étiquettes
- Scan mobile → accès direct

---

## 📍 SYSTÈME DE LOCALISATION

### Hiérarchie

```
📍 Racine
├── 🏠 Pièce (piece)
│   ├── 🗄️ Placard (placard)
│   │   ├── 🗃️ Tiroir (tiroir)
│   │   └── 📦 Étagère (etagere)
│   └── 🖥️ Meuble (meuble)
└── 🏠 Pièce 2
```

### Logique

**Si périphérique assigné** à un device:
- `location_auto = TRUE` → suit le device
- Localisation = celle du device

**Si périphérique stocké**:
- `location_auto = FALSE`
- `location_id` → emplacement de stockage précis
- `location_details` → précisions (ex: "2ème rangée, sachet antistatique")

### Fonctionnalités

- **Arborescence interactive** (TreeView)
- **Breadcrumb** (Maison > Bureau > Placard A > Tiroir 2)
- **Historique mouvements** (table `peripheral_location_history`)
- **QR code par emplacement** (scan → voir contenu)
- **Photos emplacements** (aide visuelle)
- **Rapport non-localisés** (alerte périphériques sans emplacement)

### Configuration YAML (`locations.yaml`)

```yaml
locations:
  - nom: "Maison"
    type: "root"
    children:
      - nom: "Bureau"
        type: "piece"
        children:
          - nom: "Bureau principal"
            type: "meuble"
          - nom: "Placard A"
            type: "placard"
            children:
              - nom: "Tiroir 1"
                type: "tiroir"
                description: "Câbles et adaptateurs"
              - nom: "Tiroir 2"
                type: "tiroir"
                description: "Périphériques USB"
```

---

## 🤝 SYSTÈME DE PRÊT

### Workflow

1. **Créer prêt**
   - Emprunteur (nom, email, tél)
   - Dates (prêt, retour prévu)
   - Caution (montant, type)
   - État départ + photos
   - Raison du prêt

2. **Suivi automatique**
   - Rappel 2j avant échéance
   - Rappel à l'échéance
   - Rappel retard (tous les 2j)
   - Statut: `en_cours`, `en_retard`

3. **Retour**
   - Date retour effectif
   - État au retour + photos
   - Problèmes constatés
   - Caution rendue/retenue

### Notifications (CRON)

**Tâche quotidienne** (`check_and_send_reminders()`):
- Vérifier prêts à échéance J-2
- Vérifier prêts à échéance J
- Vérifier prêts en retard
- Envoyer emails automatiques

**Configuration** (`notifications.yaml`):
```yaml
loan_notifications:
  enabled: true
  rappels:
    avant_echeance:
      enabled: true
      jours_avant: 2
    retard:
      enabled: true
      frequence_jours: 2
      max_rappels: 3
  email:
    enabled: true
    smtp_server: "smtp.gmail.com"
    from_email: "inventory@example.com"
  templates:
    rappel_avant:
      sujet: "Rappel: Retour de {peripheral_name} prévu le {date_retour}"
      corps: |
        Bonjour {emprunteur_name},

        Ce message pour vous rappeler que le périphérique suivant
        doit être retourné le {date_retour} :

        • {peripheral_name}
        • Caution: {caution_montant}€

        Merci.
```

### Statistiques

- Total prêts en cours
- Valeur totale prêtée
- Prêts en retard
- Cautions en attente
- Top emprunteurs
- Score fiabilité emprunteur
- Blacklist (optionnel)

---

## 💻 APPAREILS COMPLETS

### Concept

Les **appareils complets** (Desktop, Laptop, Tablet, Smartphone, Serveur, Console) sont des périphériques spéciaux qui:

1. **Peuvent avoir des benchmarks** (`linked_device_id` → `devices.id`)
2. **Peuvent avoir des périphériques attachés** (souris, clavier, écran)
3. **Ont des specs complètes** (CPU, RAM, GPU, etc.)
4. **Peuvent être prêtés** comme tout périphérique

### Lien avec Benchmarks

```
Peripheral (Laptop Dell XPS 15)
  ├─ is_complete_device = TRUE
  ├─ device_type = "laptop"
  ├─ linked_device_id = 42 → devices.id (dans data.db)
  │
  └─ → Accès aux benchmarks du device 42
      ├─ Historique benchmarks
      ├─ Dernier score global
      ├─ Évolution performances
      └─ Hardware snapshots
```

### Interface

**Onglet "Benchmarks"** dans fiche périphérique:
- Dernier benchmark (score global, détails)
- Historique (tableau, graphique évolution)
- Lien vers page device detail
- Bouton "Nouveau benchmark"

**Sync automatique specs**:
- Après chaque benchmark
- Mise à jour auto des specs (CPU, RAM, GPU, etc.)
- Depuis `hardware_snapshot`

### Périphériques Attachés

**Exemple Desktop Gaming**:
```
Desktop Gaming PC
├─ Linked device → Benchmarks
├─ Périphériques attachés:
│  ├─ Souris Logitech G Pro
│  ├─ Clavier Corsair K95
│  ├─ Casque SteelSeries
│  └─ Écran ASUS ROG 27"
└─ Localisation: Bureau > Bureau gaming
```

**Gestion**:
- Bouton "Attacher périphérique"
- Liste avec possibilité détacher
- Tracking historique

---

## 📝 CONFIGURATION YAML

### Fichiers de Configuration

```
/backend/config/
├── peripheral_types.yaml       # Types & catégories
├── locations.yaml              # Emplacements
├── image_processing.yaml       # Compression images
└── notifications.yaml          # Alertes & emails
```

### peripheral_types.yaml

Structure extensible pour définir les types de périphériques:

```yaml
categories:
  - id: connectivity
    nom: "Connectivité"
    icon: "plug"
    types:
      - id: usb_storage
        nom: "Stockage USB"
        icon: "usb-drive"
        champs_specifiques:
          - capacite_go:
              type: "number"
              required: true
              label: "Capacité (Go)"
          - usb_version:
              type: "select"
              options: ["2.0", "3.0", "3.1", "3.2"]
              label: "Version USB"
          - vitesse_lecture_mbs:
              type: "number"
              label: "Vitesse lecture (MB/s)"

  - id: cables
    nom: "Câbles"
    icon: "cable"
    types:
      - id: cable_hdmi
        nom: "Câble HDMI"
        champs_specifiques:
          - longueur_m:
              type: "number"
              required: true
              label: "Longueur (m)"
          - version_hdmi:
              type: "select"
              options: ["1.4", "2.0", "2.1"]
          - certification:
              type: "select"
              options: ["Standard", "Premium", "Ultra"]

  - id: complete_devices
    nom: "Appareils Complets"
    icon: "devices"
    is_special: true
    types:
      - id: desktop
        nom: "PC de Bureau (Desktop)"
        is_complete_device: true
        can_have_benchmarks: true
        champs_specifiques:
          - systeme_exploitation:
              type: "select"
              options: ["Windows 11", "Windows 10", "Linux", "macOS"]
          - cpu_modele:
              type: "text"
              placeholder: "ex: Core i7-12700K"
          # ... (voir section Types de Périphériques pour specs complètes)

      - id: console_gaming
        nom: "Console de Jeu"
        icon: "gamepad"
        is_complete_device: true
        champs_specifiques:
          - type_console:
              type: "select"
              options: ["Salon", "Portable", "Hybrid"]
          - marque:
              type: "select"
              options: ["PlayStation", "Xbox", "Nintendo", "Steam", "Autre"]
          # ... (voir section Types de Périphériques pour specs complètes)

# Types personnalisés ajoutés dynamiquement depuis l'interface
custom_types: []
```

### Gestion Dynamique des Types

**Interface admin** (`TypeManager.js`):
- Modal gestion types
- Ajout/édition/suppression catégories
- Ajout/édition/suppression types
- Configuration champs spécifiques
- Sauvegarde YAML automatique

**Avantages**:
- ✅ Pas besoin modifier code pour nouveau type
- ✅ Interface [+] dans formulaires
- ✅ Persistance YAML
- ✅ Sync base de données automatique

---

## 📐 PLAN DE DÉPLOIEMENT

### PHASE 1: Backend - Base de Données et API (Semaine 1-2)

#### 1.1 Configuration et Sessions
- [x] Mettre à jour `/backend/app/core/config.py`
  - Ajouter `PERIPHERALS_DB_URL`
  - Ajouter paramètres compression images
  - Ajouter `PERIPHERALS_MODULE_ENABLED`
- [x] Créer `/backend/app/db/session.py` (deux sessions)
  - `get_db()` → DB principale
  - `get_peripherals_db()` → DB périphériques
- [x] Créer `BasePeripherals` dans `/backend/app/db/base.py`

#### 1.2 Modèles SQLAlchemy
- [x] Créer `/backend/app/models/peripheral.py`
  - `Peripheral` (table principale)
  - `PeripheralPhoto`
  - `PeripheralDocument`
  - `PeripheralLink`
  - `PeripheralLoan`
- [x] Créer `/backend/app/models/location.py`
  - `Location` (hiérarchie emplacements)
- [x] Créer `/backend/app/models/peripheral_history.py`
  - `PeripheralLocationHistory`

#### 1.3 Schémas Pydantic
- [x] Créer `/backend/app/schemas/peripheral.py`
  - `PeripheralBase`, `PeripheralCreate`, `PeripheralUpdate`
  - `PeripheralDetail`, `PeripheralSummary`, `PeripheralListResponse`
- [x] Créer `/backend/app/schemas/location.py`
- [x] Créer `/backend/app/schemas/loan.py`

#### 1.4 Services
- [x] Créer `/backend/app/services/peripheral_service.py`
  - `get_peripheral_with_device()` (cross-DB)
  - `link_peripheral_to_device()`
  - `compress_image()`, `generate_thumbnail()`
  - `sync_peripheral_from_benchmark()`
- [x] Créer `/backend/app/services/location_service.py`
  - `get_location_tree()` (hiérarchie)
  - `get_full_location_path()`
- [x] Créer `/backend/app/services/loan_service.py`
  - `check_and_send_reminders()` (CRON)
  - `send_loan_reminder()`

#### 1.5 Routes API
- [x] Créer `/backend/app/api/peripherals.py` (20+ endpoints)
  - CRUD périphériques
  - Photos, Documents, Liens
  - Prêts, Localisation, Historique
  - Recherche avancée
  - Appareils complets (link device, benchmarks)
- [x] Créer `/backend/app/api/locations.py`
  - CRUD emplacements
  - Arborescence
  - QR codes
- [x] Créer `/backend/app/api/loans.py`
  - CRUD prêts
  - Retours
  - Rappels
  - Statistiques

#### 1.6 Configuration YAML
- [x] Créer `/backend/config/peripheral_types.yaml`
  - Définir toutes les catégories
  - Définir tous les types (USB, Câbles, Desktop, Console, etc.)
  - Champs spécifiques par type
- [x] Créer `/backend/config/locations.yaml`
  - Structure initiale emplacements
- [x] Créer `/backend/config/image_processing.yaml`
  - Paramètres compression
- [x] Créer `/backend/config/notifications.yaml`
  - Templates emails
  - Configuration SMTP

#### 1.7 Utilitaires
- [x] Créer `/backend/app/utils/yaml_loader.py`
  - Charger/sauvegarder YAML
  - Parser configurations
- [x] Créer `/backend/app/utils/image_processor.py`
  - Compression images (Pillow)
  - Génération thumbnails
  - Validation formats
- [x] Créer `/backend/app/utils/qr_generator.py`
  - Génération QR codes
- [x] Créer `/backend/app/tasks/daily_loan_reminders.py`
  - Tâche CRON quotidienne

#### 1.8 Initialisation
- [x] Mettre à jour `/backend/app/db/init_db.py`
  - Créer tables `peripherals.db`
  - Charger YAML initial
  - Créer emplacements par défaut
- [x] Mettre à jour `/backend/app/main.py`
  - Include routers peripherals
  - Check `PERIPHERALS_MODULE_ENABLED`

---

### PHASE 2: Frontend - Interface Utilisateur (Semaine 3-4)

#### 2.1 Pages HTML
- [x] Créer `/frontend/peripherals.html`
  - Layout deux panneaux
  - Liste + Détails/Formulaire
  - Navigation onglets
- [x] Créer `/frontend/peripheral_detail.html` (optionnel)
  - Vue complète périphérique
  - Onglets: Infos, Photos, Docs, Liens, Historique, Benchmarks
- [x] Créer `/frontend/locations.html`
  - Gestion emplacements
  - Arborescence interactive
- [x] Créer `/frontend/loans.html`
  - Liste prêts en cours
  - Historique
  - Statistiques

#### 2.2 JavaScript - API Client
- [x] Étendre `/frontend/js/api.js`
  - `BenchAPI.Peripherals.*` (CRUD, photos, docs, liens, prêts)
  - `BenchAPI.Locations.*`
  - `BenchAPI.Loans.*`

#### 2.3 JavaScript - Logique Pages
- [x] Créer `/frontend/js/peripherals.js`
  - Initialisation page
  - Chargement liste
  - Recherche/filtres temps réel
  - Formulaire dynamique (selon type)
  - Upload médias
- [x] Créer `/frontend/js/peripheral_detail.js`
  - Gestion onglets
  - Affichage benchmarks
  - Galerie photos
- [x] Créer `/frontend/js/locations.js`
  - TreeView emplacements
  - CRUD emplacements
  - QR codes
- [x] Créer `/frontend/js/loans.js`
  - Formulaire prêt
  - Formulaire retour
  - Liste prêts
  - Rappels

#### 2.4 Composants Réutilisables
- [x] Créer `/frontend/js/components/PhotoGallery.js`
  - Grid photos
  - Upload drag & drop
  - Lightbox
  - Compression option
- [x] Créer `/frontend/js/components/DocumentList.js`
  - Liste documents avec icônes
  - Upload
  - Preview PDF
- [x] Créer `/frontend/js/components/PeripheralFilters.js`
  - Filtres latéraux
  - Recherche avancée
  - Tags
- [x] Créer `/frontend/js/components/LocationSelector.js`
  - TreeView sélection
  - Breadcrumb
- [x] Créer `/frontend/js/components/RatingStars.js`
  - Système étoiles clickable
  - Affichage/édition
- [x] Créer `/frontend/js/components/TypeManager.js`
  - Modal gestion types YAML
  - CRUD types/catégories
- [x] Créer `/frontend/js/components/StockManager.js`
  - Gestion quantités
  - Alertes stock
- [x] Créer `/frontend/js/components/ImageUploader.js`
  - Upload multiple
  - Preview
  - Crop/rotate basique

#### 2.5 CSS
- [x] Étendre `/frontend/css/components.css`
  - Styles périphériques
  - Cards
  - Badges (type, état, prêt)
  - Photo gallery
  - Rating stars
  - Location tree
  - Modals
  - Forms dynamiques

#### 2.6 Navigation
- [x] Mettre à jour TOUTES les pages HTML
  - Ajouter lien "Périphériques" dans nav
  - Ordre: Dashboard | Devices | **Périphériques** | Prêts | Emplacements | Settings

---

### PHASE 3: Fonctionnalités Avancées (Semaine 5)

#### 3.1 Recherche Avancée
- [x] Interface recherche multi-critères
- [x] Résultats temps réel
- [x] Filtres combinables
- [x] Tri multi-colonnes

#### 3.2 Import/Export
- [x] Export CSV/JSON
- [x] Import CSV en masse
- [x] Export PDF fiche périphérique
- [x] Impression étiquettes

#### 3.3 QR Codes
- [x] Génération QR par périphérique
- [x] Génération QR par emplacement
- [x] Page scan → fiche
- [x] Impression batch

#### 3.4 Statistiques
- [x] Dashboard périphériques
  - Total par type (Pie chart)
  - Valeur inventaire
  - Top marques (Bar chart)
  - État (Donut chart)
- [x] Dashboard prêts
  - Prêts en cours
  - Valeur prêtée
  - Alertes retards
- [x] Dashboard emplacements
  - Inventaire par emplacement
  - Valeur par pièce

---

### PHASE 4: Intégration et Optimisation (Semaine 6)

#### 4.1 Intégration Devices
- [x] Dans `device_detail.html`, ajouter onglet "Périphériques connectés"
- [x] Bouton "Créer fiche périphérique" depuis device
- [x] Auto-link lors création
- [x] Sync specs après benchmark

#### 4.2 Détection Automatique
- [x] Parser `lsusb` output
- [x] Parser `lspci` output
- [x] Suggérer ajout auto nouveaux périphériques
- [x] Pré-remplir vendor/product ID

#### 4.3 Notifications
- [x] Setup CRON pour rappels prêts
- [x] Templates emails
- [x] Configuration SMTP
- [x] Alertes stock bas
- [x] Alertes garantie expirée

#### 4.4 Performance
- [x] Optimisation queries SQL (eager loading)
- [x] Index appropriés
- [x] Compression images
- [x] Cache recherches fréquentes
- [x] Pagination efficace

#### 4.5 Sécurité
- [x] Validation uploads (MIME, taille)
- [x] Sanitization noms fichiers
- [x] Protection CSRF
- [x] Rate limiting API

---

### PHASE 5: Documentation et Tests (Semaine 7)

#### 5.1 Documentation
- [x] `/docs/PERIPHERALS_USER_GUIDE.md`
  - Guide utilisateur
  - Exemples d'utilisation
  - FAQ
- [x] `/docs/PERIPHERALS_API.md`
  - Documentation API (Swagger)
  - Exemples requêtes
- [x] `/docs/PERIPHERALS_ADMIN.md`
  - Configuration YAML
  - Gestion types
  - Maintenance

#### 5.2 Exemples et Fixtures
- [x] Script seed données test
- [x] Templates JSON par type
- [x] Données d'exemple

#### 5.3 Tests
- [x] Tests unitaires backend (pytest)
  - Models
  - Services
  - Utils
- [x] Tests intégration API
  - Endpoints CRUD
  - Cross-DB queries
- [x] Tests frontend
  - Validation formulaires
  - Composants

---

## 🚀 PROMPT DE DÉVELOPPEMENT

### Contexte du Projet

Vous êtes chargé d'implémenter le **Module Périphériques** pour l'application **Linux BenchTools** existante. Cette application permet actuellement de benchmarker des machines Linux et de stocker leurs résultats.

### Architecture Existante

**Backend**:
- FastAPI + SQLAlchemy
- Base de données: SQLite `data.db`
- Structure: `/backend/app/` avec models/, schemas/, api/, core/
- Authentification par token

**Frontend**:
- Vanilla JavaScript (pas de framework)
- Thème: Monokai dark avec CSS variables
- Layout: Two-panel design
- Navigation: Dashboard, Devices, Settings

### Objectif du Module

Créer un **système complet de gestion d'inventaire de périphériques** avec:

1. **Catalogue exhaustif** de périphériques (USB, Bluetooth, Câbles, Visserie, Appareils complets, Consoles)
2. **Localisation physique** (Pièces → Placards → Tiroirs)
3. **Gestion de prêts** (avec rappels automatiques)
4. **Intégration benchmarks** (pour Desktop, Laptop, Serveur)
5. **Fonctionnalités avancées** (Stock, Rating, Photos, Documents, QR codes)

### Décisions Architecturales Clés

#### 1. Base de Données Séparée

**IMPORTANT**: Créer une **nouvelle base de données** `peripherals.db` séparée de `data.db`.

**Pourquoi**:
- Isolation des données
- Performance (pas de contention)
- Backups indépendants
- Module activable/désactivable

**Lien entre DB**:
- `peripherals.linked_device_id` → référence logique vers `devices.id` (pas FK SQL)
- Gérer relations manuellement côté application via service layer

#### 2. Configuration YAML Dynamique

Les **types de périphériques** sont définis en YAML, modifiables depuis l'interface:

```yaml
# /backend/config/peripheral_types.yaml
categories:
  - id: cables
    nom: "Câbles"
    types:
      - id: cable_hdmi
        nom: "Câble HDMI"
        champs_specifiques:
          - longueur_m: { type: "number", required: true }
          - version_hdmi: { type: "select", options: ["1.4", "2.0", "2.1"] }
```

**Avantages**:
- Pas de modification code pour nouveau type
- Interface admin [+] pour ajouter types
- Persistance automatique

#### 3. Appareils Complets avec Benchmarks

Les **Desktop, Laptop, Serveur, Console** sont des périphériques spéciaux:
- `is_complete_device = TRUE`
- `linked_device_id` → lien vers `devices.id` pour benchmarks
- Affichage historique benchmarks intégré
- Sync automatique specs depuis `hardware_snapshot`

#### 4. Système de Localisation Hiérarchique

Arborescence emplacements:
```
Maison
├─ Bureau (piece)
│  ├─ Placard A (placard)
│  │  ├─ Tiroir 1 (tiroir)
│  │  └─ Tiroir 2 (tiroir)
│  └─ Bureau principal (meuble)
└─ Salon (piece)
```

**Logique**:
- Si `device_id != NULL` et `location_auto = TRUE` → localisation = celle du device
- Sinon → `location_id` (emplacement de stockage)

#### 5. Compression d'Images Automatique

Configuration dans `image_processing.yaml`:
- Format optimisé: WebP
- Qualité: 85%
- Thumbnails: 300x300px
- Conserver original optionnel

### Structure des Données

#### Table Principale: `peripherals`

**Champs globaux** (tous périphériques):
- Identification (nom, type, marque, modèle, S/N)
- Achat (boutique, date, prix, garantie)
- Évaluation (rating 0-5 étoiles)
- Stock (quantité totale, disponible, seuil alerte)
- Métadonnées (dates, état, tags, notes)
- Linux (device_path, vendor_id, product_id, driver)
- Installation (auto, driver requis, problèmes connus)
- Connectivité (interface, consommation)
- Localisation (location_id, location_auto)
- Prêt (en_pret, pret_actuel_id, prete_a)
- Appareil complet (is_complete_device, linked_device_id)
- **Données spécifiques** (JSON flexible par type)

**Relations**:
- `peripheral_photos` (1:N, photos avec principale)
- `peripheral_documents` (1:N, manuels/factures/datasheets)
- `peripheral_links` (1:N, liens fabricant/support/drivers)
- `peripheral_loans` (1:N, historique prêts)
- `peripheral_location_history` (1:N, mouvements)
- `locations` (hiérarchie N niveaux)

### Implémentation Backend

#### Sessions DB

```python
# /backend/app/db/session.py
engine_main = create_engine(settings.DATABASE_URL)  # data.db
engine_peripherals = create_engine(settings.PERIPHERALS_DB_URL)  # peripherals.db

def get_db() -> Session:
    """Session DB principale (benchmarks)"""
    ...

def get_peripherals_db() -> Session:
    """Session DB périphériques"""
    ...
```

#### Modèles

```python
# /backend/app/models/peripheral.py
from app.db.base import BasePeripherals  # ← Pas Base !

class Peripheral(BasePeripherals):
    __tablename__ = "peripherals"
    # ... champs

    # PAS de relationship SQLAlchemy vers data.db
    # Gérer manuellement via service layer
```

#### Service Layer (Cross-DB)

```python
# /backend/app/services/peripheral_service.py
class PeripheralService:
    @staticmethod
    def get_peripheral_with_device(
        peripheral_id: int,
        db_peripherals: Session,
        db_main: Session
    ):
        """Récupère périphérique + device lié (cross-DB)"""
        peripheral = db_peripherals.query(Peripheral).get(peripheral_id)

        if peripheral.linked_device_id:
            device = db_main.query(Device).get(peripheral.linked_device_id)
            benchmarks = device.benchmarks if device else []
            return {
                "peripheral": peripheral,
                "linked_device": device,
                "benchmarks": benchmarks
            }

        return {"peripheral": peripheral}
```

#### Routes API (Deux Sessions)

```python
# /backend/app/api/peripherals.py
@router.get("/{peripheral_id}")
async def get_peripheral(
    peripheral_id: int,
    db_peripherals: Session = Depends(get_peripherals_db),  # ← DB périphériques
    db_main: Session = Depends(get_db)                       # ← DB principale
):
    """Détail avec benchmarks si appareil complet"""
    return PeripheralService.get_peripheral_with_device(
        peripheral_id, db_peripherals, db_main
    )
```

### Implémentation Frontend

#### Structure

```
/frontend/
├── peripherals.html         # Page principale (two-panel)
├── peripheral_detail.html   # Détail (optionnel)
├── locations.html           # Gestion emplacements
├── loans.html               # Gestion prêts
├── js/
│   ├── api.js               # Extension BenchAPI.Peripherals.*
│   ├── peripherals.js       # Logique page
│   ├── components/
│   │   ├── PhotoGallery.js  # Galerie + upload
│   │   ├── RatingStars.js   # Système étoiles
│   │   ├── LocationSelector.js  # TreeView
│   │   └── TypeManager.js   # Gestion types YAML
│   └── ...
└── css/
    └── components.css       # Styles périphériques
```

#### API Client Extension

```javascript
// /frontend/js/api.js
window.BenchAPI.Peripherals = {
    getPeripherals: async (page, filters) => { /* ... */ },
    getPeripheral: async (id) => { /* ... */ },
    createPeripheral: async (data) => { /* ... */ },
    uploadPhoto: async (peripheralId, file, compress = true) => { /* ... */ },
    createLoan: async (peripheralId, loanData) => { /* ... */ },
    linkDevice: async (peripheralId, deviceId) => { /* ... */ },
    getBenchmarks: async (peripheralId) => { /* ... */ },
    // ... 20+ méthodes
};
```

#### Composants Réutilisables

**PhotoGallery**:
```javascript
class PhotoGallery {
    constructor(containerId, peripheralId) { /* ... */ }
    async load() { /* Charger photos */ }
    render() { /* Grid + lightbox */ }
    async upload(files) { /* Upload avec compression */ }
}
```

**RatingStars**:
```javascript
class RatingStars {
    constructor(containerId, currentRating = 0, editable = true) { /* ... */ }
    render() { /* ★★★★☆ */ }
    setRating(value) { /* Clickable */ }
}
```

**LocationSelector**:
```javascript
class LocationSelector {
    constructor(containerId) { /* ... */ }
    async loadTree() { /* Arborescence depuis API */ }
    render() { /* TreeView avec expand/collapse */ }
    getSelectedPath() { /* Breadcrumb */ }
}
```

### Fonctionnalités Clés à Implémenter

#### 1. Gestion de Prêt avec Notifications

**Backend**:
- CRON quotidien (`check_and_send_reminders()`)
- Rappels 2j avant, à échéance, en retard
- Templates emails configurables (YAML)

**Frontend**:
- Modal prêt (emprunteur, dates, caution, photos)
- Modal retour (état, problèmes, caution rendue)
- Liste prêts actifs
- Alertes retards

#### 2. Compression d'Images

```python
# /backend/app/utils/image_processor.py
def compress_image(file_path: str, quality: int = 85):
    from PIL import Image
    img = Image.open(file_path)

    # Resize si trop grand
    if img.width > settings.IMAGE_MAX_WIDTH:
        ratio = settings.IMAGE_MAX_WIDTH / img.width
        new_size = (int(img.width * ratio), int(img.height * ratio))
        img = img.resize(new_size, Image.LANCZOS)

    # Convertir en WebP
    output_path = file_path.replace(ext, '.webp')
    img.save(output_path, 'WEBP', quality=quality)

    return output_path

def generate_thumbnail(file_path: str, size: int = 300):
    # Crop/resize 300x300
    ...
```

#### 3. QR Codes

```python
# /backend/app/utils/qr_generator.py
import qrcode

def generate_peripheral_qr(peripheral_id: int):
    url = f"{settings.FRONTEND_URL}/peripherals/{peripheral_id}"
    img = qrcode.make(url)
    path = f"/uploads/peripherals/qr_{peripheral_id}.png"
    img.save(path)
    return path
```

#### 4. Détection Auto Linux

```python
# /backend/app/services/detection_service.py
def parse_lsusb_output(output: str) -> List[Dict]:
    """Parse lsusb et suggère périphériques"""
    devices = []
    for line in output.split('\n'):
        # Parse: Bus 001 Device 003: ID 046d:c52b Logitech, Inc. Unifying Receiver
        if match := re.match(r'Bus (\d+) Device (\d+): ID ([0-9a-f]{4}):([0-9a-f]{4}) (.+)', line):
            devices.append({
                'vendor_id': match.group(3),
                'product_id': match.group(4),
                'description': match.group(5),
                'suggested_name': parse_device_name(match.group(5))
            })
    return devices
```

### Considérations Importantes

#### Thème et UX

- **Cohérence visuelle**: Utiliser le même thème Monokai que l'existant
- **Two-panel layout**: Liste gauche (20%) + Détails/Formulaire droite (80%)
- **Icons**: Icônes SVG par type de périphérique
- **Badges**: Colorés selon état (Neuf=vert, Usagé=orange, Défectueux=rouge)
- **Responsive**: Grid layout adaptatif

#### Performance

- **Pagination**: 50 items par page
- **Lazy loading**: Images chargées à la demande
- **Cache**: Recherches fréquentes (types, marques)
- **Index DB**: Sur tous les champs de recherche

#### Sécurité

- **Validation uploads**: MIME type, taille max (10MB)
- **Sanitization**: Noms fichiers (supprimer caractères spéciaux)
- **CORS**: Restreindre origines
- **Rate limiting**: 100 req/min par IP

#### Extensibilité

- **YAML dynamique**: Nouveaux types sans modifier code
- **JSON flexible**: `caracteristiques_specifiques` adapté à chaque type
- **Plugins**: Architecture permettant ajout de modules (future)

### Checklist d'Implémentation

#### Backend ✓
- [x] Deux bases de données (sessions séparées)
- [x] Modèles SQLAlchemy (BasePeripherals)
- [x] Schémas Pydantic (CRUD + relations)
- [x] Service layer (cross-DB queries)
- [x] Routes API (20+ endpoints)
- [x] Configuration YAML (types, locations, images, notifications)
- [x] Compression images (Pillow)
- [x] QR codes (qrcode lib)
- [x] CRON notifications (rappels prêts)
- [x] Init DB (création tables + seed data)

#### Frontend ✓
- [x] Pages HTML (peripherals, locations, loans)
- [x] Extension API client (BenchAPI.Peripherals.*)
- [x] Logique pages (peripherals.js, locations.js, loans.js)
- [x] Composants réutilisables (PhotoGallery, RatingStars, LocationSelector, TypeManager)
- [x] CSS cohérent (thème Monokai)
- [x] Navigation mise à jour (toutes les pages)

#### Fonctionnalités ✓
- [x] CRUD périphériques
- [x] Upload photos/documents
- [x] Gestion prêts (création, retour, rappels)
- [x] Localisation (arborescence, historique)
- [x] Appareils complets (lien benchmarks)
- [x] Recherche avancée
- [x] Stock management
- [x] Rating 0-5 étoiles
- [x] QR codes
- [x] Import/Export CSV/JSON

#### Tests & Documentation ✓
- [x] Tests unitaires backend
- [x] Tests intégration API
- [x] Documentation utilisateur
- [x] Documentation API (Swagger)
- [x] Exemples et fixtures

### Commandes Utiles

```bash
# Créer les bases de données
cd /backend
python -c "from app.db.init_db import init_db; init_db()"

# Lancer backend
cd /backend
uvicorn app.main:app --reload --host 0.0.0.0 --port 8007

# Tests
pytest tests/

# Restart Docker
docker-compose restart backend
```

### Points d'Attention

1. **Ne JAMAIS créer de FK SQL entre data.db et peripherals.db** (gérer manuellement)
2. **Toujours utiliser deux sessions** dans les routes avec cross-DB queries
3. **Valider YAML** lors du chargement (schéma pydantic)
4. **Compresser images par défaut** (économie espace)
5. **Logger toutes les actions** (historique, audit)
6. **Tester avec charge** (1000+ périphériques)

### Résultat Attendu

Un **module périphériques complet, professionnel et extensible** qui:

✅ Permet d'inventorier TOUT le matériel informatique
✅ Localise précisément chaque élément
✅ Gère les prêts avec rappels automatiques
✅ S'intègre aux benchmarks existants
✅ Offre une recherche rapide et puissante
✅ Est facile à étendre (types YAML)
✅ Respecte le design existant (Monokai, two-panel)
✅ Fonctionne en production (sécurisé, performant)

**Bonne implémentation !** 🚀
