JavaScript 56.7%
TypeScript 42.6%
1<p align="center">2 <img src="https://img.shields.io/badge/SPB_Cloud-v3.1-6366f1?style=for-the-badge&logo=cloud&logoColor=white" alt="Version" />3</p>45<h1 align="center">SPB Private Cloud</h1>67<p align="center">8 <strong>Cloud personnel privé, souverain, sécurisé et mobile-first.</strong><br/>9 Plus clean que Dropbox. Plus privé que Google Drive. 100% local-first.10</p>1112<p align="center">13 <img src="https://img.shields.io/badge/Next.js-14-black?style=flat-square&logo=nextdotjs&logoColor=white" alt="Next.js" />14 <img src="https://img.shields.io/badge/TypeScript-5-3178C6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" />15 <img src="https://img.shields.io/badge/Tailwind_CSS-3.4-06B6D4?style=flat-square&logo=tailwindcss&logoColor=white" alt="Tailwind" />16 <img src="https://img.shields.io/badge/Prisma-ORM-2D3748?style=flat-square&logo=prisma&logoColor=white" alt="Prisma" />17 <img src="https://img.shields.io/badge/SQLite-Database-003B57?style=flat-square&logo=sqlite&logoColor=white" alt="SQLite" />18 <img src="https://img.shields.io/badge/Claude_AI-Sonnet_4.5-D97706?style=flat-square&logo=anthropic&logoColor=white" alt="Claude AI" />19</p>2021<p align="center">22 <img src="https://img.shields.io/badge/License-Private-red?style=flat-square" alt="License" />23 <img src="https://img.shields.io/badge/Platform-macOS%20%7C%20Linux%20%7C%20VPS-lightgrey?style=flat-square" alt="Platform" />24 <img src="https://img.shields.io/badge/Mobile-Responsive-green?style=flat-square&logo=apple&logoColor=white" alt="Mobile" />25 <img src="https://img.shields.io/badge/Auth-2FA%20TOTP-purple?style=flat-square&logo=keycdn&logoColor=white" alt="2FA" />26 <img src="https://img.shields.io/badge/Encryption-AES--256--GCM-orange?style=flat-square&logo=letsencrypt&logoColor=white" alt="Encryption" />27 <img src="https://img.shields.io/badge/API-REST%20v1-blue?style=flat-square&logo=fastapi&logoColor=white" alt="API" />28</p>2930---3132## v3.1 — Connexion par code courriel, audit fonctionnel, réorganisation IA (2026-09-07)3334**Connexion par code courriel (Resend)** — méthode par défaut : saisir son adresse (`spbou4@protonmail.com`, `r-boucher@sympatico.ca`…), recevoir un code à 6 chiffres (10 min, 5 essais, renvoi 30 s), le saisir. Le code est stocké haché dans le cookie de session chiffré (aucune table). Routes `POST /api/auth/otp/request` et `/verify` ; envoi via `lib/mailer.ts` (Resend REST, `RESEND_API_KEY`, `MAIL_FROM`). ⚠ Sans domaine vérifié dans Resend, seul `onboarding@resend.dev` est autorisé et il ne livre qu'au propriétaire du compte : vérifier `spboucher.ai` dans Resend puis mettre `MAIL_FROM="SPB Cloud <no-reply@spboucher.ai>"` pour que Richard reçoive ses codes. Connexion par mot de passe conservée (administration).3536**Audit fonctionnel (11 correctifs)** — suppression de dossier = corbeille récursive (plus de fichiers orphelins ni de contenu effacé du disque), restauration fidèle (dossier d'origine recréé), purge réelle (contenu + versions + vignettes) et purge horaire des > 30 j (`server.ts`), **partage de dossier** (`POST /api/shares {folderId}`, page publique avec navigation, ZIP, mot de passe via cookie signé), sous-dossiers héritant de l'espace partagé, quotas cohérents (chunks, duplication, corbeille exclue), duplication conservant l'extension, validations 404/400, notifications d'upload, WebDAV DELETE → corbeille. Migration : `scripts/migrations/apply-2026-09-07-audit.ts` (idempotente) puis `npx prisma generate` **dans le dossier de l'app** (le client Prisma mémorise le dossier `prisma/` au moment de la génération).3738**Réorganisation IA des espaces partagés** (`scripts/organize/`) — `extract.ts` (Claude Opus 5 : vision pour les photos, PDF natif, texte/Office), `dupes.ts` (SHA-256), `plan.ts` (arborescence + noms par espace, albums photo par ordre de numérisation), `apply.ts --dry-run` puis `apply.ts` (sauvegarde `VACUUM INTO`, journal `data/applied.jsonl`), `verify.ts`, `rollback.ts`. Appliqué le 2026-09-07 : 9 espaces, 1 171 fichiers renommés/déplacés, 85 dossiers créés, 44 anciens supprimés, 78 doublons identiques isolés dans « 99 Doublons identiques ». `data/` est ignoré par git (métadonnées personnelles).3940## Nouveautés v3 « Aurora » (2026-09-07)4142Refonte complète du front-end, déployée sur `cloud.spboucher.ai` (M2U64, PM2 `cloud`).4344**Design system**45- Tokens sémantiques (`canvas`, `surface`, `elevated`, `line`), thème clair / sombre / système, **7 couleurs d'accent** au choix (Aurore, Océan, Glacier, Forêt, Corail, Ambre, Améthyste) appliquées à toute l'interface via `--accent-*`.46- Police **Geist** locale (plus d'appel à Google Fonts), verre dépoli, ombres douces, animations réductibles (préférence « Réduire les animations »).47- Densité des listes (confortable / compacte). Préférences dans `⌘,` — persistées en `localStorage` et appliquées avant le premier rendu (script inline dans `app/layout.tsx`, clés dans `lib/prefs.ts`).4849**Coquille**50- Barre latérale repliable en rail (`⌘B`), sections Dossiers / Espaces / Outils / Administration / Tags, jauge de stockage, menu utilisateur.51- Barre supérieure avec fil d'Ariane (cible de dépôt), bouton Envoyer, assistant IA, notifications, thème.52- **Palette de commandes `⌘K`** (ou `/`) : recherche de fichiers et dossiers en direct, navigation, actions (envoyer, nouveau dossier, thème, préférences, déconnexion), historique des commandes.53- Mobile : barre d'onglets iOS-like, tiroir glissable, PWA installable (`manifest.webmanifest`, icônes, `viewport-fit=cover`).5455**Explorateur**56- Liste avec en-tête collant et colonnes triables, grille avec vignettes et actions rapides, sélection par plage (⇧-clic), clic droit → menu contextuel, navigation clavier complète.57- **Glisser-déposer** : fichiers du bureau (overlay plein écran), déplacement interne vers dossiers, arbre latéral (auto-expansion) et fil d'Ariane ; déplacement multiple.58- Liens profonds `?file=`, `?upload=1`, `?new=1` (utilisés par la palette, la barre supérieure et l'accueil).59- Aperçu : plein écran réel, balayage tactile, panneau d'informations et versions refaits.6061**Accueil et administration**62- Bandeau vivant, anneau de stockage par catégorie, activité sur 14 jours, KPI, « Reprendre », favoris, fichiers volumineux.63- `GET /api/admin/stats` enrichi (rétro-compatible) : `byCategory`, `activityByDay`, `favoriteCount`, `trashCount`, `versionCount`, `largestFiles`.6465**Correctifs**66- Recherche `/api/files?search=` : `mode: "insensitive"` (non supporté par Prisma/SQLite) renvoyait 500.67- Limiteur de débit : 600 req/min/IP et exemption des aperçus/flux (une grille de 50 vignettes dépassait l'ancien plafond de 100).68- Vignettes de l'accueil pointaient vers une route `/raw` inexistante.69- Route `/admin/snapshots` manquante (404) ; `app/api/snapshots` n'était pas versionné (`.gitignore` trop large).70- `SNAPSHOT_DISABLED=1` désactive le snapshot quotidien (utile pour un serveur de staging).7172## Qu'est-ce que SPB Cloud ?7374SPB Private Cloud est un cloud personnel auto-hébergé conçu pour offrir un contrôle total sur vos données. Aucune dépendance à Google, Dropbox ou iCloud. Vos fichiers restent chez vous, chiffrés, accessibles depuis n'importe quel appareil.7576### Pourquoi SPB Cloud ?7778| | SPB Cloud | Google Drive | Dropbox |79|---|---|---|---|80| **Propriété des données** | Vous | Google | Dropbox |81| **Chiffrement at-rest** | AES-256-GCM | Oui (leur clé) | Oui (leur clé) |82| **IA intégrée** | Claude Sonnet 4.5 | Gemini (limité) | Non |83| **OCR intelligent** | Oui (Vision IA) | Basique | Non |84| **Coût mensuel** | 0$ (auto-hébergé) | 2.99$/mois+ | 11.99$/mois+ |85| **Code source** | Accès complet | Fermé | Fermé |86| **Multi-utilisateur** | Oui (roles) | Oui | Oui |87| **2FA TOTP** | Oui | Oui | Oui |88| **API REST** | Oui | Oui | Oui |8990---9192## Fonctionnalités9394### Gestion de fichiers95- Upload multi-fichiers avec drag & drop96- Upload depuis caméra mobile97- Rename, delete, move, duplicate98- Organisation en dossiers imbriqués99- Breadcrumb navigation100- Vue grille et liste101- Sélection multiple + actions en lot102- Téléchargement de dossiers en ZIP103- Progress bar d'upload104105### Preview de fichiers106- Images (JPG, PNG, GIF, WebP, SVG)107- Vidéos (MP4, WebM, MOV)108- Audio (MP3, WAV, OGG) avec waveform109- PDF avec navigation de pages110- Code source avec syntax highlighting (20+ langages)111- Markdown avec rendu112- CSV/JSON avec tableau interactif113- Archives ZIP (exploration du contenu)114115### Intelligence Artificielle (Claude Sonnet 4.5)116- **Recherche sémantique** : trouvez des fichiers par description naturelle117- **Chat IA** : posez des questions sur vos fichiers118- **Auto-tagging** : classification automatique par contenu119- **OCR intelligent** : extraction de texte depuis images et PDFs120- **Description IA** : génération automatique de descriptions121122### Sécurité123- Hash bcrypt pour les mots de passe124- Authentification 2FA TOTP (Google Authenticator, Authy)125- Chiffrement AES-256-GCM at-rest126- Sessions HTTP-only cookies (iron-session)127- Rate limiting sur le login128- CSRF protection129- Validation des types de fichiers130131### Multi-utilisateur132- Système de rôles : Admin, User, Viewer133- Gestion CRUD des utilisateurs134- Permissions par rôle135- Logs d'activité par utilisateur136137### Partage sécurisé138- Liens de partage avec token unique139- Protection par mot de passe optionnel140- Date d'expiration configurable141- Mode téléchargement ou aperçu seul142- Désactivation instantanée143- Gestion centralisée des liens144145### Système de backup146- Backup complet (DB + fichiers) en ZIP147- Backup incrémental148- Historique des backups avec statut149- Suppression des anciens backups150151### Notifications152- Notifications en temps réel (polling 30s)153- Badge avec compteur non-lus154- Types : upload, backup, IA, partage155- Marquer comme lu / tout lire156157### API REST publique158- Authentification par clé API (Bearer token)159- Génération et révocation de clés160- Permissions configurable (read, write, admin)161- Expiration optionnelle des clés162- Endpoint : `GET /api/v1/files`163164### Interface165- Design mobile-first (iPhone optimisé)166- Mode clair / sombre avec persistance167- Touch targets 44px minimum168- Bottom sheet modals sur mobile169- Safe area support (notch iPhone)170- Sidebar collapsible171- Animations Framer Motion172- Typographie Inter173174---175176## Stack technique177178<p align="center">179 <img src="https://img.shields.io/badge/Frontend-Next.js_14-000000?style=for-the-badge&logo=nextdotjs" alt="Next.js" />180 <img src="https://img.shields.io/badge/Language-TypeScript_5-3178C6?style=for-the-badge&logo=typescript" alt="TypeScript" />181 <img src="https://img.shields.io/badge/Styling-Tailwind_CSS-06B6D4?style=for-the-badge&logo=tailwindcss" alt="Tailwind" />182 <img src="https://img.shields.io/badge/Animation-Framer_Motion-FF0055?style=for-the-badge&logo=framer" alt="Framer" />183</p>184<p align="center">185 <img src="https://img.shields.io/badge/ORM-Prisma-2D3748?style=for-the-badge&logo=prisma" alt="Prisma" />186 <img src="https://img.shields.io/badge/Database-SQLite-003B57?style=for-the-badge&logo=sqlite" alt="SQLite" />187 <img src="https://img.shields.io/badge/Auth-iron--session-FF6600?style=for-the-badge" alt="iron-session" />188 <img src="https://img.shields.io/badge/AI-Anthropic_Claude-D97706?style=for-the-badge&logo=anthropic" alt="Claude" />189</p>190191---192193## Installation194195### Prérequis196197- **Node.js** 18+198- **npm** 9+199- Clé API Anthropic (pour les fonctionnalités IA)200201### Installation rapide202203```bash204# 1. Cloner le repo205git clone https://github.com/simonpierreboucher02/spb-private-cloud.git206cd spb-private-cloud207208# 2. Installer les dépendances209npm install210211# 3. Configurer l'environnement212cp .env.example .env213# Éditer .env avec vos valeurs214215# 4. Initialiser la base de données216npx prisma db push217npx tsx prisma/seed.ts218219# 5. Lancer l'application220npm run dev221```222223L'application sera accessible sur [http://localhost:3000](http://localhost:3000).224225### Configuration (.env)226227```env228DATABASE_URL="file:./dev.db"229SESSION_PASSWORD="votre-secret-session-min-32-caracteres"230ANTHROPIC_API_KEY="sk-ant-api03-..."231ENCRYPTION_KEY="votre-cle-encryption-32-caracteres"232BACKUP_DIR="./backups"233UPLOAD_DIR="./uploads"234MAX_FILE_SIZE="524288000"235```236237### Identifiants par défaut238239| Champ | Valeur |240|---|---|241| **Email** | `admin@spbcloud.local` |242| **Mot de passe** | `admin123` |243| **Rôle** | Admin |244245> **Important** : Changez le mot de passe après la première connexion via Admin > Utilisateurs.246247---248249## Architecture250251```252spb-private-cloud/253├── app/254│ ├── admin/ # Pages administration255│ │ ├── activity/ # Historique d'activité256│ │ ├── api-keys/ # Gestion clés API257│ │ ├── backup/ # Gestion backups258│ │ ├── settings/ # Paramètres (2FA)259│ │ ├── shares/ # Liens partagés260│ │ └── users/ # Gestion utilisateurs261│ ├── api/262│ │ ├── ai/ # Endpoints IA (search, chat, tag, ocr, describe)263│ │ ├── auth/ # Login, logout, 2FA264│ │ ├── backup/ # CRUD backups265│ │ ├── files/ # CRUD fichiers + bulk + versions266│ │ ├── folders/ # CRUD dossiers + ZIP download267│ │ ├── keys/ # CRUD clés API268│ │ ├── notifications/# Notifications269│ │ ├── shares/ # Liens de partage270│ │ ├── tags/ # Tags271│ │ ├── users/ # Gestion utilisateurs272│ │ └── v1/ # API REST publique273│ ├── dashboard/ # File explorer274│ ├── login/ # Page de connexion275│ └── shared/ # Pages de partage public276├── components/277│ ├── admin/ # Composants admin278│ ├── ai/ # Panel IA279│ ├── files/ # FileCard, FileExplorer, BulkActions280│ ├── folders/ # FolderCard, CreateFolderModal281│ ├── layout/ # AppShell, Sidebar, MobileNav, Notifications282│ ├── preview/ # Preview engine + plugins (image, video, pdf...)283│ ├── tags/ # TagBadge, TagSelector284│ ├── theme/ # ThemeProvider, ThemeToggle285│ └── ui/ # Button, Modal, SearchBar286├── lib/287│ ├── ai.ts # Intégration Claude API288│ ├── auth.ts # Authentification multi-user289│ ├── backup.ts # Système de backup290│ ├── encryption.ts # Chiffrement AES-256-GCM291│ ├── notifications.ts # Système de notifications292│ ├── prisma.ts # Client Prisma293│ ├── rate-limit.ts # Rate limiting294│ ├── session.ts # Configuration sessions295│ ├── storage.ts # Gestion fichiers sur disque296│ └── utils.ts # Utilitaires297├── prisma/298│ ├── schema.prisma # Schéma de base de données299│ └── seed.ts # Seed admin user300├── types/301│ └── files.ts # Types TypeScript302└── uploads/ # Stockage fichiers (git-ignored)303```304305---306307## Base de données308309### Modèles Prisma310311| Modèle | Description |312|---|---|313| `User` | Utilisateurs avec rôles et 2FA |314| `File` | Fichiers avec métadonnées, IA, chiffrement |315| `Folder` | Dossiers imbriqués (arbre récursif) |316| `SharedLink` | Liens de partage sécurisés |317| `Permission` | Permissions par dossier/utilisateur |318| `ActivityLog` | Journal d'activité |319| `FileMetadata` | Métadonnées étendues (favoris, annotations) |320| `Tag` / `FileTag` | Système de tags |321| `FileVersion` | Versioning de fichiers |322| `Notification` | Notifications utilisateur |323| `ApiKey` | Clés API REST |324| `BackupLog` | Historique des backups |325326---327328## API REST329330### Authentification331332Toutes les requêtes à l'API publique nécessitent un header `Authorization` :333334```bash335curl -H "Authorization: Bearer spb_votre_cle_api" \336 https://votre-domaine/api/v1/files337```338339### Endpoints340341| Méthode | Endpoint | Description |342|---|---|---|343| `GET` | `/api/v1/files` | Lister les fichiers |344| `GET` | `/api/v1/files?folderId=xxx` | Fichiers d'un dossier |345346### Générer une clé API3473481. Connectez-vous en tant qu'admin3492. Allez dans **Administration > Clés API**3503. Cliquez **Nouvelle clé**3514. Copiez la clé générée (affichée une seule fois)352353---354355## Déploiement356357### Mac Studio / NAS (local)358359```bash360# Build de production361npm run build362363# Lancer en production364PORT=3001 npm start365```366367### VPS (avec Nginx)368369```nginx370server {371 listen 443 ssl;372 server_name cloud.votredomaine.com;373374 ssl_certificate /etc/letsencrypt/live/cloud.votredomaine.com/fullchain.pem;375 ssl_certificate_key /etc/letsencrypt/live/cloud.votredomaine.com/privkey.pem;376377 client_max_body_size 500M;378379 location / {380 proxy_pass http://127.0.0.1:3001;381 proxy_http_version 1.1;382 proxy_set_header Upgrade $http_upgrade;383 proxy_set_header Connection 'upgrade';384 proxy_set_header Host $host;385 proxy_set_header X-Real-IP $remote_addr;386 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;387 proxy_set_header X-Forwarded-Proto $scheme;388 proxy_cache_bypass $http_upgrade;389 }390}391```392393### Docker (optionnel)394395```dockerfile396FROM node:18-alpine397WORKDIR /app398COPY package*.json ./399RUN npm ci400COPY . .401RUN npx prisma generate402RUN npm run build403EXPOSE 3000404CMD ["npm", "start"]405```406407---408409## Roadmap410411### Fait412- [x] Upload multi-fichiers + drag & drop413- [x] Organisation en dossiers imbriqués414- [x] Preview 10+ formats (PDF, images, vidéo, audio, code, markdown...)415- [x] Partage sécurisé avec expiration et mot de passe416- [x] Mode clair / sombre417- [x] Multi-utilisateur avec rôles418- [x] 2FA TOTP419- [x] Recherche IA (Claude Sonnet 4.5)420- [x] Chat IA intégré421- [x] Auto-tagging IA422- [x] OCR intelligent (images + PDF)423- [x] Chiffrement AES-256-GCM424- [x] Système de backup425- [x] Notifications426- [x] API REST avec clés427- [x] Actions en lot (supprimer, déplacer, ZIP, chiffrer)428- [x] Interface mobile-first (iPhone optimisé)429430### À venir431- [ ] Migration PostgreSQL432- [ ] HTTPS / SSL intégré433- [ ] Corbeille (soft delete)434- [ ] Thumbnails auto-générés435- [ ] Video streaming HLS436- [ ] Infinite scroll437- [ ] Docker Compose438- [ ] WebDAV439- [ ] Sync multi-device440441---442443## Sécurité444445SPB Cloud est conçu avec la sécurité en priorité :446447| Mesure | Détail |448|---|---|449| **Mots de passe** | Hash bcrypt (12 rounds) |450| **2FA** | TOTP RFC 6238 (Google Authenticator) |451| **Sessions** | Cookies HTTP-only, SameSite, expiration 24h |452| **Chiffrement** | AES-256-GCM avec clé dérivée (scrypt) |453| **Rate limiting** | 5 tentatives/min sur login |454| **API Keys** | SHA-256 hash, jamais stockées en clair |455| **Upload** | Limite de taille configurable |456457---458459## Auteurs460461<table>462 <tr>463 <td align="center">464 <strong>Simon-Pierre Boucher</strong><br/>465 Créateur & Propriétaire<br/>466 <a href="https://www.spboucher.ai">www.spboucher.ai</a><br/>467 <a href="mailto:spbou4@protonmail.com">spbou4@protonmail.com</a>468 </td>469 <td align="center">470 <strong>Claude Opus 4.6</strong><br/>471 Co-auteur & Développeur IA<br/>472 <a href="https://anthropic.com">Anthropic</a><br/>473 Architecture, code, optimisation mobile474 </td>475 </tr>476</table>477478---479480## Statistiques du projet481482<p align="center">483 <img src="https://img.shields.io/badge/Fichiers-139-blue?style=for-the-badge" alt="Files" />484 <img src="https://img.shields.io/badge/Lignes_de_code-21%2C456-green?style=for-the-badge" alt="Lines" />485 <img src="https://img.shields.io/badge/API_Routes-32-orange?style=for-the-badge" alt="API Routes" />486 <img src="https://img.shields.io/badge/Composants-28-purple?style=for-the-badge" alt="Components" />487</p>488489<p align="center">490 <img src="https://img.shields.io/badge/Preview_Plugins-10-teal?style=flat-square" alt="Plugins" />491 <img src="https://img.shields.io/badge/Mod%C3%A8les_DB-12-red?style=flat-square" alt="DB Models" />492 <img src="https://img.shields.io/badge/Fonctions_IA-5-yellow?style=flat-square" alt="AI Functions" />493 <img src="https://img.shields.io/badge/D%C3%A9pendances-42-grey?style=flat-square" alt="Dependencies" />494</p>495496---497498## Contact499500- **Email** : [spbou4@protonmail.com](mailto:spbou4@protonmail.com)501- **Site web** : [www.spboucher.ai](https://www.spboucher.ai)502- **GitHub** : [github.com/simonpierreboucher02](https://github.com/simonpierreboucher02)503504---505506<p align="center">507 <sub>Built with passion by Simon-Pierre Boucher & Claude Opus 4.6</sub><br/>508 <sub>© 2024-2026 SPB Private Cloud. Tous droits réservés.</sub>509</p>510