531 lines
16 KiB
Markdown
531 lines
16 KiB
Markdown
# Plan de développement - Application de partitions OHMJ
|
|
|
|
## Structure finale du projet
|
|
|
|
```
|
|
/home/jbnadal/sources/jb/ohmj/ohmj2/
|
|
├── legacy/ # Backup ancien code
|
|
│ ├── api/ # Ancien PHP legacy (MySQL)
|
|
│ ├── frontend/ # Ancien Vue.js 2
|
|
│ ├── fpdf/
|
|
│ ├── Imgs/
|
|
│ ├── Scripts/
|
|
│ ├── Textes/
|
|
│ └── index.php
|
|
├── api/ # NOUVEAU backend PHP moderne
|
|
│ ├── index.php # Router / entry point API
|
|
│ ├── config/
|
|
│ │ └── users.json # Users avec passwords hashés
|
|
│ └── lib/
|
|
│ ├── Auth.php # JWT authentication
|
|
│ └── ScoreScanner.php # Lecture fichiers ini + scan partitions
|
|
├── partitions/ # NOUVEAU frontend SvelteKit
|
|
│ ├── src/
|
|
│ │ ├── routes/
|
|
│ │ │ ├── +page.svelte # Login page
|
|
│ │ │ ├── scores/+page.svelte # Liste des morceaux
|
|
│ │ │ ├── scores/[id]/+page.svelte # Détail partition
|
|
│ │ │ └── +layout.svelte # Layout avec auth guard
|
|
│ │ ├── lib/
|
|
│ │ │ ├── api.ts # Client API
|
|
│ │ │ └── stores/auth.ts # Store JWT
|
|
│ │ └── app.html
|
|
│ ├── package.json
|
|
│ └── svelte.config.js
|
|
└── Scores/ # Répertoire partitions (hors git)
|
|
└── {id}/
|
|
├── score.ini
|
|
├── cla/
|
|
│ └── 1/
|
|
│ └── *.pdf
|
|
└── ...
|
|
```
|
|
|
|
## Phase 1 : Backend PHP (api/)
|
|
|
|
### 1.1 ScoreScanner.php ✓ (FAIT)
|
|
- [x] Classe pour scanner les partitions
|
|
- [x] Lecture des fichiers score.ini (supporte sections [info], [pieces])
|
|
- [x] Scan récursif instruments → parties → fichiers PDF
|
|
- [x] Mapping codes instruments vers noms
|
|
- [x] Retourne `piece` pour chaque instrument
|
|
- [x] Parse les noms de fichiers : `part`, `key`, `clef`, `variant`
|
|
- [x] Retourne `ressource` si présent dans score.ini
|
|
- [x] Supporte les partitions multi-morceaux (ex: score 390)
|
|
|
|
### 1.2 Auth.php
|
|
- [x] Classe JWT pour authentification
|
|
- [x] Génération token JWT
|
|
- [x] Vérification token JWT
|
|
- [x] Lecture users.json
|
|
- [x] Vérification password hashé (bcrypt)
|
|
- [ ] Tests unitaires Auth.php (PHP non installé)
|
|
|
|
### 1.3 users.json
|
|
- [x] Fichier JSON avec structure users
|
|
- [ ] Passwords hashés avec bcrypt (password: password)
|
|
- [ ] Script pour ajouter/modifier users
|
|
|
|
### 1.4 index.php (Router API)
|
|
- [x] CORS headers
|
|
- [x] POST /login
|
|
- [x] GET /scores (protégé JWT)
|
|
- [x] GET /scores/:id (protégé JWT)
|
|
- [x] GET /pieces/:scoreId (protégé JWT)
|
|
- [x] GET /download/:path (protégé JWT, stream PDF)
|
|
- [x] POST /admin/scores (protégé JWT, créer partition)
|
|
- [x] PUT /admin/scores/:id (protégé JWT, modifier partition)
|
|
- [x] DELETE /admin/scores/:id (protégé JWT, supprimer partition)
|
|
- [x] POST /admin/scores/:id/upload (protégé JWT, upload PDF)
|
|
- [ ] Gestion erreurs JSON
|
|
- [ ] Tests toutes les routes (PHP non installé)
|
|
|
|
### 1.5 Tests API
|
|
- [ ] Tests unitaires Auth.php (PHP non installé)
|
|
- [ ] Tests intégration toutes les routes (PHP non installé)
|
|
- [ ] Tests authentification JWT (PHP non installé)
|
|
|
|
## Phase 2 : Frontend SvelteKit (partitions/)
|
|
|
|
### 2.1 Initialisation projet
|
|
- [ ] npm create svelte@latest partitions
|
|
- [ ] TypeScript + ESLint + Prettier
|
|
- [ ] npm install (axios, etc.)
|
|
|
|
### 2.2 Configuration
|
|
- [ ] svelte.config.js (adapter static)
|
|
- [ ] API base URL config
|
|
|
|
### 2.3 Stores
|
|
- [ ] lib/stores/auth.ts
|
|
- [ ] Store JWT token
|
|
- [ ] Store user info
|
|
- [ ] Persistance localStorage
|
|
|
|
### 2.4 Client API
|
|
- [ ] lib/api.ts
|
|
- [ ] Instance axios avec baseURL
|
|
- [ ] Intercepteur pour ajouter header Authorization
|
|
- [ ] Méthodes : login(), getScores(), getScore(id), downloadFile(path)
|
|
|
|
### 2.5 Routes
|
|
|
|
#### Login (/)
|
|
- [ ] Formulaire : username, password
|
|
- [ ] Appel API login
|
|
- [ ] Stockage JWT
|
|
- [ ] Redirection vers /scores
|
|
- [ ] Gestion erreurs
|
|
|
|
#### Liste des morceaux (/scores)
|
|
- [ ] Auth guard (redirect si pas connecté)
|
|
- [ ] Table/DataGrid avec :
|
|
- [ ] Numéro (ID)
|
|
- [ ] Nom du morceau
|
|
- [ ] Compositeur
|
|
- [ ] Tri possible
|
|
- [ ] Click → navigation /scores/:id
|
|
- [ ] Loading state
|
|
|
|
#### Détail partition (/scores/[id])
|
|
- [ ] Auth guard
|
|
- [ ] Header :
|
|
- [ ] Numéro
|
|
- [ ] Nom du morceau
|
|
- [ ] Compositeur
|
|
- [ ] Bouton retour
|
|
- [ ] Liste des instruments (grid ou accordion) :
|
|
- [ ] Nom de l'instrument
|
|
- [ ] Pour chaque partie :
|
|
- [ ] Numéro de partie
|
|
- [ ] Liste des fichiers PDF
|
|
- [ ] Bouton téléchargement par fichier
|
|
- [ ] Loading state
|
|
|
|
#### Layout
|
|
- [ ] Auth guard global
|
|
- [ ] Header avec :
|
|
- [ ] Titre app
|
|
- [ ] User connecté
|
|
- [ ] Bouton logout
|
|
- [ ] Footer (optionnel)
|
|
|
|
### 2.6 Styles
|
|
- [ ] CSS moderne (Tailwind ou CSS vanilla)
|
|
- [ ] Responsive (mobile-friendly)
|
|
- [ ] Thème harmonie (couleurs)
|
|
|
|
## Phase 3 : Déploiement
|
|
|
|
### 3.1 Build frontend
|
|
- [ ] npm run build
|
|
- [ ] Output dans dist/
|
|
|
|
### 3.2 Configuration serveur
|
|
- [ ] /partitions → contenu dist/
|
|
- [ ] /api → PHP
|
|
- [ ] /legacy/Scores → accès aux PDFs
|
|
- [ ] .htaccess ou config nginx pour routing
|
|
|
|
### 3.3 Sécurité
|
|
- [ ] HTTPS obligatoire
|
|
- [ ] JWT secret fort
|
|
- [ ] Protection download (vérif JWT)
|
|
- [ ] Headers sécurité
|
|
|
|
## Notes techniques
|
|
|
|
### Backend PHP
|
|
- Pas de base de données
|
|
- JWT pour auth stateless
|
|
- Lecture fichiers uniquement
|
|
- Stream PDF pour download
|
|
|
|
### Frontend SvelteKit
|
|
- Svelte 5 (runes)
|
|
- TypeScript strict
|
|
- Pas de store complexe (juste auth)
|
|
- Client API simple
|
|
|
|
### Contraintes
|
|
- Chemin partitions : ../legacy/Scores/ (sera déplacé après DL)
|
|
- Fichiers ini présents partout
|
|
- PDFs uniquement
|
|
- Auth obligatoire pour tout accès
|
|
|
|
## Phase Préliminaire : Normalisation des données
|
|
|
|
### 0.1 Structure des partitions (à valider)
|
|
- [ ] Analyser tous les instruments pour voir si le répertoire "1" est nécessaire
|
|
- [ ] Identifier les cas où il n'y a qu'une seule partie (supprimer le niveau "1" ?)
|
|
- [ ] Valider la structure finale avant codage
|
|
|
|
### 0.2 Harmonisation des noms de fichiers ✓
|
|
**Convention finale :**
|
|
- Format : `{instrument}[_{instrument2}][_{variante}][_{tonalité}]_{partie}[_clef].pdf`
|
|
- Exemples :
|
|
- `clarinette_sib_1.pdf` (clarinette en Si♭, partie 1)
|
|
- `clarinette_alto_mib_1.pdf` (clarinette alto en Mi♭, partie 1)
|
|
- `basse_et_contrebasse_sib_1.pdf` (partition pour 2 instruments)
|
|
- `cor_mib_1_et_2.pdf` (cor en Mi♭, parties 1 et 2 combinées)
|
|
- `euphonium_sib_2_clefa.pdf` (euphonium en Si♭, partie 2, clé de fa)
|
|
- Tout en minuscule, français, ASCII sans accents
|
|
- Tonalités : sib (Bb), mib (Eb), fa (F), do (C), etc.
|
|
- **Garder les sous-répertoires numérotés (1/, 2/, etc.)** pour distinguer les versions
|
|
- **Script :** `scripts/convert_final_v2.js`
|
|
- **Usage :** `node scripts/convert_final_v2.js /chemin/vers/Scores confirm`
|
|
|
|
### 0.3 À propos des répertoires numérotés (1/, 2/, etc.)
|
|
**Découverte importante :**
|
|
- Le répertoire `1/` = version principale du morceau
|
|
- Le répertoire `2/` (ou plus) = alternative du même morceau
|
|
- Cela permet d'avoir plusieurs versions d'un même morceau dans le même ID
|
|
- Exemple : Score 210, dossier `cla/1/` et `cla/2/` contiennent des versions différentes
|
|
- **Action:** Le script de conversion doit utiliser le numéro du répertoire comme numéro de partie UNIQUEMENT pour les fichiers "version_X"
|
|
|
|
### 0.4 À propos du répertoire "sup"
|
|
- Le répertoire `sup/` signifie "supérieur" ou "combiné"
|
|
- C'est une partition où deux instruments jouent sur la même partition
|
|
- Ex: baryton + tuba sur une même partition
|
|
- **Note API:** Ces partitions combinées doivent être gérées différemment dans l'interface (afficher les deux instruments)
|
|
|
|
### 0.5 Conventions de nommage - Instruments
|
|
**Orthographe standardisée (français) :**
|
|
- Clarinette → clarinette
|
|
- Saxophone → saxophone (ou sax_baryton, sax_tenor, sax_alto, sax_soprano pour les variantes)
|
|
- Cor → cor
|
|
- Trompette → trompette
|
|
- Trombone → trombone
|
|
- Tuba → tuba (ou tuba_tenor pour tenor tuba)
|
|
- Basse → basse
|
|
- Contrebasse → contrebasse (UN SEUL MOT)
|
|
- Baryton → baryton
|
|
- Euphonium → euphonium
|
|
- Flute → flute (ou petite_flute, grande_flute)
|
|
- Hautbois → hautbois
|
|
- Basson → basson
|
|
- Contre-basson → contre_basson
|
|
- Bugle → bugle (inclut flugelhorn)
|
|
- Percussion → percussion (timbales, grosse_caisse, cymbale, caisse_claire, triangle, etc.)
|
|
|
|
**Instrumentsperaussion reconnus :**
|
|
- timpani, glockenspiel, bongos, maracas, tambourine, vibraphone, xylophone
|
|
- woodblock, claves, batterie
|
|
|
|
**Tonalités :**
|
|
- sib (Bb), mib (Eb), fa (F), do (ut), sol, re, mi, si, reb
|
|
- NOTE: "do" devient "ut" dans les noms de fichiers
|
|
|
|
**Cas spéciaux gérés :**
|
|
- "default_cor" = instrument de substitution (ex: baryton_default_cor_2)
|
|
- Parties combinées avec & = format "instrument1_et_instrument2_info1_info2_partie"
|
|
|
|
### 0.6 Structure du nom de fichier final
|
|
**Format :** `{instrument}[_{variante}][_{tonalité}][_{default}][_{instrument_subst}]_{partie}[_clef].pdf`
|
|
|
|
**Exemples :**
|
|
- `clarinette_sib_1.pdf`
|
|
- `sax_baryton_mib_1.pdf`
|
|
- `cor_fa_1_et_2.pdf`
|
|
- `baryton_sib_default_cor_2.pdf`
|
|
- `sax_tenor_sib_1.pdf`
|
|
- `baryton_mib_2_clesol.pdf`
|
|
- `baryton_et_tuba_tenor_sib_clefa.pdf` (parties combinées sup)
|
|
|
|
**Note:** Pour les parties combinées (sup), chaque instrument garde ses propres infos (tonalité, partie, clef)
|
|
|
|
## Phase 3 : Déploiement
|
|
|
|
### 3.1 Build frontend
|
|
- [ ] npm run build
|
|
- [ ] Output dans dist/
|
|
|
|
### 3.2 Configuration serveur
|
|
- [ ] /partitions → contenu dist/
|
|
- [ ] /api → PHP
|
|
- [ ] /legacy/Scores → accès aux PDFs
|
|
- [ ] .htaccess ou config nginx pour routing
|
|
|
|
### 3.3 Sécurité
|
|
- [ ] HTTPS obligatoire
|
|
- [ ] JWT secret fort
|
|
- [ ] Protection download (vérif JWT)
|
|
- [ ] Headers sécurité
|
|
|
|
## Phase 4 : Admin (post-déploiement)
|
|
|
|
### 4.1 Page d'administration
|
|
- [ ] Route `/admin` protégée (super-user)
|
|
- [ ] Interface CRUD pour les partitions
|
|
- [ ] Formulaire : ID, nom du morceau, compositeur
|
|
- [ ] Création automatique du répertoire et du score.ini
|
|
- [ ] Upload drag & drop des fichiers PDF
|
|
- [ ] Organisation automatique des fichiers dans la bonne structure
|
|
- [ ] Validation du format (convention de nommage)
|
|
|
|
## Prochaines étapes
|
|
|
|
1. ✓ Backup legacy (FAIT)
|
|
2. ✓ Renommage IDs avec zéros (FAIT)
|
|
3. ✓ Correction noms fichiers (& et espaces) (FAIT)
|
|
4. → Définir structure finale des partitions
|
|
5. → Harmoniser tous les noms de fichiers
|
|
6. → Créer Auth.php
|
|
7. → Créer users.json
|
|
8. → Créer index.php (router)
|
|
9. → Tester backend
|
|
10. → Créer frontend SvelteKit
|
|
11. → Développer routes
|
|
12. → Tester intégration
|
|
13. → Déployer
|
|
14. → Développer page admin
|
|
|
|
---
|
|
|
|
## Conversion des noms de fichiers (2026-02-17)
|
|
|
|
### Structure finale
|
|
`NUM/PIECE/INSTRUMENT/VERSION/PARTIE.pdf`
|
|
|
|
- **NUM**: numéro du score (ex: 102, 390)
|
|
- **PIECE**: numéro de pièce (1 = premier morceau)
|
|
- **INSTRUMENT**: trigramme de l'instrument (ex: cla, sax, trp)
|
|
- **VERSION**: numéro de version (1 = première version)
|
|
- **PARTIE**: numéro de partie (ex: 1, 2, 3...)
|
|
|
|
### Exemples
|
|
|
|
#### Score normal (1 seul morceau)
|
|
- `102/1/cla/1/1/clarinette-sib-1.pdf`
|
|
|
|
#### Score 390 (5 morceaux différents)
|
|
- `390/1/sax/1/1/sax_alto-1.pdf` (pièce 1)
|
|
- `390/2/sax/1/1/sax_alto-1.pdf` (pièce 2)
|
|
|
|
### Format score.ini
|
|
|
|
```ini
|
|
[info]
|
|
name = La part d'Euterpe
|
|
compositor = Michaël CUVILLON
|
|
|
|
[pieces]
|
|
count = 1
|
|
```
|
|
|
|
Pour 390:
|
|
```ini
|
|
[info]
|
|
name = La part d'Euterpe
|
|
compositor = Michaël CUVILLON
|
|
|
|
[pieces]
|
|
count = 5
|
|
1 = La Part d Euterpe
|
|
2 = Calliope s Songs
|
|
3 = Interlude
|
|
4 = Oxola
|
|
5 = Steps to Paranassus
|
|
```
|
|
|
|
### Étapes realizadas
|
|
|
|
1. ✅ score.ini: ajouté section [info] et [pieces] pour tous les scores
|
|
2. ✅ Répertoires 2 chiffres renommés (72→072, 73→073, 98→098)
|
|
3. ✅ Structure NUM/1/INSTRUMENT/VERSION appliquée pour tous les scores (sauf 390)
|
|
4. ✅ Structure NUM/PIECE/INSTRUMENT/VERSION appliquée pour 390 (PIECE=1-5)
|
|
5. ✅ Script convert_final_v2.js mis à jour pour supporter la nouvelle structure
|
|
6. ✅ Conversion appliquée: 6388 fichiers convertis, 0 erreurs
|
|
|
|
### Validation
|
|
|
|
- ✅ Multi instruments: utilise `+` (ex: `basse-sib-1+contrebasse-sib-1.pdf`)
|
|
- ✅ Parties combinées: utilise `_` (ex: `cor-mib-1_2.pdf`)
|
|
- ✅ Variantes: `solo` (ex: `clarinette-sib-solo-1.pdf`)
|
|
- ✅ Clefs: `clesol`, `clefa` (ex: `basse-sib-clesol-1.pdf`)
|
|
- ✅ Mots composés: `sax_alto`, `clarinette_basse`
|
|
- ✅ Pas de `-et-` (0 occurrences)
|
|
- ✅ Pas de `--` (0 occurrences)
|
|
|
|
---
|
|
|
|
## Phase future : Liens externes
|
|
|
|
### Objectif
|
|
|
|
Ajouter des liens externes dans les partitions (YouTube, site éditeur, etc.)
|
|
|
|
### Implementation
|
|
|
|
1. **Modification score.ini** (FAIT)
|
|
```ini
|
|
[info]
|
|
name = Le morceau
|
|
compositor = Compositeur
|
|
ressource = https://youtube.com/watch?v=xxx
|
|
# ou
|
|
ressource = https://www.musicdiffusion.com/...
|
|
```
|
|
|
|
2. **API** (FAIT)
|
|
- GET /scores → retourner `ressource` si présent
|
|
- GET /scores/:id → retourner `ressource` aussi
|
|
|
|
3. **Frontend**
|
|
- Page liste partitions : afficher icône lien externe si présent
|
|
- Page détail partition : afficher les liens sous le titre
|
|
|
|
### Ordre de priorité
|
|
- Implémenté, en attente frontend
|
|
|
|
---
|
|
|
|
## TODO: Icônes instruments
|
|
|
|
- Installer lucide-svelte (fait)
|
|
- Personnaliser chaque instrument avec la bonne icône
|
|
|
|
### Code IconeDesired
|
|
- pic flute traversiere
|
|
- flu flute traversiere
|
|
- cla clarinette
|
|
- clb clarinette basse
|
|
- sax OK
|
|
- sat OK
|
|
- sab OK
|
|
- coa cor anglais
|
|
- cba OK
|
|
- cor cor
|
|
- trp OK
|
|
- trb OK
|
|
- tub OK
|
|
- htb hautbois
|
|
- bas basson
|
|
- per OK
|
|
- crn OK
|
|
- eup OK
|
|
- har OK
|
|
- pia OK
|
|
|
|
---
|
|
|
|
## TODO: Déploiement
|
|
|
|
### Solution idéale: Docker
|
|
|
|
**Services à conteneriser:**
|
|
1. **PHP-FPM** - API backend
|
|
2. **Nginx** - Servir static + proxy PHP
|
|
3. **Node.js** - Frontend SvelteKit (ou build static)
|
|
|
|
**docker-compose.yml:**
|
|
```yaml
|
|
services:
|
|
nginx:
|
|
image: nginx:alpine
|
|
ports:
|
|
- "80:80"
|
|
volumes:
|
|
- ./frontend/build:/usr/share/nginx/html
|
|
- ./api:/var/www/html
|
|
- ./legacy/Scores:/var/www/html/Scores
|
|
depends_on:
|
|
- php
|
|
|
|
php:
|
|
image: php:8.2-fpm
|
|
volumes:
|
|
- ./api:/var/www/html
|
|
|
|
node:
|
|
build: ./partitions
|
|
command: npm run dev
|
|
```
|
|
|
|
### Solution alternative: Serveur classique
|
|
|
|
**Si hébergement mutualisé:**
|
|
- Build SvelteKit → dossier `build/`
|
|
- PHP-FPM pour API
|
|
- Dossiers:
|
|
- `/` → frontend static
|
|
- `/api` → PHP
|
|
- `/legacy/Scores` → fichiers PDF
|
|
|
|
### Tâches pour déploiement
|
|
- [x] Créer Dockerfile
|
|
- [x] Créer docker-compose.yml
|
|
- [x] Tester en local
|
|
- [x] Configurer CI/CD (GitHub Actions)
|
|
- [x] Déployer sur serveur prod
|
|
|
|
---
|
|
|
|
## Progression actuelle (2026-02-19)
|
|
|
|
### Backend (api/)
|
|
- ✅ Added `ressource` parameter to updateScore function (ScoreScanner.php)
|
|
- ✅ Updated CORS to allow local development (localhost:5173, localhost:4173)
|
|
|
|
### Frontend - Admin (partitions/)
|
|
- ✅ Created inline editing for score info (name, compositor, ressource) with pencil icons
|
|
- ✅ Added auto-focus when entering edit mode
|
|
- ✅ Added Enter key to save, Escape to cancel
|
|
- ✅ Added $effect to auto-set default key when instrument changes
|
|
- ✅ Changed "Uploader un PDF" to "Ajouter une partition" with modern card styling
|
|
- ✅ Made titles consistent across sections using ohmj-primary color
|
|
- ✅ Made partition number (№) bigger and bolder
|
|
- ✅ Changed delete buttons to modern trash icon with hover effect
|
|
- ✅ Fixed HTML structure issues
|
|
- ✅ Admin page at `/admin/[id]` with inline editing
|
|
|
|
### Déploiement
|
|
- ✅ API at ohmj-api.c.nadal-fr.com
|
|
- ✅ Frontend at partitions.c.nadal-fr.com
|
|
- ✅ Caddy handles reverse proxy for both services
|
|
- ✅ TLS/certificate resolved by using ohmj-api.c.nadal-fr.com
|
|
- ✅ Deploy zip at _builds/deploy_ohmj.zip
|
|
|
|
### API Documentation
|
|
- ✅ README.md updated with ressource parameter
|