# Décisions techniques

> Décisions **proposées**, hypothèses de travail et questions ouvertes issues de la phase d'audit.
> Rien n'est figé : ce document sert de base d'arbitrage avant le début du développement.
> Format inspiré des ADR (Architecture Decision Records).

## 1. Décisions proposées (à valider)

### D-01 — CMS maison, sans framework lourd
Micro-noyau PHP fait main (routeur, couche PDO, vues, sessions, CSRF). **Pas** de WordPress ni de
framework lourd (exigence AGENTS.md). Justification : site simple (≈8 galeries, ~100 images),
hébergement mutualisé, maintenabilité.

### D-02 — La base de données devient la source de vérité
Abandon du modèle « filesystem + régénération `update.php` ». Le contenu (galeries, images, ordre,
textes, SEO) vit en base ; le système de fichiers ne stocke que les binaires d'images. Conséquence :
fin des conventions de nommage `##`/`++`/`--` et de `text.txt`.

### D-03 — Accès aux données via PDO + requêtes préparées
Systématiquement, pour la portabilité MySQL 8 / MariaDB 10.11 et la sécurité (anti-injection).

### D-04 — Encodage utf8mb4 de bout en bout
Base, tables, connexion et sorties en **utf8mb4** (l'ancien site était en `utf8` 3 octets). Couvre
accents, `&`, ligatures (`œ`), etc.

### D-05 — Secrets hors dépôt
`config/local.php` (non versionné, déjà prévu dans `.gitignore`) pour identifiants DB et **email de
contact**. `config/config.php` versionné pour les valeurs par défaut non sensibles.

### D-06 — Traitement d'images à l'upload via GD
Génération des dérivés (web, miniature, couverture) **au moment de l'upload**, pas en lot destructif.
GD (disponible en mutualisé) encapsulé dans un `ImageService`. La classe `Zebra_Image` de l'ancien
site sert de **référence d'algorithme** (modes de recadrage), pas de code à copier.

### D-07 — Conserver les slugs publics existants
`/anfractuosite`, `/bouches-a-clef`, `/cartes-geo`, `/chien-mechant-cie`, `/gravures-noires`,
`/gravures-pliages`, `/modele-berger`, `/sols-graphismes` repris à l'identique pour préserver le SEO.
Redirections 301 seulement en cas d'exception.

### D-08 — Authentification applicative réelle
`password_hash`/`password_verify`, sessions sécurisées (cookie `HttpOnly`/`SameSite`, régénération
d'ID à la connexion), CSRF. Remplace le HTTP Basic Auth de `/libs/`.

### D-09 — Suppression des reliquats à risque
`info.php` (phpinfo), `update.php`, `libs/*`, `chemin.php` ne sont **pas** repris. Endpoints de debug
proscrits en production.

### D-10 — Le schéma reste une proposition tant qu'il n'est pas validé
La proposition de tables (`cms.md` §3) n'est **pas** écrite dans `database/schema.sql` durant l'audit
(« ne créer aucune table définitive »). Matérialisation en phase 1 après validation.

### D-11 — Framework front : **Bootstrap 5** (recommandation pour « BS4, 5 ou autre »)
Choix proposé : **Bootstrap 5.3+** (vendored, sans build obligatoire ; CDN possible en secours).
Justification :
- **Aucune dépendance jQuery** (l'ancien site était en Bootstrap 3 + jQuery) → modernisation.
- **Barre de navigation responsive native** avec hamburger (`navbar` + `navbar-toggler` + `collapse`),
  qui couvre le besoin de menu hamburger « comme la référence » (voir D-12).
- **Variables CSS natives** (`--bs-*`) → rend la **gestion simple des couleurs** triviale (D-13).
- Grille responsive 4/2/1 colonnes immédiate.
- Léger, compatible mutualisé, pas d'outil de build requis.

Comparatif : **Bootstrap 4** nécessite jQuery pour la navbar (moins bon) ; **Tailwind** impose en
pratique une étape de build (contraire à « pas de build sans validation ») et se prête mal au réglage
des couleurs à l'exécution ; **CSS 100 % maison** (l'option qu'utilise justement le site de référence,
qui n'embarque pas le framework Bootstrap) est viable mais plus coûteux en développement et réinvente
navbar + grille. → **BS5 retenu**, sauf objection.

> Lightbox : BS5 n'en fournit pas. Prévoir une **lightbox légère sans jQuery** (ex. GLightbox ou
> une solution maison minimale) en remplacement de Fancybox. *(Sous-question Q-15.)*

### D-12 — Menu de navigation responsive (hamburger) façon référence
Ajout d'un **vrai menu de navigation** (absent de l'ancien site, qui n'affichait que des tuiles).
Comportement calqué sur https://www.brunstatt-didenheim.fr/ **uniquement pour le fonctionnement**
(pas les couleurs) :
- En-tête avec **logo à gauche** + **bouton hamburger** ; menu **horizontal en grand écran**,
  **replié en hamburger** sous le point de rupture (≈ `lg` / 992px).
- Au clic : **panneau off-canvas** (glisse depuis un bord, **par-dessus** la page, avec voile sombre),
  fermé par une croix ou en touchant le voile — **choix client**. (La référence, elle, est en *collapse* ;
  BS5 fournit l'off-canvas nativement.)
- Contenu du menu : **Accueil + galeries publiées** (triées) + **Contact** (si activé).
- Couleurs issues du **thème du site** (D-13), pas de la référence.

### D-13 — Gestion des couleurs simple, via variables CSS pilotées par l'admin
Un écran d'administration **simple** (« sans aller dans trop de détail ») expose **6 couleurs**
(Q-16 tranchée) : fond, texte, liens/accent, fond d'en-tête, **fond de pied de page**, **survol**.
Elles sont stockées en base (`settings`) puis **injectées en variables CSS** dans le `<head>` public
(`:root { --color-… }`, surcharge éventuelle des `--bs-*`). Valeurs par défaut = couleurs proches de
la production actuelle (fond `#e6e6e6`, texte `#7a7a7a`, accent `#e2041a`). Bouton « réinitialiser ».

### D-14 — Chargement progressif des images (lazy-load) **paramétrable** dans l'admin
Le « upload on load » des galeries = **chargement différé au défilement** : afficher un premier lot
puis charger la suite au scroll (l'ancien `index.php` faisait 12 images puis +4). **Confirmé par le
client** : l'admin règle **deux choses** — **si on l'utilise** (on/off) et **le nombre d'images par
lot**. Réglages `settings` : `gallery_lazyload_enabled` et `gallery_batch_size` (le premier lot et les
suivants utilisent ce même nombre). Complété par `loading="lazy"` natif sur les `<img>`.

### D-15 — Lightbox : **GLightbox** (sans jQuery)
Choix retenu (Q-15) : **GLightbox** (~10 Ko, sans dépendance, accessible clavier/ARIA, swipe mobile,
légendes = nom de l'image, zoom). Remplace Fancybox 2.x + jQuery de l'ancien site. Une lightbox maison
minimale reste un repli possible si l'on veut zéro dépendance tierce.

### D-16 — Page « Mentions légales » activable, à champ HTML unique *(exigence client)*
Ajout d'une page **Mentions légales** :
- Modèle : une entrée de la table `pages` (slug `mentions-legales`).
- **Un seul champ HTML éditable** (`body_html`) en admin ; titre par défaut « Mentions légales ».
- **Activable/désactivable** via le **statut** de la page (`published`/`draft`) — pas de réglage séparé.
- Rendu public : **lien en pied de page** si publiée ; `/mentions-legales` renvoie **404** si masquée.
- SEO : `noindex` par défaut (modifiable).

### D-17 — Racine web = `public_html` (tout à la racine), `.htaccess` durci *(Q-01 tranché)*
Le dépôt est déployé **directement dans `public_html`** : la **racine du projet est la racine web**.
`index.php` (front controller) et les dossiers publics (`admin/`, `assets/`, `media/`) sont à la racine ;
les dossiers **privés** (`config/`, `src/`, `storage/`, `database/`, `docs/`), ne pouvant pas être placés
hors racine, sont **protégés par `.htaccess`** (accès direct interdit). Pas de `DocumentRoot` à déplacer.

### D-18 — Éditeur : **TinyMCE** minimal + sanitization serveur *(Q-02 & Q-03 tranchés)*
**TinyMCE** auto-hébergé (« le plus light » à intégrer, sans build). Barre d'outils **réduite** :
sélecteur de **styles** (Normal, H1, H2, H3…), **gras**, *italique*, **exposant** (+ éventuellement
listes/lien). L'éditeur côté client **n'étant pas** une barrière de sécurité, on applique une
**sanitization serveur** (liste blanche de balises alignée sur la barre) à chaque enregistrement de
champ HTML (galeries, pages, mentions légales).

### D-19 — Pipeline images : 30 Mo, redimensionnement orientation-aware, dérivés par usage *(Q-05 tranché)*
- **Upload jusqu'à 30 Mo** (relever `upload_max_filesize`/`post_max_size` via `.user.ini`/`.htaccess` —
  **à confirmer avec l'hébergeur**, l'actuel plafonne à 2 Mo).
- À l'upload, génération d'une **image « écran »** redimensionnée selon l'**orientation** :
  **paysage** → bornée en **largeur** (ex. ≤ ~1920px) ; **portrait** → bornée en **hauteur**
  (ex. ≤ ~1280px), pour tenir dans l'écran.
- Puis **vignettes/dérivés par usage** (miniature de grille, couverture de tuile…) pour optimiser
  selon l'emplacement d'affichage.
- **Original conservé** (dossier privé `storage/uploads`) pour re-générer les dérivés à la demande.
- Dimensions/recadrage/orientation **configurables par type dans l'admin** + **sortie WebP** (D-26).

### D-20 — Email du contact : **PHPMailer** (SMTP) *(Q-06 tranché)*
Envoi via **PHPMailer** en SMTP. Identifiants SMTP + adresse de destination dans `config/local.php`
(non versionné) ; **configuration détaillée plus tard**.

### D-21 — Anti-spam du contact : honeypot + **Google reCAPTCHA** *(Q-07 tranché)*
Protection en deux temps : **honeypot + horodatage** (sans friction) dès le départ, **+ Google
reCAPTCHA** ; les **clés reCAPTCHA** iront dans `config/local.php` et seront **configurées plus tard**.

### D-22 — Images : **EXIF conservé** + **auteur** injecté selon param admin *(Q-08 tranché)*
On **conserve l'EXIF** dans les dérivés et on **ajoute l'auteur** (champ IPTC/EXIF *Artist*/*Creator*)
d'après un **paramètre d'administration** (`image_author`), pour marquer la paternité des œuvres.

### D-23 — Galeries **plates** (mono-niveau) ; **tags en attente** *(Q-10)*
Pas de galeries imbriquées : structure **plate / mono-galerie**. La piste « tags ? » est **mise en
stand-by** (non retenue pour l'instant). `parent_id` n'est pas utilisé. Si un besoin de regroupement
apparaît plus tard, on pourra ajouter des **tags** (`tags` + `gallery_tags`) sans refonte.

### D-24 — Suppression **et** désactivation (les deux) *(Q-11 tranché)*
Deux mécanismes coexistent : **désactivation** (statut masqué/brouillon, réversible, contenu conservé)
**et suppression définitive** (confirmation explicite + **purge des fichiers et dérivés**). L'admin choisit.

### D-25 — Site **monolingue** au lancement, mais **architecture i18n-ready** *(Q-12 tranché)*
Une seule langue au lancement, **mais conçu pour qu'ajouter une 2ᵉ langue soit facile** : **pas de
chaînes en dur** dans le code, contenus prévus pour être **traduisibles** (mécanisme ajoutable sans
refonte), attribut `lang` piloté par paramètre. **Langue par défaut paramétrable : français ou anglais**
(`default_lang` = `fr`/`en`). Pas de routes/SEO par langue tant que le multilingue n'est pas activé.

### D-26 — Dérivés d'images **configurables par type** dans l'admin (+ WebP) *(Q-09 tranché)*
Le CMS génère plusieurs **types de dérivés** par image — au minimum **vignette**, **normal**,
**plein écran** (+ **couverture** de tuile) — et expose dans l'admin, **par type** :
- **dimensions** (largeur/hauteur cibles),
- **recadrage** (crop) **oui/non** (sinon redimensionnement proportionnel « contain »),
- **gestion de l'orientation** (verticale / horizontale : quelle dimension borne le rendu),
- **sortie WebP oui/non** (en plus du JPEG).

Ces réglages (« **profils d'image** ») sont stockés en base (`image_profiles` ou clé `settings` JSON),
appliqués à l'upload et **regénérables**. Défauts repris de l'existant (plein écran ~1900×1400,
vignette ~400×266, couverture ~400×240 recadrée). Complète D-19 (upload 30 Mo, orientation-aware).

## 2. Hypothèses de travail

- **H-01** Galeries **plates** (mono-niveau, aucune imbrication). Pas de catégorisation pour l'instant ;
  les **tags** restent une piste **en attente** (D-23) ; `parent_id` n'est pas utilisé.
- **H-02** **Un seul administrateur** (l'artiste) suffit ; la table `admins` permet d'en ajouter.
- **H-03** Site **monolingue** au lancement (D-25), **langue par défaut FR ou EN** (`default_lang`),
  mais **architecture i18n-ready** : ajout d'une 2ᵉ langue facilité (contenus traduisibles, pas de
  chaînes en dur). Pas de routes par langue tant que le multilingue n'est pas activé.
- **H-04** Contenu **non versionné en base** : pas de besoin d'historique/brouillons multiples au-delà
  du statut `draft/published`.
- **H-05** Volumétrie faible et stable (~8 galeries, ~100 images) → pas de pagination lourde ni de CDN.
- **H-06** L'hébergement cible reste **cPanel mutualisé** (pas d'accès root, pas de service d'images
  externe, `mail()` disponible).
- **H-07** Le logo et l'image d'accueil (`daniel_tiziani.jpg`) sont récupérables depuis la production
  ou fournis par le client.
- **H-08** Les **originaux** des images sont disponibles dans `image_in/` pour une réimport qualité
  (sinon repli sur les dérivés `img/`).

## 3. Questions ouvertes (à arbitrer avec le client / avant dev)

### Q-01 — Emplacement de la racine web — *tranché (D-17)*
**Tout à la racine** (`public_html`) + `.htaccess` durci protégeant les dossiers privés. Pas de
`DocumentRoot` séparé.

### Q-02 — Éditeur de texte HTML — *tranché (D-18)*
**TinyMCE** auto-hébergé, barre minimale (styles Normal/H1/H2/H3, gras, italique, exposant).

### Q-03 — Sanitization du HTML riche — *tranché (D-18)*
**Liste blanche serveur** alignée sur la barre TinyMCE, appliquée à l'enregistrement (l'éditeur n'est
pas une barrière de sécurité). Bibliothèque (HTML Purifier ou liste blanche maison) à confirmer à l'implémentation.

### Q-04 — Framework front & jQuery — *tranché (D-11)*
Décision proposée : **Bootstrap 5, sans jQuery** (voir D-11). Reste à confirmer par le client.

### Q-05 — Limite d'upload — *tranché (D-19)*
**30 Mo**, puis redimensionnement « écran » orientation-aware + dérivés par usage. La hausse de la
limite est à confirmer côté hébergeur.

### Q-06 — Envoi d'email du contact — *tranché (D-20)*
**PHPMailer** (SMTP) ; configuration et adresse de destination définies plus tard, en config locale.
*(Rappel : `daniel.tiziani@dbmail.com` côté contenu vs `contact@mixer.fr` côté ancien code — à confirmer.)*

### Q-07 — Protection anti-spam du contact — *tranché (D-21)*
**Honeypot + Google reCAPTCHA** ; clés et activation **plus tard** (config locale).

### Q-08 — Conservation des métadonnées EXIF/IPTC — *tranché (D-22)*
**Conserver l'EXIF** + **ajouter l'auteur** selon un paramètre admin (`image_author`).

### Q-09 — Sortie WebP — *tranché (D-26)*
**Oui, générer du WebP** (en plus du JPEG), **activable par type d'image** dans l'admin, avec les
réglages de dimensions / crop / orientation par type.

### Q-10 — Imbrication des galeries — *tranché (D-23)*
**Pas d'imbrication** : galeries **plates (mono-niveau)**. Les **tags** sont **en stand-by** (piste
possible plus tard, non retenue maintenant).

### Q-11 — Suppression vs désactivation — *tranché (D-24)*
**Les deux** : désactivation (statut) et suppression définitive (confirmation + purge des dérivés).

### Q-12 — Multilingue — *tranché (D-25)*
**Monolingue** au lancement, **langue par défaut FR ou EN** (`default_lang`), **architecture prête**
pour ajouter une 2ᵉ langue facilement plus tard.

### Q-13 — Périmètre du pied de page — *orientation donnée, contenu différé*
Direction : pied de page en **2 colonnes** — une colonne « **réf** » (références/infos) et une colonne
« **galeries** ». **Contenu détaillé à définir plus tard.**

### Q-14 — Mécanique du menu mobile : collapse ou off-canvas ? — *tranché (D-12)*
**Off-canvas** retenu (choix client) : au clic, un panneau glisse depuis un bord par-dessus la page
(avec voile), fermé par une croix ou en touchant le voile. BS5 fournit l'off-canvas nativement.
(Diverge du *collapse* de la référence, mais conserve le même principe hamburger → menu.)

### Q-15 — Bibliothèque de lightbox (sans jQuery) — *tranché (D-15)*
**GLightbox** retenu (léger, accessible, sans jQuery, titre = nom de l'image).

### Q-16 — Étendue de la palette de couleurs administrable — *tranché (D-13)*
**6 couleurs** : fond, texte, accent/liens, fond d'en-tête, **fond de pied de page**, **survol**.

### Q-17 — Point de rupture du menu hamburger — *tranché (ajustable)*
**< 992px** par défaut ; pourra être **abaissé** (la nav est très légère). **Fil d'Ariane conservé**
pour le contexte. À décider plus tard : proposer aussi une **nav horizontale** en grand écran, ou
garder le hamburger/off-canvas à toutes les tailles.

## 4. Journal des décisions actées

| Date       | Réf. | Décision | Statut |
|------------|------|----------|--------|
| 2026-06-13 | —    | Phase d'audit réalisée ; 5 documents produits ; aucun code applicatif ni table créés | Acté |
| 2026-06-13 | D-11→D-14 | Exigences client ajoutées : menu hamburger responsive (réf. brunstatt-didenheim, fonctionnement seul), gestion simple des couleurs en admin, framework **Bootstrap 5**, lazy-load paramétrable | Proposé |
| 2026-06-13 | Q-14/15/16, D-13, D-15, D-16 | Arbitrages client : menu mobile **off-canvas** ; lightbox **GLightbox** ; palette **6 couleurs** (+ pied de page, survol) ; ajout **page Mentions légales** (activable, champ HTML unique) | Acté |
| 2026-06-13 | Q-01/02/03/05/06/17 → D-17..D-20 | Arbitrages client : racine `public_html` (.htaccess durci) ; éditeur **TinyMCE** + sanitization serveur ; upload **30 Mo** + image « écran » orientation-aware + dérivés par usage ; **PHPMailer** ; breakpoint <992px (ajustable) + **fil d'Ariane** conservé | Acté |
| 2026-06-13 | Q-07/08/10/11/12 → D-21..D-25, Q-13 | Arbitrages client : anti-spam **honeypot + Google reCAPTCHA** ; **EXIF conservé + auteur** (param admin) ; **galeries plates** (tags en attente) ; **suppression + désactivation** ; **monolingue mais i18n-ready, langue défaut FR/EN** ; pied de page 2 colonnes (réf/galeries, contenu différé) | Acté |
| 2026-06-13 | Q-09 → D-26 | Arbitrage client : **WebP** activable **par type d'image** ; **profils d'image configurables** en admin (dimensions, crop oui/non, orientation V/H) | Acté |

> Les décisions D-01 à D-26 restent **proposées** jusqu'à validation. **Toutes les questions Q-01 à
> Q-17 sont tranchées.** Restent à préciser à l'implémentation : le **contenu** du pied de page
> (Q-13 : 2 colonnes réf/galeries) et quelques détails notés dans les décisions (valeurs par défaut,
> bibliothèque de sanitization, etc.).
