# Spécifications fonctionnelles détaillées — Walk The Line Management

**Version fonctionnelle documentée : V16.11.16**  
**Application : Symfony 7.4 / PHP 8.2+**

## 1. Objet et principes directeurs

Walk The Line Management est un back-office associatif multi-projets destiné à centraliser le cycle de vie commercial, administratif, technique, documentaire et financier de plusieurs projets artistiques gérés par une même association.

L'application applique quatre niveaux de données :

1. **Association** : identité légale, utilisateurs, comptabilité, comptes financiers, conventions, facturation, documents transversaux.
2. **Projet artistique** : identité visuelle légère, tarifs, frais, prospections, dates, technique, plans de scène, préparation du site public.
3. **Données partagées** : lieux et contacts réutilisables par tous les projets.
4. **Documents historiques** : PDF générés et pièces comptables conservés de manière immuable ou versionnée selon leur nature.

Principes UX :
- rendre le projet actif visible à tout moment ;
- présenter une action principale évidente par écran et reléguer les options avancées ;
- utiliser pages, actions contextuelles, panneaux ou modales selon le parcours, sans imbriquer de modales ;
- automatiser les classements calculables ;
- éviter les doubles saisies et réuploads ;
- rendre les écrans utilisables par un non-informaticien ;
- proposer sur smartphone des cartes métier et des zones tactiles d'au moins 44 px plutôt qu'une simple réduction des tableaux ;
- conserver l'historique plutôt que remplacer silencieusement les objets déjà utilisés.

---

## 2. Utilisateurs, rôles et sécurité

### 2.1 Hiérarchie

- `ROLE_USER` : rôle de base ;
- `ROLE_PRESSE` : accès presse, hérite de `ROLE_USER` ;
- `ROLE_ADMIN` : accès au back-office, hérite de `ROLE_PRESSE` ;
- `User.isSuperAdmin` : drapeau additionnel pour les opérations sensibles.

### 2.2 Super administrateur

Le super administrateur peut notamment :
- gérer les utilisateurs ;
- créer et administrer les projets artistiques ;
- supprimer certaines données opérationnelles lorsque les règles métier l'autorisent ;
- utiliser la maintenance ;
- importer/exporter les lieux et contacts ;
- réinitialiser les données de démonstration.

Les contrôles sont réalisés côté serveur et non uniquement par masquage des boutons.

Un compte non super-admin qui possède des permissions de back-office doit être associé à au moins un projet. Son authentification peut réussir, mais l'accès à `/admin` est refusé tant que cette association manque, avec un message invitant à contacter un administrateur. Le compte presse autonome reste orienté vers l'espace presse.

Le reCAPTCHA du login est global à l'application (`LOGIN_RECAPTCHA_SITE_KEY` et `LOGIN_RECAPTCHA_SECRET_KEY`) et ne dépend jamais du domaine, du projet courant ou du premier projet trouvé. Les formulaires publics conservent leur configuration reCAPTCHA propre à chaque projet.

---

## 3. Architecture multi-projets

### 3.1 Entité `ArtisticProject`

Un projet artistique représente un groupe, spectacle ou projet solo géré par l'association.

Données principales :
- code ;
- nom ;
- slug ;
- statut `DRAFT`, `ACTIVE`, `ARCHIVED` ;
- couleur principale ;
- couleur secondaire ;
- identité documentaire ;
- paramètres du futur site public ;
- informations de complétude.

### 3.2 Projet actif

Un service de contexte conserve le projet actif pour la navigation du back-office.

Le projet actif est :
- affiché en permanence dans la barre latérale ;
- rappelé dans l'en-tête des pages contextualisées ;
- identifié par ses couleurs ;
- modifiable par le sélecteur `Changer de projet`.

### 3.3 Données propres au projet

Sont notamment contextualisés :
- prospections ;
- dates de concert ;
- tarifs ;
- frais annexes ;
- profils techniques ;
- paramètres techniques ;
- patch audio ;
- matériel ;
- intentions / effets ;
- accueil technique ;
- blocs rédactionnels ;
- éléments scéniques spécifiques ;
- plans de scène ;
- fiches techniques ;
- documents propres au projet ;
- configuration publique.

### 3.4 Données communes

Restent communes à l'association :
- lieux ;
- contacts ;
- utilisateurs ;
- modèles de convention ;
- numérotation des devis/factures ;
- comptabilité ;
- comptes financiers ;
- bibliothèque documentaire transversale.

### 3.5 Navigation du back-office

Sur desktop, la navigation latérale regroupe les fonctions par usage et conserve un accès visible au projet actif. Sur smartphone, la barre principale est stable : **Accueil · À traiter · Saisir · Prospections · Plus**. Une entrée non autorisée est masquée ; elle n'est jamais remplacée dynamiquement par une autre fonction. Le menu **Plus** donne accès aux fonctions secondaires permises.

Les listes denses de prospections, lieux et dates utilisent des cartes métier sur smartphone et conservent un tableau sur les grands écrans. Les actions secondaires sont regroupées dans un menu contextuel. Les messages de résultat sont annoncés aux technologies d'assistance, le focus clavier reste visible et un lien d'évitement permet d'aller directement au contenu.

Ce principe s'applique également aux documents commerciaux, conventions, documents techniques, plans de scène, bibliothèque documentaire, factures à encaisser, mouvements, dépenses, recettes, merchandising, contrats, comptes financiers, utilisateurs et groupes de permissions. Sur mobile, le tableau desktop est remplacé par une carte métier lorsque la comparaison en colonnes n'est pas l'objectif principal. La matrice de permissions conserve sa vue tabulaire desktop et propose une vue par groupe sur smartphone.

Les modales longues conservent une surface continue, un corps défilant et des actions accessibles quelle que soit la hauteur de l'écran. Le formulaire interne ne peut pas déborder visuellement du fond de la modale.

Le back-office est installable sur l'écran d'accueil comme une Progressive Web App. Son manifeste démarre sur `/admin` et limite l'expérience installée au back-office. L'application reste volontairement dépendante du réseau : le service worker ne met en cache ni page métier, ni réponse, ni donnée personnelle. Une indisponibilité réseau suit donc les mécanismes de reprise des formulaires déjà décrits, sans promettre un fonctionnement hors ligne.

---

## 4. Création d'un projet artistique

La création est réservée au super administrateur et suit un wizard long mais guidé.

### 4.1 Préambule

Une page introductive explique les informations à préparer : identité, logos, couleurs, tarifs, frais, technique, patch, matériel, accueil, éléments scéniques, plans et site public.

### 4.2 Brouillon et reprise

Le projet est créé en statut `DRAFT`.

Le wizard :
- sauvegarde la progression ;
- peut être interrompu ;
- peut être repris ultérieurement ;
- permet de revenir sur les étapes déjà visitées.

### 4.3 Préremplissage

Pour réduire la saisie initiale, certaines configurations peuvent être reprises comme base depuis le projet de référence, puis deviennent indépendantes du projet source.

### 4.4 Complétude

Le système expose trois états :
- **Prêt pour la prospection** ;
- **Prêt pour la production** ;
- **Prêt pour le site public**.

La complétude n'empêche pas nécessairement l'usage partiel du projet : un projet peut commencer sa prospection avant que son site public soit terminé.

---

## 5. Référentiel des lieux et contacts

### 5.1 `Venue`

Un lieu est durable et partagé entre tous les projets.

Informations principales :
- nom / raison sociale ;
- type ;
- adresse ;
- ville / CP / pays ;
- jauge ;
- budget indicatif ;
- SIRET / TVA ;
- e-mail de facturation ;
- site ;
- notes administratives ;
- statut ;
- identifiant externe.

Statuts : `ACTIVE`, `CLOSED`, `ARCHIVED`.

### 5.2 `VenueContact`

Un lieu possède plusieurs contacts :
- identité / fonction ;
- type de contact ;
- e-mail ;
- téléphone ;
- principal ou secondaire ;
- notes ;
- identifiant externe.

La sélection des contacts d'une prospection est filtrée par lieu et le contact principal peut être présélectionné automatiquement.

Un lieu peut être créé sans contact. Dès qu'un contact est créé, son nom et au moins un moyen de contact parmi téléphone et e-mail sont obligatoires. L'application ne crée jamais de faux contact pour compléter une fiche.

### 5.3 Nouveau contact terrain

L'action **Nouveau contact terrain** orchestre les entités existantes sans créer de modèle parallèle. Elle permet de retrouver ou créer un lieu, de sélectionner ou créer un contact, puis de choisir explicitement l'intention :

1. enregistrer uniquement le lieu et le contact éventuel ;
2. créer une prospection dont le premier contact reste à faire ;
3. créer une prospection avec **Premier échange réalisé maintenant**.

Le troisième choix est présélectionné uniquement dans ce parcours et reste visible et modifiable avant validation. Une création effectuée ailleurs n'est jamais assimilée automatiquement à un premier contact.

Les doublons sont contrôlés côté serveur : un SIRET identique bloque la création et propose le lieu existant ; un nom et une ville identiques provoquent un avertissement fort avec création forcée possible pour un utilisateur autorisé ; une correspondance approchée avertit sans bloquer. L'invariant d'une seule prospection active par projet et lieu reste appliqué.

La saisie est enregistrée en une opération transactionnelle. En cas d'échec réseau, les valeurs restent dans le formulaire et l'utilisateur peut réessayer ; aucune donnée personnelle n'est stockée par défaut dans `localStorage`. La cible ergonomique est une saisie lieu + contact + prospection en moins d'une minute sur téléphone avec les informations essentielles.

---

## 6. Prospection

### 6.1 Entité centrale

`Prospection` représente une campagne commerciale propre à un projet artistique et à un lieu.

Pour un couple projet + lieu, une seule prospection active peut exister. `REFUSED`, `CANCELLED_AFTER_CONFIRMATION`, `COMPLETED` et `NOT_RELEVANT` sont terminaux ; `FUTURE_RECONTACT` reste actif. Après un refus, une nouvelle démarche crée une nouvelle prospection. Après une annulation, le même dossier peut être réactivé pour être reprogrammé.

Les statuts possèdent un code technique stable et unique, distinct du libellé affiché. Le workflow ne doit jamais rechercher un statut à partir de son libellé français. Les codes fonctionnels sont notamment : `TO_IDENTIFY`, `TO_CONTACT`, `INITIAL_CONTACT_SENT`, `FOLLOWUP_1_SENT`, `FOLLOWUP_2_SENT`, `IN_DISCUSSION`, `PROPOSAL_SENT`, `AGREEMENT_CONFIRMED`, `DATE_SCHEDULED`, `REFUSED`, `NOT_RELEVANT`, `FUTURE_RECONTACT`, `CANCELLED_AFTER_CONFIRMATION` et `COMPLETED`. Les anciens statuts inconnus sont conservés sous un code `LEGACY_<id>`.

### 6.2 Wizard de création

Trois étapes :
1. **Lieu** : lieu + priorité ;
2. **Contact** : contact ciblé + canal + premier contact ;
3. **Suivi** : statut, relances, tarif proposé, accueil, chapeau, notes.

Les contacts sont chargés dynamiquement au passage de l'étape 1 à l'étape 2.

Dans l'interface courante, les informations essentielles sont affichées en premier et les champs avancés restent repliés jusqu'à leur ouverture. La liste mobile utilise des cartes donnant directement accès au dossier et à la prochaine action ; les documents lourds ne sont pas préchargés depuis la liste.

### 6.3 Historique et responsabilité

`ProspectionEvent` conserve les événements et l'utilisateur associé lorsque disponible.

Responsabilités suivies : créateur, premier contact, relances, proposition, décision, date réalisée, etc.

Le cycle distingue : proposition envoyée, accord commercial obtenu (`agreementDate`, `agreementBy`), date effectivement programmée (`confirmedDate`), puis cycle terminé. Un accord peut donc exister sans date. Les données anciennes ne reçoivent pas d'`agreementDate` inventée.

`REFUSED` décrit uniquement un refus commercial avant accord. Après accord ou programmation, l'abandon est une annulation `CANCELLED_AFTER_CONFIRMATION` : accord et ancienne date sont conservés, le motif et l'auteur sont historisés, la date liée est annulée et la prochaine action est vidée. L'action explicite de reprogrammation fait revenir le dossier à `AGREEMENT_CONFIRMED`, puis à `DATE_SCHEDULED` si une nouvelle date est immédiatement connue.

Les transitions déclenchées par les e-mails sont monotones : un ancien modèle renvoyé ne peut pas faire régresser le statut, les premières dates de jalon restent conservées, chaque envoi réussi est journalisé et aucun état terminal n'est quitté automatiquement.

### 6.4 Prochaine action

`ProspectionScheduleService` calcule automatiquement la prochaine action à partir des dates et règles configurées.

Une action métier effectivement accomplie consomme `postponeUntil` puis recalcule immédiatement `nextActionDate` : contact, relance, réponse, proposition envoyée avec succès, accord, programmation, refus, annulation ou représentation jouée. La génération d'un devis, une consultation, une modification descriptive, un changement de visibilité ou un échec SMTP ne consomment pas le report.

### 6.5 Suggestions

`ProspectionSuggestionService` calcule les lieux à prospecter/recontacter à partir de l'historique, du délai d'inactivité, du budget et des contacts.

### 6.6 Statistiques

Deux lectures sont distinctes :

- le tunnel historique cumulatif compte les jalons réellement atteints (contacts, propositions envoyées, accords obtenus, dates programmées, représentations jouées). Une annulation ultérieure n'efface pas un accord historique ;
- le stock courant compte les états présents (programmées, annulées, jouées, etc.). Une date annulée n'est plus dans le stock « actuellement programmées ».

### 6.7 Suppression

La suppression d'une prospection est réservée au super-admin et orchestrée explicitement. La date associée et les dépendances supprimables sont nettoyées ; les PDF spécifiques suivent les règles de conservation, les modèles partagés ne sont jamais supprimés et la présence de documents comptables conservables bloque la suppression.

La suppression distante Google Calendar est tentée avant la suppression locale. En cas d'échec, le super-admin reçoit un avertissement et peut forcer la suppression locale. Une trace conserve l'identifiant d'événement, le calendrier, le projet, la date et l'erreur afin de permettre le nettoyage manuel ultérieur.

---

## 7. Dates de concert

### 7.1 `ConcertDate`

Une date programmée est distincte de l'accord commercial et rattachée à la prospection et au projet. Toute modification synchronise `Prospection.confirmedDate`, recalcule immédiatement `nextActionDate`, historise ancienne et nouvelle valeurs, puis synchronise Google Calendar après la transaction locale. Une date jouée ou annulée reste sans prochaine action.

La création utilise une page dédiée sans modale imbriquée. Le premier niveau demande uniquement le lieu, le jour, l'heure de début éventuelle et le mode de publication ; horaires détaillés, contenu public, confidentialité, affiche et liens sont regroupés dans les options avancées. Une erreur de validation restitue les valeurs textuelles déjà saisies. Les actions de la liste sont regroupées dans un menu et les dates sont présentées sous forme de cartes métier sur smartphone.

Données :
- lieu ;
- date et horaires ;
- titre / description publics ;
- affiche ;
- billetterie / réservation / lien externe ;
- visibilité ;
- publication différée ;
- complet ;
- mise en avant ;
- annulation ;
- report ;
- slug.

### 7.2 Historique de report

`ConcertDateHistory` conserve ancienne date, nouvelle date, motif, date du changement et utilisateur.

Une date annulée déjà publiée reste publique par défaut jusqu'à sa date et affiche clairement « ANNULÉE » ; l'utilisateur peut la masquer manuellement. Une date reportée puis finalement jouée peut apparaître dans les archives : le marqueur historique de report ne l'exclut pas.

### 7.3 Préparation du site public

Les repositories distinguent dates publiées à venir et archives. Le frontend est résolu par domaine/projet via `ArtisticProjectDomain`.

Lorsque `showPublicVenue = false`, aucune donnée générée automatiquement ne révèle le lieu : titre automatique, accueil, listes, archives, page Dates et JSON-LD utilisent une présentation centralisée sans nom de lieu. Les textes libres restent sous la responsabilité de l'utilisateur et l'interface avertit du risque de divulgation.

### 7.4 Bilan de représentation

Une représentation passée et non annulée peut recevoir un unique **Bilan de représentation** complet. Ce bilan reprend le questionnaire historique en 48 colonnes : contexte de la date et du lieu, public, accueil et technique, réception du spectacle, auto-évaluation, retours professionnels, suites commerciales, synthèse et notes. Il n'existe pas de variante « retour rapide ».

Le projet du bilan est toujours déduit de sa `ConcertDate` : il n'est jamais choisi ni accepté depuis une valeur envoyée par le navigateur. Les listes, statistiques, formulaires, accès directs et exports sont limités au projet actif. Le droit `CONCERT_FEEDBACK` distingue lecture et écriture ; seule la suppression physique est réservée au super-admin.

Le bilan peut être créé à partir du menu, d'une date ou de la prospection liée. Si un bilan existe déjà, l'action ouvre sa consultation ou sa modification au lieu d'en créer un second. La règle est garantie à la fois par le service métier et par une contrainte SQL unique sur `concert_date_id`.

La saisie utilise un assistant en six étapes, sans enregistrement intermédiaire :

1. représentation et public ;
2. accueil et conditions techniques ;
3. réception du spectacle ;
4. auto-évaluation artistique et physique ;
5. retours du lieu, opportunités et prochaine action ;
6. synthèse, notes globales et enseignements.

Toutes les réponses du questionnaire sont facultatives : un bilan peut être enregistré puis complété progressivement, sans fabriquer de valeur `0` ou de réponse par défaut. Seule la sélection de la représentation est indispensable lorsque le bilan n'est pas ouvert depuis une date, car elle détermine son projet et garantit l'unicité. Les statistiques ignorent les notes non renseignées et l'export conserve des cellules vides.

La validation reste entièrement côté serveur ; l'assistant JavaScript ne fait que présenter les étapes et signaler les valeurs renseignées mais invalides. Une erreur conserve les réponses et ramène vers le premier champ concerné. Les utilisateurs disposant de l'écriture peuvent modifier le bilan. `createdAt` et `createdBy` restent inchangés ; `updatedAt` et `updatedBy` identifient la dernière modification.

Lorsqu'il existe, le détail du bilan est affiché directement en bas de la fiche Prospection. Depuis la liste des Dates, il est consultable dans une fenêtre chargée à la demande, sans quitter le planning. Ces deux présentations utilisent le même composant de lecture et appliquent la permission `CONCERT_FEEDBACK` ainsi que la portée du projet actif.

Les listes sont filtrables et triables sur ordinateur, avec une présentation en cartes sur smartphone. Les indicateurs synthétiques et l'export ne mélangent jamais plusieurs projets. L'export Excel contient une feuille et reproduit strictement les 48 intitulés et leur ordre historique, définis par `ConcertFeedbackChoices::EXPORT_HEADERS` ; les réponses codées sont exportées avec leurs libellés lisibles.

La relation vers la date utilise `ON DELETE RESTRICT`. L'application bloque donc explicitement la suppression d'une date, de la prospection qui la porte ou du lieu dont la suppression entraînerait celle de la date tant que le bilan existe, avant toute synchronisation Google Calendar. Le message demande au super-admin de supprimer d'abord le bilan depuis sa fiche. La suppression d'un compte utilisateur conserve le bilan et met seulement ses références auteur à `NULL`.

---

## 8. Tarification et frais annexes

Les tarifs et frais annexes sont propres au projet actif.

Le simulateur calcule les composantes suivantes :
- formule / cible ;
- trajet / stationnement ;
- repas / nuit artiste et accompagnateur ;
- techniciens supplémentaires ;
- options ;
- autres frais ;
- remise commerciale.

Les paramètres sont éditables dans le back-office.

Depuis une prospection, le simulateur reçoit le contexte du dossier autorisé et peut reporter le résultat vers celui-ci. Ce contexte est vérifié côté serveur contre le projet actif et la permission d'écriture. L'interface mobile place le résultat avant les réglages et replie les frais et options avancés sans dupliquer le calcul métier en JavaScript.

---

## 9. Devis et factures

### 9.1 `CommercialDocument`

Deux types principaux :
- devis ;
- facture.

Numérotation annuelle indépendante :
- `D-AA-XXXX` ;
- `F-AA-XXXX`.

La numérotation reste commune à l'association.

### 9.2 Génération PDF

Les PDF :
- utilisent les données figées du document ;
- intègrent l'identité documentaire du projet ;
- restent immuables une fois générés ;
- sont stockés via `Document` / `DocumentContent`.

La génération d'un devis crée et fige le document, peut mettre à jour le montant proposé et écrit l'événement `quote_generated`. Elle ne renseigne ni `proposalSentDate` ni `proposalBy`, ne pose pas `PROPOSAL_SENT` et ne consomme pas un report. Le jalon « Proposition envoyée » n'est posé qu'après succès SMTP d'un e-mail contenant le devis ou après l'action explicite « Marquer la proposition comme envoyée ». Le devis envoyé conserve `sentAt` et `sentBy`. Les anciens jalons issus du comportement historique « génération = envoi » sont conservés sans correction rétroactive.

L'interface présente explicitement la séquence **Généré → Envoyé → Facturé**. L'action d'envoi ouvre le module d'e-mail de la prospection et présélectionne le PDF du devis ; la politique serveur des pièces jointes reste appliquée au chargement comme à l'envoi.

### 9.3 Conversion devis → facture

Une facture est générée à partir d'un devis existant.

Un devis donne naissance à au maximum une facture. L'invariant est protégé par le service métier, une transaction avec verrou, le contrôleur et une contrainte SQL unique. La migration s'arrête si elle rencontre un doublon historique ; elle ne choisit ni ne supprime aucune facture automatiquement.

À sa création :
- le PDF est figé ;
- le document est automatiquement référencé dans la GED comptable ;
- aucun réupload manuel n'est nécessaire.

---

## 10. Paiements et statut des factures

### 10.1 `Payment`

Un paiement est lié à une facture et contient notamment :
- date ;
- montant ;
- compte financier ;
- moyen de paiement ;
- référence ;
- notes ;
- exercice et période comptables.

Une facture peut recevoir plusieurs paiements.

### 10.2 Statut calculé

Le statut est dérivé du total encaissé :
- **À encaisser** ;
- **Partiellement payée** ;
- **Payée**.

### 10.3 Accès rapides

L'enregistrement d'un paiement est possible depuis :
- la fiche facture ;
- `Devis & factures` ;
- la liste des prospections si une vraie facture existe ;
- le dashboard projet ;
- le dashboard comptable.

### 10.4 Correction

Un paiement peut être modifié ou supprimé. Le statut de facture et le classement comptable sont recalculés. Un contrôle empêche de dépasser le total TTC de la facture.

---

## 11. Conventions

Les `ConventionTemplate` sont communs à l'association.

Une `Convention` :
- est liée à une prospection ;
- est générée à partir d'un devis précis ;
- conserve son modèle/version ;
- produit un PDF immuable ;
- est archivée et restaurée dans le cycle normal ;
- ne peut être supprimée physiquement que par un super administrateur.

Un devis ne possède qu'une convention active à la fois. Une convention archivée conserve son PDF figé et n'apparaît plus par défaut dans les listes et pièces jointes courantes. Elle ne peut être restaurée si une autre convention active existe déjà pour le même devis. Une vue dédiée présente les archives.

La mini-GED des conventions regroupe devis, facture, convention et fiches techniques liés au dossier.

---

## 12. Module technique multi-projet

### 12.1 Référentiels

Sont gérés par projet :
- `TechnicalGeneralSetting` ;
- `TechnicalProfile` ;
- patch audio ;
- matériel ;
- effets / intentions ;
- accueil technique ;
- blocs rédactionnels ;
- modèles de fiches techniques.

### 12.2 Wizard de fiche technique

Trois modes :
1. utiliser une fiche existante ;
2. personnaliser un modèle ;
3. créer une fiche spécifique.

Le wizard reste dans la modale de prospection.

Le mode « utiliser une fiche existante » est présenté comme **Association rapide** : il ne demande que le choix du modèle standard. Les modes de personnalisation et de création spécifique ouvrent le wizard avancé. L'administration distingue visuellement les modèles de documents techniques remis aux lieux de la configuration interne qui les alimente.

### 12.3 Cycle de vie

Le cycle est : `generated → sent → validated`, avec les branches `sent → refused`, `generated|sent|refused|validated → replaced` et `refused → sent`. `replaced` est terminal. Une fiche envoyée n'est jamais validée automatiquement.

Chaque transition conserve ancien état, nouvel état, date, acteur et motif lorsqu'il est pertinent. Seule une fiche encore `generated` peut être supprimée. Après envoi, elle est conservée et peut être refusée, validée ou remplacée.

---

## 13. Plans de scène et éléments scéniques

### 13.1 `StagePlan`

Un plan est propre au projet et versionné.

L'éditeur accepte les interactions tactiles et fournit des actions de sélection utilisables sans clic droit. Pour les petits téléphones, l'interface recommande le paysage ; l'édition précise reste volontairement orientée tablette et desktop plutôt qu'optimisée artificiellement pour le portrait.

L'unicité porte sur le projet, le code et la version afin que plusieurs groupes puissent réutiliser le même code logique.

### 13.2 `StageElementType` / affectation projet

Deux catégories d'éléments :
- éléments système réutilisables ;
- éléments spécifiques à un projet.

L'affectation d'un élément système à un projet enrichit sa palette sans supprimer les éléments historiques déjà disponibles.

### 13.3 Éditeur

Fonctions :
- drag & drop ;
- grille ;
- numéros sur le plan ;
- légende séparée ;
- renommage ;
- duplication ;
- rotation ;
- agrandissement/réduction ;
- suppression ;
- raccourcis clavier.

Les layouts historiques Walk The Line sont conservés.

---

## 14. Stockage documentaire / GED générale

### 14.1 `Document`

Métadonnées :
- code ;
- version ;
- type ;
- nom ;
- nom original ;
- MIME ;
- extension ;
- taille ;
- checksum ;
- dates ;
- auteur ;
- état ;
- description ;
- droits public/presse/admin ;
- `documentContentId`.

### 14.2 `DocumentContent`

Stockage BLOB séparé afin d'éviter de charger les contenus binaires dans les listes.

### 14.3 Immutabilité et versionnage

- devis, factures, conventions et fiches spécifiques générées sont immuables ;
- documents ordinaires : versionnage possible ;
- pièce comptable : pas de nouvelle version depuis la bibliothèque globale ; une nouvelle pièce distincte doit être ajoutée.

Les métadonnées sont protégées avec la même portée que le fichier. Un identifiant, une URL, un code GED, une relation Doctrine ou une valeur de formulaire ne constitue jamais une autorisation. Les contrôles de permission et de projet s'appliquent aux listes, détails, téléchargements, accès par code, pièces jointes, modales, wizards et pages publiques. `availableProjects`, `template_id`, `profile_id`, `project_id` et tout autre identifiant reçu du client sont revérifiés côté serveur.

La bibliothèque utilise des cartes sur smartphone avec l'affichage comme action principale ; téléchargement, versionnage, métadonnées et archivage restent accessibles selon les permissions. Le formulaire conserve explicitement la portée projet et les droits Public, Presse et Admin.

---

## 15. Architecture comptable

Le module comptable est global à l'association.

Cette portée associative n'accorde pas un accès transversal aux dossiers des projets. Une facture appartient au projet de sa prospection. Hors super-admin, listes de factures, paiements, impayés, mouvements nominatifs, contrats, écritures et pièces sont limitées aux projets autorisés ; une ligne étrangère est omise. Les écritures sans projet restent associatives. Les agrégats globaux non nominatifs peuvent rester communs lorsqu'ils ne permettent pas de reconstituer des informations confidentielles.

Entités principales :
- `AccountingYear` ;
- `AccountingPeriod` ;
- `FinancialAccount` ;
- `Expense` ;
- `ExpenseCategory` ;
- recette exceptionnelle ;
- `Payment` ;
- `PaymentMethod` ;
- `MerchSale` ;
- `ExternalContract` ;
- `VatRegimePeriod` ;
- `AccountingDocumentLink`.

Objectif : simplifier la tenue et la préparation des éléments comptables sans transformer le logiciel en ERP complet.

Les listes comptables nominatives utilisent des cartes métier sur smartphone et restent filtrées côté serveur par projets autorisés. Les formulaires de recette et merchandising affichent d'abord les données essentielles et replient les options comptables facultatives. Cette présentation progressive ne modifie ni les contrôles de projet, ni le CSRF, ni la validation serveur.

---

## 16. Exercices et périodes automatiques

### 16.1 Génération

`AccountingCalendarManager` garantit la présence des exercices/périodes nécessaires sans intervention manuelle.

Le système peut créer :
- exercice courant ;
- exercice suivant ;
- périodes comprises dans les dates réelles de l'exercice.

### 16.2 Début comptable de l'association

Le premier exercice est tronqué à la date de début comptable.

Exemple :
- début comptable : 01/10/2026 ;
- premier exercice : 01/10/2026 → 31/12/2026 ;
- périodes attendues : octobre, novembre, décembre uniquement.

---

## 17. Comptes financiers

`FinancialAccount` représente :
- compte bancaire ;
- prestataire de paiement tel que SumUp ;
- caisse ;
- autre compte financier.

Informations :
- nom ;
- type ;
- fournisseur/prestataire ;
- IBAN éventuel ;
- date d'ouverture ;
- date de fermeture ;
- actif ;
- attente ou non d'un relevé mensuel.

Un relevé ne peut être considéré manquant avant l'ouverture du compte.

Les alertes sont calculées selon le chevauchement entre la période comptable et `openedAt` / `closedAt`, y compris si le compte est aujourd'hui inactif. La désactivation d'un compte soumis au relevé mensuel exige `closedAt`, avec `closedAt >= openedAt`.

---

## 18. Dépenses / prestations

### 18.1 `Expense`

Informations :
- date ;
- fournisseur/prestataire ;
- libellé ;
- catégorie ;
- projet nullable ;
- HT ;
- taux de TVA ;
- TVA ;
- TVA déductible ;
- TTC ;
- compte financier ;
- moyen de paiement ;
- date de paiement ;
- notes ;
- auteur ;
- exercice/période.

### 18.2 Saisie

L'interface accepte une saisie orientée HT ou TTC et recalcule les montants complémentaires.

### 18.3 Justificatif obligatoire

Toute nouvelle dépense doit recevoir un justificatif.

Le document :
- est stocké dans `Document` / `DocumentContent` ;
- est lié via `AccountingDocumentLink` ;
- est classé automatiquement dans l'exercice, le mois et la catégorie GED ;
- n'est pas dupliqué.

Les anciennes dépenses sans pièce peuvent être régularisées via `Ajouter justificatif`.

### 18.4 Modification

La dépense est éditable en modale. Un changement de date, projet ou compte réaligne le classement documentaire.

---

## 19. Recettes

### 19.1 Paiements de factures

Les recettes commerciales sont dérivées des paiements réels et non uniquement des factures émises.

### 19.2 Recettes exceptionnelles

Saisie manuelle pour :
- dons ;
- cotisations ;
- subventions ;
- remboursements ;
- autres recettes.

Elles peuvent être affectées à un projet ou rester communes à l'association.

---

## 20. Vente merchandising

`MerchSale` enregistre un récapitulatif simple de vente :
- date ;
- projet ;
- libellé ;
- TTC ;
- TVA comprise ;
- HT dérivé ;
- compte financier ;
- moyen de paiement ;
- frais prestataire ;
- notes.

Les frais SumUp/prestataire sont comptabilisés séparément comme sortie afin de conserver :
- recette brute ;
- frais de transaction ;
- montant net.

La gestion détaillée des stocks est préparée mais n'est pas imposée dans la V15.

---

## 21. Contrats / sous-traitance

`ExternalContract` conserve :
- objet ;
- prestataire ;
- début / fin ;
- projet nullable ;
- HT / TVA / TTC ;
- statut ;
- notes.

Lors de la création ou plus tard, il est possible d'ajouter :
- contrat ;
- devis prestataire ;
- facture prestataire ;
- autre pièce.

Ces documents sont automatiquement envoyés dans la GED comptable dans la catégorie appropriée.

---

## 22. GED comptable

### 22.1 Principe

`AccountingDocumentLink` associe un document existant à :
- exercice ;
- période ;
- type comptable ;
- projet ou compte ;
- source métier.

Il ne duplique pas le BLOB.

### 22.2 Classement automatique

Arborescence logique :
- année ;
- mois ;
- catégorie.

Catégories visibles :
- factures émises ;
- justificatifs dépenses ;
- relevés bancaires / SumUp ;
- factures fournisseurs ;
- devis prestataires ;
- contrats / sous-traitance ;
- assurances / échéanciers ;
- TVA / déclarations ;
- autres pièces.

### 22.3 Vue arbre

La GED utilise :
- dossiers repliables ;
- compteurs ;
- `Tout déplier` ;
- `Tout replier` ;
- recherche instantanée.

---

## 23. TVA

### 23.1 Historisation

`VatRegimePeriod` mémorise :
- date de début ;
- date de fin nullable ;
- régime ;
- fréquence.

Le régime peut donc évoluer sans réécrire l'historique.

### 23.2 Assistant TVA

L'écran TVA calcule pour une période :
- TVA collectée estimée ;
- TVA déductible ;
- solde indicatif.

Les périodes antérieures à l'assujettissement ne sont pas traitées comme déclarations manquantes.

L'assistant prépare les chiffres ; il ne constitue pas une télédéclaration officielle.

---

## 24. Tableau de bord comptable

La page `Comptabilité` expose :
- recettes encaissées ;
- dépenses ;
- résultat de trésorerie ;
- factures à encaisser ;
- derniers mouvements ;
- raccourcis vers GED, contrats, vente merch., comptes et TVA.

Les factures non payées ou partiellement payées peuvent recevoir un paiement sans quitter le dashboard.

---

## 25. Identité visuelle

Chaque projet dispose d'une mini-thématisation :
- couleur principale ;
- couleur secondaire ;
- logos/identité documentaire.

Utilisations :
- repérage du projet actif ;
- états actifs du menu ;
- accents dans le back-office ;
- PDF.

Cette configuration ne pilote pas le frontend public.

---

## 26. Futurs sites publics multi-domaines

`ArtisticProjectDomain` prépare la résolution :
`nom de domaine → projet artistique → frontend`.

Chaque projet pourra utiliser :
- structure Twig indépendante ;
- CSS/JS indépendants ;
- navigation différente ;
- identité graphique totalement différente.

Les données publiques restent issues du même back-office.

---


## 27. Gestion des accès utilisateurs et matrice de permissions

### 27.1 Administration des comptes

La page `Administration → Utilisateurs` est réservée aux super administrateurs.

Fonctions :
- création d'un compte ;
- modification nom/e-mail ;
- réinitialisation du mot de passe ;
- activation/désactivation ;
- promotion/retrait super administrateur ;
- affectation à un ou plusieurs projets artistiques ;
- affectation à un ou plusieurs groupes fonctionnels.

Les comptes historiques ne sont pas supprimés lorsqu'ils ont participé à des opérations : ils sont désactivés afin de conserver les références d'audit.

### 27.2 Affectation aux projets

`User` possède une relation ManyToMany vers `ArtisticProject`.

Règles :
- super administrateur : tous les projets ;
- utilisateur normal : uniquement les projets affectés ;
- le sélecteur de projet est filtré par ces affectations ;
- tout utilisateur non super-admin possédant un accès back-office doit disposer d'au moins un projet ;
- les contrôles serveur interdisent l'accès direct à un objet appartenant à un projet non autorisé ;
- les documents spécifiques à un projet suivent la même règle.

### 27.3 Groupes fonctionnels

Le système utilise `UserGroup` et `UserGroupPermission`.

Groupes système créés par la migration :
- Administrateur projet ;
- Prospecteur ;
- Technique ;
- Trésorier ;
- Lecture seule.

Le super administrateur peut créer d'autres groupes. Un utilisateur peut appartenir à plusieurs groupes : le niveau effectif pour une fonction est alors le niveau maximum accordé par l'un de ses groupes actifs.

### 27.4 Matrice de permissions

L'écran `Administration → Groupes & permissions` affiche une matrice à double entrée :
- lignes : fonctions métier ;
- colonnes : groupes utilisateurs.

Sur smartphone, une présentation par groupe remplace la matrice horizontale tout en envoyant les mêmes formulaires CSRF vers les mêmes contrôleurs. Les niveaux et règles d'autorisation sont donc identiques sur desktop et mobile.

Chaque cellule est cliquable et fait évoluer le niveau jusqu'au maximum autorisé par la fonction :
- `NONE = 0` : Aucun ;
- `READ = 1` : Lecture ;
- `WRITE = 2` : Lecture / écriture ;
- `DELETE = 3` : Lecture / écriture / suppression.

`WRITE` implique `READ`. `DELETE` implique `WRITE` et `READ`.

Certaines fonctions ont un niveau maximal inférieur à `DELETE` lorsqu'une suppression n'a pas de sens fonctionnel.

### 27.5 Catalogue fonctionnel

Le catalogue couvre notamment :
- Dashboard et À traiter ;
- Prospections ;
- Lieux & contacts ;
- Devis ;
- Factures ;
- Paiements ;
- Simulateur ;
- Dates ;
- Fiches techniques ;
- Plans de scène ;
- Tarifs ;
- Frais ;
- Configuration technique ;
- Éléments scéniques ;
- Conventions ;
- Documents ;
- Comptabilité ;
- Vente merch. ;
- Recettes exceptionnelles ;
- Dépenses ;
- Contrats / sous-traitance ;
- GED comptable ;
- TVA ;
- paramétrages associatifs/commerciaux/comptables et référentiels.

### 27.6 Effets des permissions

Les permissions pilotent simultanément :
- visibilité du menu ;
- boutons d'action ;
- tableaux de bord ;
- formulaires d'écriture ;
- accès direct aux routes ;
- accès aux documents sensibles.

Exemple : si le groupe Prospecteur a `Factures = Aucun`, ses utilisateurs :
- ne voient pas les factures dans `Devis & factures` ;
- ne peuvent pas convertir un devis en facture ;
- ne voient pas les factures à encaisser sur le dashboard ;
- ne peuvent pas ouvrir directement une facture par URL ;
- ne voient pas les actions d'encaissement liées aux factures.

La permission `Paiements` est indépendante de `Factures` et contrôle la création, correction et suppression des paiements.

### 27.7 Super administrateur

`User.isSuperAdmin` court-circuite la matrice :
- toutes les permissions ;
- tous les projets ;
- gestion des utilisateurs ;
- gestion des groupes et de la matrice ;
- gestion des projets ;
- maintenance.

Les groupes système restent configurables dans la matrice mais ne peuvent pas être supprimés.

### 27.8 Accès sans permission back-office

Un compte authentifié ne possédant aucune permission fonctionnelle de back-office n'accède pas à `/admin`.

Après connexion, il est redirigé vers la page de login avec un message explicite indiquant que son compte ne dispose pas des droits nécessaires. Un compte presse reste orienté vers l'espace presse.

Un compte qui possède des permissions de back-office mais aucun projet est authentifié, puis refusé sur `/admin` avec un message distinct demandant de contacter un administrateur. Sa création ou sa réactivation dans cette configuration est bloquée. Le super-admin est exempt.

### 27.9 Règles métier prioritaires

La matrice ne contourne jamais les règles d'intégrité métier. Par exemple, un niveau `Suppression` ne permet pas de supprimer un document historique déclaré immuable ou un objet dont le cycle de vie interdit la suppression.

---

## 28. Maintenance et import/export

### 28.1 Import/export lieux et contacts

XLSX avec identifiants externes stables et prévisualisation avant import.

Rapprochement :
- lieux : externalId, SIRET, identité métier ;
- contacts : externalId, e-mail, téléphone, identité + lieu.

### 28.2 Reset de démonstration

Réservé au super administrateur et protégé par CSRF + saisie `RESET`.

Les données de configuration essentielles sont conservées selon `DemoResetService`.

---

## 29. Contraintes d'intégrité

1. Un lieu n'est jamais dupliqué pour un nouveau projet.
2. Les objets générés officiellement sont figés.
3. Les pièces comptables ne sont pas remplacées par versionnage.
4. Les BLOBs ne sont pas chargés dans les listes.
5. Les suppressions destructrices sont limitées.
6. Les changements financiers conservent leur rattachement temporel.
7. Les filtres de projet sont appliqués à toutes les données spécifiques.
8. Les objets communs restent disponibles quel que soit le projet actif.
9. Le schéma Doctrine doit rester strictement aligné avec les migrations.
10. `doctrine:schema:update --force` n'est pas utilisé en production.
11. Une seule prospection active existe par couple projet + lieu.
12. Un devis ne produit qu'une facture et ne possède qu'une convention active.
13. Un statut de prospection est identifié par son code technique, jamais par son libellé.
14. Toute portée projet est revalidée côté serveur quel que soit le canal d'accès.

---

## 30. Technologies et exploitation

- PHP 8.2+ ;
- Symfony 7.4 ;
- Doctrine ORM + Migrations ;
- Twig ;
- Bootstrap ;
- DataTables ;
- Select2 ;
- Chart.js ;
- MariaDB/MySQL compatible ;
- `symfony/mime` ;
- `ZipArchive` pour XLSX ;
- stockage BLOB séparé ;
- Docker Desktop supporté pour le développement ;
- fichiers texte livrés en CRLF.

---

## 31. Règles de conception futures

Toute évolution doit :
- rester accessible à un utilisateur non technique ;
- automatiser le classement lorsqu'il est déductible ;
- préserver le multi-projet ;
- préserver le caractère commun de la comptabilité associative ;
- éviter la ressaisie d'un document déjà généré ;
- historiser les changements de régime et de période ;
- garder une distinction nette entre gestion interne et sites publics.

---

# Google Analytics 4 — mesure d'audience par projet

## Objectif

Chaque projet artistique peut connecter son propre site public à une propriété Google Analytics 4. L'intégration couvre deux usages distincts :

1. **collecte côté site public** via l'ID de mesure GA4 ;
2. **lecture des indicateurs dans le back-office** via Google Analytics Data API et un compte de service en lecture seule.

Aucune donnée Analytics n'est mutualisée entre projets.

## Paramétrage projet

Écran :

```text
/admin/projet/communications
```

Données stockées dans `ArtisticProject` :

- `googleAnalyticsEnabled` : activation du module ;
- `googleAnalyticsMeasurementId` : ID de mesure du flux Web, format `G-...` ;
- `googleAnalyticsPropertyId` : ID numérique de propriété GA4 ;
- `googleAnalyticsServiceAccountEmail` : `client_email` du compte de service Google Cloud ;
- `googleAnalyticsPrivateKeyEncrypted` : clé privée du compte de service, chiffrée avec `SecretCipher`.

La collecte publique est considérée comme configurée si le module est activé et qu'un ID de mesure est présent.

Le reporting back-office est considéré comme configuré si sont présents : activation, ID de mesure, ID de propriété, e-mail du compte de service et clé privée.

## Collecte publique

Le template public commun n'injecte le mécanisme Analytics que si la collecte est configurée pour le projet actif.

Le visiteur dispose d'un choix explicite **Accepter / Refuser**. Le Consent Mode est initialisé à `denied` avant toute décision. Avant acceptation :

- aucun chargement de `https://www.googletagmanager.com/gtag/js` ;
- aucun appel de collecte Google Analytics par le code du site.

Après acceptation :

- création de `window.dataLayer` / `gtag` ;
- chargement asynchrone de `gtag.js` ;
- configuration avec l'ID de mesure du projet ;
- choix enregistré localement dans le navigateur ;
- bouton `Cookies` permettant de rouvrir le choix.

Un retrait de consentement est effectif immédiatement sur la page courante : mise à jour Consent Mode vers `denied`, activation de `ga-disable-<MEASUREMENT_ID>`, arrêt des nouveaux envois et suppression raisonnable des cookies `_ga*` accessibles pour les domaines applicables. Une réacceptation sur la même page réactive le consentement sans recharger deux fois `gtag.js`, sans seconde configuration et sans double page vue.

La Content-Security-Policy autorise uniquement les domaines Google nécessaires au chargement et à la collecte Analytics, en complément des domaines déjà nécessaires à reCAPTCHA.

## Google Analytics Data API

Le service `GoogleAnalyticsService` s'authentifie par compte de service avec un JWT RS256 signé à partir de la clé privée chiffrée en base.

Scope OAuth utilisé :

```text
https://www.googleapis.com/auth/analytics.readonly
```

Endpoint de reporting :

```text
POST https://analyticsdata.googleapis.com/v1beta/properties/{PROPERTY_ID}:runReport
```

Aucun SDK Google supplémentaire n'est nécessaire : l'application utilise l'API REST.

## Tableau de bord

Le bloc Google Analytics n'est affiché que lorsque le reporting est entièrement configuré pour le projet actif.

Période courante : **7 derniers jours**.

Indicateurs :

- utilisateurs actifs (`activeUsers`) ;
- sessions (`sessions`) ;
- pages vues (`screenPageViews`) ;
- taux d'engagement (`engagementRate`) ;
- top 5 des pages selon les pages vues, avec chemin, titre, vues et utilisateurs actifs.

En cas d'erreur API, le tableau de bord reste fonctionnel et affiche un diagnostic dans le bloc Analytics sans interrompre le reste de la page.

## Test de connexion

L'écran `Site public & communications` propose **Tester la connexion Analytics**. Le test :

1. génère un jeton OAuth au nom du compte de service ;
2. appelle Google Analytics Data API ;
3. vérifie l'accès à la propriété configurée ;
4. retourne le nombre d'utilisateurs actifs des 7 derniers jours ou le message d'erreur Google.

## Procédure Google à documenter dans le produit

1. Créer la propriété GA4 dans Google Analytics.
2. Créer le flux Web et récupérer l'ID de mesure `G-...`.
3. Récupérer l'ID numérique de propriété.
4. Créer/sélectionner un projet Google Cloud.
5. Activer **Google Analytics Data API**.
6. Créer un compte de service.
7. Créer une clé JSON et récupérer `client_email` et `private_key`.
8. Dans Google Analytics, ajouter `client_email` dans **Gestion des accès à la propriété** avec le rôle **Lecteur**.
9. Reporter les quatre valeurs dans le back-office, activer Analytics, enregistrer et tester.

## Confidentialité

La page publique de confidentialité indique automatiquement si Google Analytics est actif. Lorsque le module est actif, elle précise que la mesure d'audience est conditionnée au consentement du visiteur et que le choix peut être modifié depuis le bouton Cookies.
