# 📁 Organisation des fichiers par hostname ## Vue d'ensemble Le systĂšme d'upload a Ă©tĂ© amĂ©liorĂ© pour organiser automatiquement les fichiers et images par hostname de device dans des sous-dossiers structurĂ©s. ### Structure prĂ©cĂ©dente ``` uploads/ ├── 3562b30f85326e79_3.jpg ├── 7660e368d0cb566e_4.png ├── 8b5371f003d8616f_3.png ├── ec199bc98be16a37_3.pdf └── peripherals/ ``` ### Nouvelle structure ``` uploads/ ├── srv-proxmox/ │ ├── images/ │ │ ├── 3562b30f85326e79_3.jpg │ │ └── 7660e368d0cb566e_4.png │ └── files/ │ └── ec199bc98be16a37_3.pdf ├── rpi4-cluster-01/ │ ├── images/ │ │ └── a1b2c3d4e5f67890_1.jpg │ └── files/ │ └── datasheet_5.pdf └── peripherals/ └── (unchanged) ``` ## Avantages 1. **Organisation claire** : Les fichiers sont regroupĂ©s par device 2. **SĂ©paration images/fichiers** : Facilite la gestion et les sauvegardes 3. **ScalabilitĂ©** : Fonctionne avec des milliers de devices 4. **Navigation facile** : AccĂšs direct aux fichiers d'un device 5. **Nettoyage simplifiĂ©** : Suppression d'un device = suppression d'un dossier ## Fonctionnement ### DĂ©tection automatique Le systĂšme dĂ©tecte automatiquement si un fichier est une image : **Extensions d'images** : - `.jpg`, `.jpeg` - `.png` - `.gif` - `.webp` - `.bmp` - `.svg` **Type MIME** : - Tout MIME type commençant par `image/` ### Sanitisation des noms Les hostnames sont nettoyĂ©s pour ĂȘtre utilisables comme noms de dossiers : ```python # Exemples de sanitisation "srv-proxmox.local" → "srv-proxmox.local" "my server (old)" → "my_server_old" "test@2024" → "test_2024" "___test___" → "test" ``` **RĂšgles** : - CaractĂšres interdits remplacĂ©s par `_` - Points et tirets conservĂ©s - Underscores multiples condensĂ©s - Longueur limitĂ©e Ă  100 caractĂšres - Fallback sur "unknown" si vide ## Migration des fichiers existants Un script de migration est fourni pour rĂ©organiser les fichiers existants. ### Dry-run (simulation) Pour voir ce qui serait fait sans modifier les fichiers : ```bash python backend/migrate_file_organization.py ``` Sortie exemple : ``` ================================================================================ File Organization Migration ================================================================================ Found 15 documents to migrate Mode: DRY RUN -------------------------------------------------------------------------------- 📄 Document 1 (image): Device: srv-proxmox (ID: 3) From: ./uploads/3562b30f85326e79_3.jpg To: ./uploads/srv-proxmox/images/3562b30f85326e79_3.jpg [DRY RUN - would migrate] 📄 Document 5 (file): Device: srv-proxmox (ID: 3) From: ./uploads/ec199bc98be16a37_3.pdf To: ./uploads/srv-proxmox/files/ec199bc98be16a37_3.pdf [DRY RUN - would migrate] ... Summary: Migrated: 12 Skipped: 2 Errors: 1 Total: 15 This was a DRY RUN. To actually migrate files, run: python backend/migrate_file_organization.py --execute ``` ### Migration rĂ©elle Pour effectuer rĂ©ellement la migration : ```bash python backend/migrate_file_organization.py --execute ``` ### Avec nettoyage Pour migrer ET supprimer les dossiers vides : ```bash python backend/migrate_file_organization.py --execute --cleanup ``` ## Utilisation de l'API ### Upload d'un document L'API dĂ©tecte automatiquement le type et place le fichier au bon endroit : ```bash # Upload d'une image curl -X POST "http://localhost:8007/api/devices/3/docs" \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "file=@photo.jpg" \ -F "doc_type=photo" # Sera stockĂ© dans: uploads/srv-proxmox/images/hash_3.jpg ``` ```bash # Upload d'un PDF curl -X POST "http://localhost:8007/api/devices/3/docs" \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "file=@manual.pdf" \ -F "doc_type=manual" # Sera stockĂ© dans: uploads/srv-proxmox/files/hash_3.pdf ``` ### TĂ©lĂ©chargement Le tĂ©lĂ©chargement utilise toujours le mĂȘme endpoint : ```bash curl "http://localhost:8007/api/docs/123/download" \ -H "Authorization: Bearer YOUR_TOKEN" \ -o document.pdf ``` Le systĂšme lit le `stored_path` en base de donnĂ©es qui contient le chemin complet. ## Architecture technique ### Module file_organizer.py ```python from app.utils.file_organizer import ( sanitize_hostname, get_device_upload_paths, ensure_device_directories, get_upload_path, is_image_file ) ``` **Fonctions principales** : #### `sanitize_hostname(hostname: str) -> str` Nettoie un hostname pour utilisation comme nom de dossier. #### `get_device_upload_paths(base_dir: str, hostname: str) -> Tuple[str, str]` Retourne les chemins (images, files) pour un device. #### `ensure_device_directories(base_dir: str, hostname: str) -> Tuple[str, str]` CrĂ©e les dossiers s'ils n'existent pas et retourne les chemins. #### `get_upload_path(base_dir: str, hostname: str, is_image: bool, filename: str) -> str` Retourne le chemin complet oĂč stocker un fichier. #### `is_image_file(filename: str, mime_type: str = None) -> bool` DĂ©termine si un fichier est une image. ### Modification de docs.py Avant : ```python stored_path = os.path.join(settings.UPLOAD_DIR, stored_filename) os.makedirs(settings.UPLOAD_DIR, exist_ok=True) ``` AprĂšs : ```python is_image = is_image_file(file.filename, file.content_type) stored_path = get_upload_path( settings.UPLOAD_DIR, device.hostname, is_image, stored_filename ) ``` ## CompatibilitĂ© ### Anciens fichiers Les fichiers existants continuent de fonctionner grĂące au `stored_path` en base de donnĂ©es : - Les anciens chemins (`uploads/hash_id.ext`) restent valides - Les nouveaux uploads utilisent la nouvelle structure - La migration est **optionnelle** mais recommandĂ©e ### TĂ©lĂ©chargement L'API de tĂ©lĂ©chargement utilise le `stored_path` de la base de donnĂ©es, donc : - ✅ Anciens fichiers : fonctionnent - ✅ Nouveaux fichiers : fonctionnent - ✅ Fichiers migrĂ©s : fonctionnent ## Cas d'usage ### Sauvegarde sĂ©lective ```bash # Sauvegarder seulement les images d'un device rsync -av uploads/srv-proxmox/images/ backup/srv-proxmox-images/ # Sauvegarder tous les PDF find uploads/*/files -name "*.pdf" -exec cp {} backup/pdfs/ \; ``` ### Nettoyage par device ```bash # Supprimer tous les fichiers d'un device dĂ©sinstallĂ© rm -rf uploads/old-server/ ``` ### Audit de l'espace ```bash # Voir l'espace utilisĂ© par device du -sh uploads/*/ # Sortie : # 45M uploads/srv-proxmox/ # 120M uploads/rpi4-cluster-01/ # 2.3M uploads/laptop-dev/ ``` ## Migration progressive Vous pouvez migrer progressivement : 1. **Phase 1** : DĂ©ployer le nouveau code - Nouveaux uploads utilisent la nouvelle structure - Anciens fichiers restent en place 2. **Phase 2** : Tester la migration - Faire un dry-run - VĂ©rifier les chemins gĂ©nĂ©rĂ©s 3. **Phase 3** : Migrer en production - ExĂ©cuter la migration rĂ©elle - VĂ©rifier que les tĂ©lĂ©chargements fonctionnent 4. **Phase 4** : Nettoyage - Nettoyer les dossiers vides - Archiver les anciens fichiers si nĂ©cessaire ## SĂ©curitĂ© ### Validation - Les noms de fichiers sont hashĂ©s (pas de conflit de noms) - Les hostnames sont sanitisĂ©s (pas d'injection de chemin) - Les tailles de fichiers sont vĂ©rifiĂ©es - Les extensions sont validĂ©es ### Isolation - Chaque device a son propre dossier - Pas de risque de collision entre devices - Permissions prĂ©servĂ©es ## Performance ### Impact - ✅ CrĂ©ation de dossiers : nĂ©gligeable (mkdir -p) - ✅ Upload : identique Ă  avant - ✅ Download : identique Ă  avant - ✅ Migration : proportionnel au nombre de fichiers ### Optimisations - Les dossiers sont créés une seule fois - Pas de scans rĂ©cursifs - Utilise les fonctions OS natives ## Limitations 1. **Hostname changeant** : Si un hostname change, les fichiers restent dans l'ancien dossier - Solution : Script de remapping si nĂ©cessaire 2. **CaractĂšres spĂ©ciaux** : Certains caractĂšres sont remplacĂ©s par `_` - C'est intentionnel pour la compatibilitĂ© filesystem 3. **PĂ©riphĂ©riques** : Le dossier `peripherals/` garde sa propre structure - Pour Ă©viter de casser le code existant ## FAQ **Q: Que se passe-t-il si je ne migre pas les anciens fichiers ?** R: Ils continuent de fonctionner normalement. Seuls les nouveaux uploads utilisent la nouvelle structure. **Q: Puis-je revenir en arriĂšre ?** R: Oui, en modifiant les `stored_path` en base de donnĂ©es et en dĂ©plaçant les fichiers. **Q: La migration supprime-t-elle les fichiers originaux ?** R: Non, elle les **dĂ©place** (move, pas copy). Les fichiers ne sont pas dupliquĂ©s. **Q: Que faire si un device a le mĂȘme hostname qu'un autre ?** R: Les fichiers iront dans le mĂȘme dossier, mais les noms de fichiers incluent le device_id donc pas de collision. --- **Fichiers créés** : - `backend/app/utils/file_organizer.py` - Module utilitaire - `backend/migrate_file_organization.py` - Script de migration **Fichiers modifiĂ©s** : - `backend/app/api/docs.py` - Utilise la nouvelle organisation **Créé le** : 2026-01-11