# 📔 Carnet de Bord - Migration Inventory → Symfony

**Projet** : Migration backend NestJS/Prisma → Symfony/API Platform
**Début** : 2026-01-10
**Objectif** : Migrer vers Symfony + JWT + API Platform propre et maintenable

---

## 🔗 Convention de liaison des commits (INV)

- **Format** : `[INV-YYYYMMDD-XX]`
- **Usage** : même code dans les commits du backend **et** du frontend + ajout ici pour retrouver le duo rapidement.

## 🧾 Journal des liaisons INV

- INV-20260111-01 : ajout du lien submodule `Inventory_frontend` (commit backend : `987aa5c`, commit frontend : `936a73f`)
- INV-20260111-02 : alignement front API Platform + sessions (commit backend : `f7fc1bd`, commit frontend : `e99f053`)

## 🎯 Contexte

- **Situation initiale** :
  - `Inventory_backend/` : NestJS + Prisma (fonctionnel, ~11k lignes)
  - `Inventory_frontend/` : Nuxt 3 (fonctionnel, 105 fichiers)
  - Base de données PostgreSQL avec données en production

- **Objectif** :
  - Backend Symfony 8 + API Platform + JWT
  - Garder les données existantes (migration Prisma → Doctrine)
  - Frontend Nuxt connecté au nouveau backend
  - Docker : 2 backends en parallèle pendant transition

---

## ✅ Phase 1 : Préparation (TERMINÉE - 10/01/2026)

### Ce qui a été fait

#### 1. Docker & Infrastructure ✅
- **pgAdmin ajouté** au docker-compose.yml
  - Port : 5050
  - Login : admin@admin.com / admin
  - Container : `pgadmin-inventory`
  - Volume persistant : `pgadmin_data`
  - **Serveur PostgreSQL pré-configuré** :
    - Fichier `docker/pgadmin/servers.json` monté automatiquement
    - Fichier `docker/pgadmin/pgpass` pour authentification sans mot de passe
    - Connexion automatique à `db:5432/inventory` au démarrage
    - Nom du serveur : "Inventory PostgreSQL"

#### 2. Bundles Symfony installés ✅
```bash
# Versions installées
- lexik/jwt-authentication-bundle: v3.2.0
- vich/uploader-bundle: v2.9.1
- symfony/uid: 8.0.*
```

#### 3. JWT Configuration ✅
- **Clés RSA générées** : `config/jwt/private.pem` + `public.pem`
- **security.yaml configuré** :
  - Firewall `login` : pattern `^/api/login_check` avec `json_login`
  - Firewall `api` : pattern `^/api` avec `jwt` authenticator
  - Provider : `app_user_provider` (entité Profile via email)
  - Password hasher : bcrypt auto

#### 4. Entité Profile créée ✅
**Fichier** : `src/Entity/Profile.php`

**Caractéristiques** :
- Implémente `UserInterface` + `PasswordAuthenticatedUserInterface`
- Champs :
  - `id` : string (30 chars, CUID-compatible pour Prisma)
  - `email` : string unique (username pour JWT)
  - `password` : string (hashed)
  - `roles` : array JSON (ROLE_USER par défaut)
  - `firstName`, `lastName` : string
  - `isActive` : boolean
  - `createdAt`, `updatedAt` : DateTimeImmutable
- Repository : `ProfileRepository` avec `PasswordUpgraderInterface`
- API Platform : endpoints CRUD auto-générés

#### 5. Base de Données ✅
- **Migration créée** : `Version20260110175413`
- **Table** : `profiles` créée avec succès
- **Utilisateur test créé** :
  ```
  Email: admin@admin.com
  Password: admin123
  Roles: ['ROLE_USER', 'ROLE_ADMIN']
  ```

#### 6. API Platform ✅
- **Endpoint racine** : http://localhost:8081/api/
- **Réponse** :
  ```json
  {
    "@context": "/api/contexts/Entrypoint",
    "@id": "/api/",
    "@type": "Entrypoint",
    "profile": "/api/profiles"
  }
  ```
- **OpenAPI Docs** : Configurées (à tester)

#### 7. Configuration Apache ✅
- **VirtualHost** : `docker/php/config/vhost.conf`
- **DocumentRoot** : `/var/www/html/public`
- **AllowOverride** : All (pour `.htaccess`)
- **Port** : 8081 (Apache) → accessible depuis l'hôte

#### 8. Routing Symfony ✅
- **Routes définies** :
  - `/api/login_check` : Login JWT
  - `/api/test` : Test endpoint (TestController)
  - `/api/*` : API Platform auto-routes
- **Vérification** :
  ```bash
  php bin/console debug:router api_test
  php bin/console router:match /api/test --method=GET
  # ✅ Route found and matches
  ```

#### 9. .htaccess créé ✅
**Fichier** : `public/.htaccess`

**Contenu** : Symfony standard avec mod_rewrite

---

### ⚠️ Problèmes identifiés

#### 1. Routes inaccessibles via Apache (404)

**Symptôme** :
```bash
curl http://localhost:8081/api/test
# → 404 Not Found
```

**Tests effectués** :
- ✅ Route existe : `php bin/console debug:router api_test`
- ✅ Route match : `php bin/console router:match /api/test`
- ✅ Symfony fonctionne : `curl http://localhost:8081/api/` → JSON OK
- ✅ PHP built-in server OK :
  ```bash
  php -S localhost:9000
  curl http://localhost:9000/api/test
  # → {"status":"ok","message":"Test endpoint works!"}
  ```
- ❌ Apache 404 : Depuis l'hôte via port 8081

**Diagnostic** :
- Le problème est **Apache-spécifique**
- Symfony/PHP fonctionnent correctement
- Le `.htaccess` n'est probablement **PAS lu par Apache**
- Hypothèses :
  1. `AllowOverride All` non pris en compte
  2. `mod_rewrite` mal configuré
  3. Ordre des directives Apache incorrect
  4. Problème de permissions sur `.htaccess`

**Actions à faire** :
- [ ] Vérifier permissions `.htaccess` dans container
- [ ] Tester `apache2ctl configtest`
- [ ] Activer logs de rewrite : `LogLevel alert rewrite:trace3`
- [ ] Tester FallbackResource dans vhost au lieu de `.htaccess`

#### 2. JWT Login non testé

**Raison** : Bloqué par problème #1 (routes inaccessibles)

**Actions à faire** :
- [ ] Résoudre problème Apache
- [ ] Tester `POST /api/login_check` avec credentials
- [ ] Vérifier génération du token JWT
- [ ] Tester route protégée avec token

---

## 📝 Configuration Actuelle

### Docker Compose

```yaml
services:
  web:
    ports:
      - "8081:80"      # Symfony API
      - "3001:3000"    # (prévu pour Nuxt)

  db:
    ports:
      - "5433:5432"    # PostgreSQL

  pgadmin:
    ports:
      - "5050:80"      # pgAdmin
```

### Variables d'Environnement

**Fichier** : `docker/.env.docker.local`

```env
# PostgreSQL
POSTGRES_DB=inventory
POSTGRES_USER=root
POSTGRES_PASSWORD=root
POSTGRES_PORT=5433

---

## ✅ Phase 2 : Migration DB + Frontend (TERMINÉE - 10/01/2026)

### Ce qui a été fait

#### 1. Entités Doctrine alignées Prisma ✅
- **Toutes les entités manquantes** créées (Machine, ModelType, Composant, Piece, Product, Links, Requirements, CustomField, Document, etc.)
- **IDs en string(36)** pour compatibilité CUID/UUID
- **Colonnes Prisma en camelCase** conservées via `name="..."` (ex: `machineId`, `createdAt`, `supplierPrice`)
- **Corrections** :
  - `Document.path` passé en `TEXT`
  - `CustomField.options` nullable
  - `TypeMachineComponentRequirement.required` corrigé

#### 2. Migration DB inventory-data → inventory ✅
- **Dump data-only + normalisation** (conversion des identifiants quoted vers lowercase)
- **Mapping table Prisma** : `"ModelType"` → `model_types`
- **Exclusions** : `profiles`, `_prisma_migrations`
- **Import validé** : `Counts match for all tables.`

Scripts utiles :
```bash
scripts/normalize-dump.py
scripts/validate-migration.php
```

#### 3. Frontend basculé sur Inventory_frontend ✅
- `make dev-nuxt` pointe vers `Inventory_frontend/`
- `README.md` mis à jour
- **Base API** ajustée : `http://localhost:8081/api`

Fichiers modifiés :
```
makefile
README.md
Inventory_frontend/.env
Inventory_frontend/nuxt.config.ts
Inventory_frontend/app/services/modelTypes.ts
```

---

# pgAdmin
PGADMIN_EMAIL=admin@admin.com
PGADMIN_PASSWORD=admin
PGADMIN_PORT=5050

# Symfony
APP_ENV=dev
APP_SECRET=changeme_super_secret_key_123456789
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=your_jwt_passphrase_change_me

# NestJS (pour futur parallèle)
NESTJS_PORT=3000
SESSION_SECRET=changeme_session_secret
CORS_ORIGIN=http://localhost:3001
```

---

## 🚧 Phase 2 : Debugging & Tests (EN COURS)

### Objectifs
- [x] Résoudre problème Apache `.htaccess`
- [ ] Tester authentification JWT complète
- [ ] Créer endpoint de test public fonctionnel
- [ ] Documenter la solution Apache

### Prochaines étapes
1. **Fix Apache** : Logs de debug + test FallbackResource
2. **Test JWT** : Login + génération token + route protégée
3. **Documentation** : Documenter la config Apache qui fonctionne

---

## 📊 Métriques

### Temps passé
- **Phase 1** : ~3h (exploration + setup + debugging)
- **Problème Apache** : ~1h30 (en cours)

### Fichiers créés/modifiés

**Nouveaux fichiers** :
- `src/Entity/Profile.php`
- `src/Repository/ProfileRepository.php`
- `src/Controller/TestController.php`
- `public/.htaccess`
- `config/routes/routing.controllers.yaml`
- `create_test_user.php` (script utilitaire)
- `migrations/Version20260110175413.php`
- `docker/pgadmin/servers.json` (config serveur PostgreSQL)
- `docker/pgadmin/pgpass` (credentials PostgreSQL)
- `CARNET_DE_BORD.md` (ce fichier)

**Fichiers modifiés** :
- `docker-compose.yml` (+ pgAdmin)
- `docker/.env.docker.local` (+ variables Symfony/JWT/pgAdmin)
- `docker/php/config/vhost.conf` (DocumentRoot → public/)
- `config/packages/security.yaml` (JWT firewalls)
- `config/routes.yaml` (+ api_login_check)
- `composer.json` (+ lexik JWT, vich uploader)

---

## 🎓 Leçons Apprises

### 1. Symfony 8 + API Platform
- **Attributs PHP 8** : `use Symfony\Component\Routing\Attribute\Route;` (pas `Annotation`)
- **Routes controllers** : Nécessite `config/routes/routing.controllers.yaml` avec `type: attribute`
- **API Platform** : Auto-génère les endpoints CRUD avec `#[ApiResource]`

### 2. JWT Authentication
- **3 composants** :
  1. Firewall `login` : `json_login` intercepte `/api/login_check`
  2. Firewall `api` : `jwt` vérifie le token sur `/api/*`
  3. Access control : `PUBLIC_ACCESS` vs `IS_AUTHENTICATED_FULLY`
- **username_path** : Permet de mapper `email` au lieu de `username`
- **Provider** : Doit être défini dans le firewall `login`

### 3. Doctrine Migrations
- **ID Prisma CUID** : Garder en `string(30)` pour compatibilité
- **Lifecycle callbacks** : `#[ORM\PrePersist]` pour `createdAt`/`updatedAt`
- **UserInterface** : Nécessite `getUserIdentifier()`, `getRoles()`, `eraseCredentials()`

### 4. Docker & Apache
- **`.htaccess` vs VirtualHost** : Le vhost peut override le `.htaccess`
- **AllowOverride All** : Indispensable pour que `.htaccess` fonctionne
- **FallbackResource** : Alternative au mod_rewrite dans `.htaccess`
- **Debugging** : Tester avec PHP built-in server pour isoler le problème

---

## 📚 Ressources Utiles

### Accès aux Services

```
🌐 pgAdmin:      http://localhost:5050
   └─ Login:     admin@admin.com / admin
   └─ Serveur:   "Inventory PostgreSQL" (pré-configuré)
   └─ Database:  inventory
   └─ Note:      Le serveur PostgreSQL est automatiquement connecté au démarrage

🌐 API Platform: http://localhost:8081/api/
   └─ Docs:      http://localhost:8081/api/docs (à venir)

🗄️ PostgreSQL:  localhost:5433
   └─ User:      root / root
   └─ Database:  inventory
```

### Commandes fréquentes

```bash
# Symfony
make shell                                    # Entrer dans le container
php bin/console cache:clear                   # Clear cache
make cache-clear-full                         # Clear cache + purge var/cache
php bin/console debug:router                  # Lister routes
php bin/console debug:firewall               # Lister firewalls
php bin/console doctrine:migrations:migrate   # Exécuter migrations

# Docker
make start                                    # Démarrer containers
make stop                                     # Arrêter containers
docker logs -f php-inventory-apache          # Logs Apache
docker logs -f pgadmin-inventory             # Logs pgAdmin
docker exec php-inventory-apache bash        # Shell root

# Tests API
curl http://localhost:8081/api/              # Test API Platform
curl -X POST http://localhost:8081/api/login_check \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@admin.com","password":"admin123"}'
```

### Documentation
- [Lexik JWT Bundle](https://github.com/lexik/LexikJWTAuthenticationBundle/blob/2.x/Resources/doc/index.rst)
- [API Platform Security](https://api-platform.com/docs/core/security/)
- [Symfony Security](https://symfony.com/doc/current/security.html)

---

## 🔄 Historique des Changements

### 2026-01-15 - Session 3
- ✅ Filtre API Platform `category` sur `ModelType`
- ✅ Normalisation des structures `ModelType` (structure ↔ skeleton)
- ✅ Migration `custom_fields.options` en JSON
- ✅ Ajout commande `make cache-clear-full`
- ✅ Correctifs frontend: headers API Platform, pagination par catégorie, persistance tri

### 2026-01-10 - Session 2 (20h30)
- ✅ Problème Apache résolu (routes fonctionnelles)
- ✅ Phase 2 complète (JWT 100% opérationnel)
- ✅ Authentification testée avec succès
- ✅ Réorganisation projet (frontend/ + _archives/)
- ✅ État des lieux dans MIGRATION_PLAN.md
- ✅ 5 commits conventionnels créés
- 📊 Base inventory-data analysée (673 lignes)

### 2026-01-10 - Session 1 (19h00)
- ✅ Création projet migration
- ✅ Phase 1 complète (pgAdmin, JWT, Profile, migrations)
- ⚠️ Problème Apache identifié (routes 404)
- 📝 Carnet de bord créé

---

**Dernière mise à jour** : 2026-01-15 13:45
**Statut** : Phase 3 EN COURS ⚠️ - Migrations et intégration frontend
