# Site vitrine — Formateur informatique

Squelette de projet Symfony 7.4 LTS pour un site vitrine de formateur (systèmes / développement / data),
avec espace d'administration (EasyAdminBundle), API REST sécurisée (API Platform + JWT) et blog.

**Versions ciblées** : PHP ≥ 8.2 (testé jusqu'à 8.5 inclus), Symfony 7.4 LTS (support jusqu'en 2028/2029),
MySQL 8.0 / MariaDB 10.11+, Doctrine ORM 2.17+ ou 3.x.


## Modèle Prestation / Session

`Prestation` est l'entité centrale du catalogue : elle couvre tout type de service (formation, coaching,
développement, conception de cours...) via son champ `type` (enum PHP `App\Enum\TypePrestation`). Le site
public et l'API exposent uniquement les prestations actives.

`Session` représente une date/un créneau planifié pour une prestation (ex. une session de formation le
12/03). **Gestion strictement interne** : visible et modifiable uniquement dans l'espace admin (menu
"Sessions"), jamais sur le site public ni via l'API — pas d'`ApiResource` sur cette entité, par choix.

## Migrations en production

⚠️ **Limitation connue** : l'hébergement de production tourne sur **MariaDB 10.3.39**, une version trop
ancienne pour la commande `doctrine:migrations:migrate` avec les versions actuelles de Doctrine
DBAL/ORM (bug d'introspection de schéma : `Unknown column 'i_c.TABLE_NAME'`). Cette commande fonctionne
normalement en local (MariaDB 11.8+) mais **échoue systématiquement en prod**, quelle que soit la
migration à appliquer — c'est pourquoi elle a été retirée de `.github/workflows/deploy.yml`.

**Procédure pour appliquer une évolution de schéma en production :**
1. En local, génère la migration comme d'habitude : `php bin/console doctrine:migrations:diff`
2. Applique-la et teste-la en local (`doctrine:migrations:migrate`)
3. Ouvre le fichier de migration généré, et transforme chaque `$this->addSql('...')` de la méthode
   `up()` en un script `.sql` autonome
4. Exécute ce script manuellement sur la prod via **phpMyAdmin** (onglet SQL)
5. Enregistre manuellement la version comme appliquée, en insérant directement la ligne en SQL
   (la commande `doctrine:migrations:version --add` échoue pour la même raison que `migrate`) :
   ```sql
   INSERT INTO doctrine_migration_versions (version, executed_at, execution_time)
   VALUES ('DoctrineMigrations\\VersionXXXXXXXXXXXXXX', NOW(), 0);
   ```
   (le double `\\` est nécessaire pour représenter un seul antislash dans la valeur stockée)

Attention aux **noms d'index** : la toute première migration de cette prod utilisait des noms explicites
(`UNIQ_article_slug`...) alors que les migrations générées ensuite par Doctrine utilisent des noms
générés automatiquement (`UNIQ_23A0E66989D9B62`...). Vérifie toujours `SHOW INDEX FROM nom_table;`
avant d'exécuter un `RENAME INDEX` pour repartir du bon nom source.

## Installation


```bash
# 1. Créer un nouveau projet Symfony (si pas déjà fait) et copier ces fichiers dedans
composer create-project symfony/skeleton:"7.4.*" formateur-site
cd formateur-site

# 2. Copier les fichiers de ce squelette (src/, templates/, sql/, config/, public/, composer.json) dans le projet

# 3. Installer les dépendances
composer require symfony/orm-pack symfony/twig-pack symfony/webapp-pack \
    easycorp/easyadmin-bundle symfony/form symfony/validator symfony/security-bundle \
    "api-platform/core:^4.2" lexik/jwt-authentication-bundle nelmio/cors-bundle

# 4. Configurer la base de données dans .env
# DATABASE_URL="mysql://user:password@127.0.0.1:3306/formateur_site"

# 5. Créer la base et importer le schéma
mysql -u root -p -e "CREATE DATABASE formateur_site CHARACTER SET utf8mb4"
mysql -u root -p formateur_site < sql/schema.sql

# OU, si tu préfères passer par Doctrine Migrations :
php bin/console doctrine:database:create
php bin/console make:migration
php bin/console doctrine:migrations:migrate

# 6. Générer les clés JWT (API)
php bin/console lexik:jwt:generate-keypair

# 6bis. Installer les assets publics des bundles tiers (EasyAdmin notamment) —
# à refaire après chaque composer update qui touche à easycorp/easyadmin-bundle
php bin/console assets:install public --symlink --relative

# 7. Créer un utilisateur admin
php bin/console security:hash-password
# puis insérer manuellement une ligne dans la table `user` avec l'email, le hash,
# et roles = ["ROLE_ADMIN"] (colonne JSON)

# 8. Lancer le serveur
symfony server:start
# ou
php -S 127.0.0.1:8000 -t public/
```

## API REST sécurisée

L'API est exposée via **API Platform** sous `/api` (documentation interactive sur `/api/docs`).

**Authentification (JWT)** :
```bash
curl -X POST https://ton-domaine/api/login_check \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@exemple.com","password":"ton_mot_de_passe"}'
# -> {"token": "eyJ0eXAiOiJKV1Qi..."}
```
Réutilise ensuite ce token dans l'en-tête `Authorization: Bearer <token>` pour les opérations protégées.

**Règles de sécurité par ressource :**

| Ressource        | Lecture (GET)                          | Écriture (POST/PUT/DELETE) |
|-------------------|-----------------------------------------|------------------------------|
| Prestation        | Publique (prestations actives)         | `ROLE_ADMIN` uniquement      |
| Article           | Publique (articles publiés)            | `ROLE_ADMIN` uniquement      |
| Categorie         | Publique                                | `ROLE_ADMIN` uniquement      |
| ContactMessage    | `ROLE_ADMIN` uniquement (données perso) | Création publique (POST), reste `ROLE_ADMIN` |

⚠️ **Important** : le filtrage des collections `/api/prestations` et `/api/articles` est géré par deux
extensions Doctrine (`src/Doctrine/PrestationActiveExtension.php` et `ArticlePublishedExtension.php`) qui
restreignent automatiquement les résultats aux éléments actifs/publiés pour tout utilisateur non-admin.
API Platform les détecte normalement via l'autoconfiguration (interface `QueryCollectionExtensionInterface`),
mais un filet de sécurité est fourni dans `config/services_api_extensions.yaml` — importe ce fichier dans
ton `config/services.yaml` si les extensions ne sont pas prises en compte automatiquement :

```yaml
# config/services.yaml
imports:
    - { resource: services_api_extensions.yaml }
```

**CORS** : si un front séparé (SPA, appli mobile) consomme l'API depuis un autre domaine, ajuste
`CORS_ALLOW_ORIGIN` dans `.env` avec le(s) domaine(s) autorisé(s).

## Charte graphique

Palette noir / blanc / orange appliquée via :
- `public/css/custom.css` — surcharge des variables Bootstrap pour le site public
- `public/css/admin-theme.css` — thème EasyAdmin (chargé automatiquement via `configureAssets()`)

Couleurs de référence : noir `#111111`, blanc `#ffffff`, orange `#ff6a00` (orange foncé au survol `#d95700`).
Modifiables directement dans les variables CSS en tête de `custom.css`.

## Structure

- `src/Entity/` — Categorie, Prestation, Session, Article, ContactMessage, User
- `src/Enum/` — TypePrestation, FormatSession, StatutSession (enums PHP natifs)
- `src/Controller/` — HomeController, PrestationController, ArticleController, ContactController
- `src/Controller/Admin/` — DashboardController + CRUD EasyAdmin pour Prestation/Session/Article/Messages
- `templates/` — Twig, base.html.twig + un dossier par page
- `sql/schema.sql` — schéma MySQL brut (alternative aux migrations Doctrine)

## Prochaines étapes suggérées

- Ajouter l'authentification admin (`make:user`, `make:auth` avec le maker-bundle)
- Styliser avec un thème (Bootstrap ou Tailwind via CDN, cf. tes préférences habituelles)
- Ajouter le formulaire de contact avec Symfony Forms + envoi d'email (Symfony Mailer)
- Générer les migrations Doctrine à partir des entités fournies plutôt que d'utiliser schema.sql directement
