# technical.md — Conventions techniques TCA Industries

> Ce fichier liste les conventions techniques spécifiques au projet TCA Industries.
> Pour les règles SEO et copywriting, voir `CLAUDE.md` section 6.
> Pour le détail des pages, voir `pages.md`.

---

---

## 0. Analyser le moule avant toute action

**Première action de Claude Code au démarrage du projet** : analyser la structure complète du moule Vultek pour comprendre les conventions existantes.

Avant de créer le moindre fichier, parcourir et noter :

- **`templates/`** — quelle organisation des Twig ? composants ? partials ? layouts ?
- **`assets/`** — quel bundler ? quelle structure CSS / JS ? quelles conventions de nommage ?
- **`src/Controller/`** — conventions de routing, attributs ou YAML ?
- **`src/Service/`** — services existants ? helpers ? managers ?
- **`config/`** — packages installés, services configurés, paramètres existants
- **`composer.json`** — bundles déjà présents (SEO, mailer, security, etc.)
- **`package.json`** — dépendances front existantes

**Si la structure du moule diverge de ce qui est décrit dans ce fichier, le moule prime.** Les conventions décrites ci-dessous sont des propositions cohérentes à utiliser uniquement si rien d'équivalent n'existe déjà.

**Reporter à Gabin** :
- La structure réelle du moule
- Les composants déjà disponibles
- Les éventuels conflits avec ce technical.md
- Les ajustements proposés

Gabin valide les ajustements, puis Claude Code adapte ce technical.md aux conventions réelles du moule.

---

## 1. Stack technique

| Élément | Valeur |
|---|---|
| Framework | Symfony 7.4.7 |
| PHP | 8.3+ (le moule est à jour) |
| BDD | MySQL via WAMP (environnement de dev Vultek standard) |
| Templating | Twig |
| ORM | Doctrine |
| Asset bundler | À détecter depuis le moule (Encore ou Vite) |
| CSS | À détecter depuis le moule |
| JS | Stimulus si présent dans le moule, sinon vanilla JS |
| Hébergement prod | OVH ou IONOS — Vincent gère le déploiement |

**Note** : le moule Symfony de Vultek est propre et à jour. Claude Code doit l'analyser au démarrage du projet et respecter les conventions existantes plutôt que d'en créer de nouvelles. Si une convention semble manquante, demander à Gabin avant de l'inventer.

---

## 2. Structure des dossiers

> **⚠️ RÈGLE PRIORITAIRE pour Claude Code** : avant toute création de fichier ou de dossier, **analyser la structure existante du moule Symfony Vultek**. Le moule a ses propres conventions de nommage et d'organisation (templates, assets, controllers, services). Claude Code doit respecter ces conventions plutôt que d'imposer celles décrites ci-dessous.
>
> Les structures listées dans les sections 2.1, 2.2 et 2.3 sont des **propositions cohérentes** à utiliser **uniquement si le moule n'a pas déjà une organisation équivalente**. Si le moule a déjà :
> - Un système de partials Twig → utiliser celui-là, ne pas créer un dossier parallèle
> - Une organisation CSS existante → l'étendre, pas la doubler
> - Des composants UI réutilisables → les compléter, pas les remplacer
> - Un service SEO ou similaire → l'utiliser, pas en créer un nouveau
>
> **En cas de doute, demander à Gabin avant de créer une nouvelle structure de dossiers.**

### 2.1 Templates Twig

Organisation modulaire à respecter dès le départ pour préparer la croissance du site :

```
templates/
├── base.html.twig                    Layout global
├── _partials/                        Éléments réutilisables structurels
│   ├── header.html.twig
│   ├── footer.html.twig
│   ├── breadcrumb.html.twig
│   └── nav.html.twig
├── _components/                      Composants UI réutilisables
│   ├── hero.html.twig
│   ├── service-card.html.twig
│   ├── article-card.html.twig
│   ├── faq-accordion.html.twig
│   ├── cta-block.html.twig
│   └── form-contact.html.twig
├── _seo/                             Composants SEO réutilisables
│   ├── meta-tags.html.twig           Title, description, canonical, OG, Twitter
│   ├── schema-local-business.html.twig
│   ├── schema-service.html.twig
│   ├── schema-faq.html.twig
│   ├── schema-article.html.twig
│   ├── schema-breadcrumb.html.twig
│   └── schema-organization.html.twig
├── pages/                            Pages spécifiques
│   ├── home.html.twig
│   ├── service.html.twig             Template réutilisé pour les 10 pages services
│   ├── about.html.twig
│   └── contact.html.twig
├── blog/
│   ├── index.html.twig               Liste des articles
│   └── article.html.twig             Article individuel
└── legal/
    ├── mentions-legales.html.twig
    ├── politique-confidentialite.html.twig
    └── 404.html.twig
```

### 2.2 Assets CSS

Organisation modulaire pour anticiper la croissance future (back-office, multilangue, etc.) :

```
assets/styles/
├── common/                           Chargé sur tout le site
│   ├── variables.css                 Couleurs, fontes, breakpoints
│   ├── reset.css
│   ├── typography.css
│   └── utilities.css
├── components/                       Composants UI partagés
│   ├── buttons.css
│   ├── cards.css
│   ├── accordion.css
│   ├── form.css
│   └── hero.css
├── front/                            Chargé uniquement sur le front public
│   ├── home.css
│   ├── service-page.css
│   ├── about.css
│   └── contact.css
└── blog/                             Chargé uniquement sur le blog
    ├── listing.css
    └── article.css
```

**Logique** : si le site grossit plus tard avec un back-office, on rajoutera `assets/styles/admin/` sans toucher au reste. Si on ajoute une langue, les composants restent partagés.

### 2.3 Assets JS

```
assets/js/
├── app.js                            Point d'entrée
├── controllers/                      Stimulus controllers
│   ├── faq-accordion_controller.js
│   ├── mobile-menu_controller.js
│   ├── smooth-scroll_controller.js
│   └── contact-form_controller.js
└── utils/
    └── analytics.js                  GA4 events helpers
```

### 2.4 Controllers PHP

```
src/Controller/
├── HomeController.php
├── ServiceController.php             Gère les 10 pages services dynamiquement
├── AboutController.php
├── ContactController.php
├── BlogController.php
├── LegalController.php
├── SitemapController.php             Génère sitemap.xml dynamiquement
└── RobotsController.php              Sert robots.txt
```

---

## 3. Services SEO

> **⚠️ Avant de créer un nouveau service** : vérifier dans le moule s'il existe déjà un service équivalent (SeoManager, MetaService, SchemaBuilder, SitemapGenerator, etc.). Si oui, l'utiliser ou l'étendre. Si non, créer les services ci-dessous.

Si le moule n'a pas de services SEO, Claude Code crée ces 4 services :

### 3.1 SeoService

Gère les métadonnées par page : title, meta description, canonical, Open Graph.
- Stockage des métadonnées par route (ex : YAML config ou attributs PHP)
- Pas de hardcoding dans les templates
- Méthode `getMetaTags(string $route): array`

### 3.2 SchemaService

Génère les JSON-LD selon le type de page.
- Méthodes par schema : `localBusiness()`, `service()`, `faq()`, `article()`, `breadcrumb()`, `organization()`
- Retourne un tableau PHP transformé en JSON dans le template
- Valide la structure avant rendu

### 3.3 SitemapService

Génère le sitemap.xml dynamiquement.
- Liste les pages indexables (12 piliers + Contact + articles blog publiés)
- Exclut les pages noindex (mentions légales, politique de confidentialité, 404)
- Update automatique à chaque publication d'article (event Doctrine)
- Sortie format sitemap protocol 0.9 valide

### 3.4 BreadcrumbService

Construit la liste du fil d'Ariane par page.
- Méthode `build(string $route, array $context = []): array`
- Retourne un tableau ordonné : [['name' => 'Accueil', 'url' => '/'], ...]
- Utilisé par le template `_partials/breadcrumb.html.twig` ET le schema BreadcrumbList

---

## 4. Routing

### 4.1 Conventions

- Noms de routes en anglais (`home`, `service_index`, `about`, `contact`, `blog_index`, `blog_article`)
- Slugs publics en français selon `pages.md`
- Trailing slash cohérent : avec trailing slash pour toutes les pages
- Pas de paramètres GET dans les URLs indexables

### 4.2 Routes principales

```yaml
home:
  path: /
  controller: App\Controller\HomeController::index

service_show:
  path: /{slug}/
  controller: App\Controller\ServiceController::show
  requirements:
    slug: 'reparation-moteur-electrique|bobinage-moteur-electrique|reducteurs-motoreducteurs|pompes-industrielles|pompe-piscine-relevage|reparation-pompe-immergee|variateurs-de-vitesse|transmissions-mecaniques|maintenance-industrielle|fournitures-industrielles'

about:
  path: /a-propos/
  controller: App\Controller\AboutController::index

contact:
  path: /contact/
  controller: App\Controller\ContactController::index

blog_index:
  path: /blog/
  controller: App\Controller\BlogController::index

blog_article:
  path: /blog/{slug}/
  controller: App\Controller\BlogController::show
```

### 4.3 Pages légales

```yaml
mentions_legales:
  path: /mentions-legales/
politique_confidentialite:
  path: /politique-confidentialite/
```

### 4.4 SEO système

```yaml
sitemap:
  path: /sitemap.xml
  controller: App\Controller\SitemapController::index
robots:
  path: /robots.txt
  controller: App\Controller\RobotsController::index
```

---

## 5. Performance — objectif Lighthouse 100/100

### 5.1 Côté code

- CSS et JS minifiés via le bundler (Encore ou Vite)
- Code splitting si possible (charger uniquement le JS dont la page a besoin)
- Critical CSS inliné pour le hero
- Polices auto-hébergées avec `font-display: swap`
- Preload sur la police principale + image hero de la page courante
- Images en WebP avec fallback PNG/JPG via `<picture>`
- Lazy loading natif sur images hors viewport (`loading="lazy"`)
- `width` et `height` définis sur toutes les images (anti-CLS)
- Pas de scripts tiers bloquants (GA4 en defer)

### 5.2 Côté serveur (à transmettre à Vincent)

- Compression gzip ou brotli activée
- Cache navigateur long sur `/build/` et `/images/` (1 an)
- HTTP/2 activé (indispensable pour Lighthouse 100)
- `APP_ENV=prod` et `APP_DEBUG=0` en production
- OPcache PHP activé
- Cache Symfony warmupé après chaque déploiement

### 5.3 Images

Pipeline à mettre en place :
- Source : photos pro depuis le drive
- Stockage dans `public/images/` organisé par thème (`atelier/`, `team/`, `services/`, `hero/`)
- Conversion WebP automatique à l'upload (ou pré-conversion manuelle si pas de back-office)
- Nommage descriptif kebab-case : `reparation-moteur-electrique-atelier-tca.webp`
- Tailles optimisées : moins de 150 Ko par image, 300 Ko max pour le hero

---

## 6. Formulaire de contact

### 6.1 Comportement

- Action côté serveur : envoi d'un email à l'adresse TCA (à compléter depuis `client.md` section 2)
- Pas de stockage en BDD pour démarrer (sauf si TCA demande l'historique des demandes plus tard)
- Confirmation visuelle à l'utilisateur sans rechargement de page (AJAX léger ou redirect vers `/contact/?success=1`)
- Email envoyé via Symfony Mailer

### 6.2 Champs

- Nom (requis)
- Prénom (requis)
- Email (requis, validation format)
- Téléphone (requis, format français)
- Sujet (liste déroulante : Urgence dépannage / Demande de devis / Renseignement produit / Autre)
- Message (requis, min 20 caractères)
- Honeypot anti-spam invisible (champ caché type "website" qui doit rester vide)

### 6.3 Sécurité

- Protection CSRF via Symfony Form (token automatique)
- Honeypot anti-spam (champ invisible)
- Pas de reCAPTCHA pour démarrer (UX dégradée + impact Lighthouse). Ajouter hCaptcha si trop de spam apparaît
- Rate limiting au niveau du contrôleur (max 3 soumissions par IP par minute)
- Validation serveur stricte sur tous les champs

### 6.4 Tracking

- Événement GA4 `contact_form_submit` au succès
- Événement GA4 `phone_click` sur clic numéro

---

## 7. Génération du contenu

### 7.1 Pages services — gestion technique

Les 10 pages services partagent le même template `pages/service.html.twig`. Deux approches possibles :

**Option recommandée** : fichiers YAML par service dans `config/services/`
```yaml
# config/services/reparation-moteur-electrique.yaml
slug: reparation-moteur-electrique
h1: "Réparation et remise en état de moteurs électriques"
title: "Réparation Moteur Électrique Clermont-Ferrand — TCA Industries"
description: "Nous réparons et rebobinons..."
primary_keyword: "réparation moteur électrique"
content_path: "content/services/reparation-moteur-electrique.html.twig"
faq_path: "content/faq/reparation-moteur-electrique.yaml"
```

Le ServiceController charge le YAML par slug, charge le contenu Twig partiel, et rend le template `pages/service.html.twig`.

Cette approche permet à Claude Code (ou Gabin plus tard) de créer une nouvelle page service en ajoutant juste un YAML + un Twig partiel, sans toucher au code.

### 7.2 Blog — gestion technique

**À démarrer en simple** :
- Articles en Markdown ou Twig dans `content/blog/`
- Métadonnées dans front-matter YAML
- Pas de back-office au démarrage — Gabin/TCA publient via Git

**À envisager plus tard si le client veut éditer lui-même** :
- Entité Doctrine `Article` avec champs : title, slug, content, publishedAt, updatedAt, author, category, image
- Back-office EasyAdmin ou KaboomAdmin (selon préférence Vultek)
- Migration vers la BDD = à anticiper mais pas obligatoire au lancement

---

## 8. Conventions de code

- Code en anglais (variables, méthodes, classes, commentaires)
- Copywriting visible en français
- PSR-12 par défaut
- Pas d'introduction de bibliothèques lourdes sans validation Gabin
- Pas de migration Doctrine sans validation Gabin (cf. CLAUDE.md règle absolue)
- Commits en anglais, mode impératif, Conventional Commits

---

## 9. Tracking et analytics

### 9.1 Google Analytics 4

- Tag GA4 chargé en defer dans le head
- ID GA4 à fournir par Gabin (configurable via `.env`)
- Événements de conversion à tracker :
  - `contact_form_submit` (soumission formulaire)
  - `phone_click` (clic sur numéro de téléphone)
  - `quote_request` (clic CTA "Demander un devis")

### 9.2 Google Search Console

- Vérification de propriété via balise meta dans `<head>` (token à fournir par Gabin)
- Sitemap soumis manuellement après mise en ligne

### 9.3 Pas de tracking tiers supplémentaire

- Pas de Facebook Pixel, Hotjar, etc., au lancement
- À ajouter uniquement sur demande explicite de TCA

---

## 10. Sécurité de base

- HTTPS uniquement en production (HSTS via Vincent côté serveur)
- Headers de sécurité : `X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`, `Referrer-Policy: strict-origin-when-cross-origin`
- CSP (Content Security Policy) à définir selon les besoins (GA4, Google Maps, polices)
- Pas de version PHP/Symfony exposée dans les headers
- `.env.local` jamais commité (déjà dans `.gitignore` standard)

---

## 11. Points à valider avec Vincent (déploiement)

Liste à transmettre à Vincent pour le déploiement production :

- Activation gzip ou brotli au niveau Apache/Nginx
- HTTP/2 obligatoire
- Cache navigateur long sur `/build/` et `/public/images/` (max-age=31536000, immutable)
- Headers de sécurité (HSTS, X-Content-Type-Options, etc.)
- Redirect www vers non-www (ou inverse selon préférence)
- HTTPS forcé (redirect 80 vers 443)
- Certificat SSL valide
- `php.ini` : OPcache activé, memory_limit raisonnable
- Cron pour : warmup cache Symfony après deploy
- Logs accessibles pour debug si besoin
- Backup quotidien (minimum BDD si une est utilisée)

---

## 12. Ce que Claude Code doit demander à Gabin avant de faire

Liste à respecter strictement :

- Ajouter une dépendance npm ou composer
- Modifier le schéma BDD (créer une entité, ajouter un champ)
- Lancer une migration Doctrine (cf. CLAUDE.md — règle absolue interdite)
- Supprimer un fichier
- Modifier les URLs définies dans `pages.md`
- Modifier les conventions de nommage de ce fichier
- Ajouter un service tiers (CDN, CRM, etc.)
- Implémenter un back-office (non prévu au lancement)

---

**Fin du fichier technical.md** — ce fichier décrit les conventions techniques du projet TCA Industries. Toute évolution doit être validée avec Gabin avant intégration.
