# Avis sur le module « Pilotage d'équipe et primes gamifiées » — convenable ? comment l'améliorer ? comment le relier au socle ?

*Cowork, 2 septembre 2026 (soir). Base : `PILOTAGECONCEPTIONAZ.md` (conception de A à Z) + maquette `docs/maquettes/pilotage-v3.38.html` (sha `2067d73c`, déjà committée dans le dépôt avec v4.0.0), relus contre le code réel du socle v4.0.0.*

## 1. Verdict

**Convenable, et bien pensé.** Le module ne remplace rien : il ajoute une couche « tâches » au-dessus de ce que le socle sait déjà (collaborateurs, marchés, équipes, feuilles de temps, push, fériés, paie, primes). Les principes (le logiciel propose, le gérant tranche ; silence sur la masse, alerte sur l'exception ; aucun point négatif ; tout explicable ligne par ligne) sont ceux du socle. La maquette est claire et les 22 points de recette sont exigeants — c'est exactement ce qu'il faut à Claude Code.

Trois réserves, à trancher avant le prompt (§5) : le **volume** (un seul lot serait le plus gros prompt jamais lancé sur le socle — plus que la v4.0.0), le **hors ligne** (une vraie application hors connexion ne se fait pas avec l'outillage actuel du socle) et **l'arabe en miroir** (le socle n'est traduit en arabe que sur la formation et la vitrine).

## 2. Ce qui existe déjà et que le module doit RÉUTILISER (vérifié dans le code)

| Besoin du module | Ce que le socle a déjà | Ce que le prompt doit dire |
|---|---|---|
| Qui est chef de marché | `projects.lead_employee_id` + `Employee::isProjectLead()` (déjà utilisé par « Feuilles de temps de l'équipe ») ; `project_assignments` (employee, mode, percent, dates) = l'équipe | « Mon équipe » et le droit d'assigner s'appuient sur `isProjectLead()` et `project_assignments` — pas une nouvelle notion d'équipe |
| Un responsable hiérarchique | `employees.manager_id` + `Employee::manager()` / `subordinates()` | Le manager hiérarchique a les mêmes droits qu'un chef de marché sur ses subordonnés, quel que soit le marché (origine `chef_de_marche`) — sinon Nadia (fonctionnement interne, sans marché) n'aurait personne pour lui assigner sauf la direction |
| Le régime de chacun | `employees.regime` (salarié · auto-entrepreneur · contractuel non déclaré · stagiaire · à déterminer), `contract_type` (CDI, CDD, ANAPEC, stage, freelance), `base_gross`, `daily_rate` | Le circuit de paiement et les majorations se choisissent sur `regime` ; « à déterminer » ⇒ prime manuelle seulement |
| Les heures | `timesheets` (date, project_id, hours, remark, status, approved_by, is_weekend) + `TimesheetService` + `MaJournee` (page Employé `/espace`, `heures[]` par marché, ligne « Fonctionnement interne ») | « Terminé » propose une ligne `timesheets` par le même service, au même statut de brouillon que la saisie manuelle ; « Ma journée v2 » = la page `MaJournee` existante avec les tâches AU-DESSUS du bloc heures, jamais une seconde page |
| Les jours ouvrés | `holidays` (date, type, confirmed) ; congés `leave_requests` validés ; `employees.timesheet_day_template` | maximum du mois = jours ouvrés − fériés confirmés − congés validés, par personne |
| Les push | `push_subscriptions` (par utilisateur, plusieurs appareils), `WebPushChannel`, `BrandedNotification`, `DailyDigestNotification` (08:00), `timesheets:remind` (08:30 et dimanche 18:00) | UN seul push à 08:30 par collaborateur (tâches du jour + rappel heures fusionnés dans `timesheets:remind`), jamais deux ; sans abonnement push ⇒ silence, pas d'erreur |
| Le planificateur | `routes/console.php` (Schedule::command, `withoutOverlapping`, file `database`) | 08:30 · 17:30 · 18:00 · vendredi 17:00 · 1ᵉʳ du mois, dans le même fichier, tout en file |
| Les primes | `bonus_rules` (trigger : soumission_retenue · decompte_encaisse · fin_de_marche · manuel ; calc_base, rate, fixed_amount, scope, project_id), `bonus_rule_beneficiaries`, `bonuses` (status due · paid · cancelled, payroll_id, transaction_id, `pay_with_payroll`), `BonusEngine`, `BonusService`, `BonusGeneratedNotification` | Nouveau trigger `cloture_mensuelle`, nouveau statut `proposee` (+ `refusee`), une ligne `bonuses` par personne et par mois avec `details` (json) ; validée ⇒ `due` et le circuit existant paie (bulletin `bonus_total` ou transaction) — aucun second moteur |
| La paie | `payrolls` (gross, bonus_total, cnss/amo, ir, net, status, payslip) ; page `ReglagesPaie` | `overtime_total` + `overtime_detail` (json) sur `payrolls` ; les MAJORATIONS LÉGALES se règlent dans `ReglagesPaie` (c'est de la paie), les montants gamifiés dans « Pilotage & primes » |
| Les paiements hors bulletin | `transactions` (employee_id, project_id, category, flow_type, status, validated_by) | auto-entrepreneur / contractuel ⇒ transaction, comme aujourd'hui pour `bonuses.transaction_id` |
| Les réglages | `settings` (group, key, value) ; pages `AppSettings`, `CmsSettings`, `ReglagesPaie` | clés `pilotage.*` (groupe `pilotage`), page « Pilotage & primes » sur le même modèle |
| L'audit | `AuditLog` (`AuditLog::create(...)`, package d'audit déjà présent) | chaque annulation, ajustement, coup de pouce, changement de réglage = une ligne d'audit avec motif — aucun nouveau journal |
| Le PDF | `FabriqueDuRapportDeMarche` (dompdf, instance fraîche par rendu, règle mémoire, jamais `isPhpEnabled`) ; `formation:rapport-hebdo` (un rapport hebdo planifié existe déjà) | le rapport hebdo pilotage copie ces deux patrons |
| Les droits | permissions `xxx.view` / `xxx.manage` (ex. `bonuses.manage`, `employees.view`) | `pilotage.view` (cockpit), `pilotage.manage` (réglages, primes), les gestes du collaborateur passent par son `user->employee_id` |
| Le multi-tenant | `Identite::nomCourt()` / `marque()` | aucun « IRADA » en dur ; RUWAD sur base vide affiche « Aucune tâche — planifiez la semaine » |

## 3. Améliorations que je propose (sans changer l'esprit)

1. **Fusionner les pushs du matin.** Le socle envoie déjà « pointe tes heures » à 08:30 ; le module ajouterait « Ta journée » à 08:30. Un seul message : « Ta journée : 3 tâches · 10 pts à prendre · série 4 j · heures d'hier à pointer ». Le collaborateur ne doit jamais recevoir deux pushs à la même minute.
2. **Une seule vérité pour l'équipe.** Chef de marché = `isProjectLead()` ; manager hiérarchique = `manager_id`. Les deux assignent, l'origine affichée reste « chef ». Aucune table « équipes » nouvelle.
3. **Tracer le pont heures.** `task_updates.timesheet_id` (nullable) : la ligne de feuille de temps créée par « Terminé » sait d'où elle vient, et la supprimer côté feuille de temps ne casse pas la tâche.
4. **Le double coût d'un retard.** Une seule tâche reçue en retard fait perdre « planning tenu » (3) ET « zéro retard » (2) = 5 points sur 10 le même jour. C'est voulu (le retard est le signal n° 1) mais à écrire noir sur blanc dans le règlement remis à l'équipe, sinon ce sera vécu comme une double peine. Réglable ? Non : gravé, mais expliqué.
5. **Heures supplémentaires et loi.** Le module ne paie la majoration que sur mission publiée ET validée (« un samedi passé au bureau sans mission = 0 »). Pour un salarié, une heure supplémentaire faite à la demande, même orale, est due — la règle « 0 sans mission » protège la direction contre le travail non demandé, mais le comptable doit confirmer la formulation (le document le prévoit déjà pour les majorations ; à étendre à ce point).
6. **Le mode strict** (journée non mise à jour à 18 h = 0 point) : garder en réglage, désactivé — et l'écrire dans le règlement comme une possibilité, pour qu'il n'arrive pas par surprise.
7. **Les animations** : CSS seulement, moins d'une seconde, coupées par `prefers-reduced-motion` ; aucune bibliothèque, aucun son, aucun confetti JS lourd sur un téléphone de terrain.
8. **Le rapport hebdo** : vendredi 17 h, généré en file, stocké comme les bulletins (`storage`), lien dans le push du gérant — pas de pièce jointe push.
9. **La régularisation** (Terminé posé le lendemain avant 8 h 30 pour la veille) remplace avantageusement le hors ligne pour le terrain : l'heure réelle est saisie par le collaborateur dans un champ « fait à … » ; mention « régularisé » dans le journal.

## 4. À REPORTER (pas dans le premier lot)

- **Le hors ligne** (PWA, gestes en attente, synchronisation). Le socle est une application Filament/Livewire : chaque geste est un aller-retour serveur. Un vrai mode hors connexion suppose une couche cliente à part (service worker, file locale, résolution des conflits) — un chantier en soi, à évaluer plus tard sur un besoin mesuré (combien de gestes échouent réellement sur le terrain ?). En phase 1 : message clair « pas de réseau, réessaie » + régularisation.
- **L'arabe en miroir.** `lang/ar` ne couvre que la formation et la vitrine ; l'espace collaborateur et l'admin sont en français. Traduire l'espace collaborateur = un lot i18n à part, tous modules confondus.
- **L'espace client, la vue groupe IRADA + RUWAD, WhatsApp API** : déjà hors phase 1 dans le document — d'accord.

## 5. Les décisions à prendre maintenant

1. **Un lot ou deux ?** Un seul prompt = tâches + cockpit + notifications + rapport + points + niveaux + primes + renfort + paie + réglages + règlement PDF : 8 tables, 5 services, 2 panneaux, 5 horaires planifiés, un PDF, ~40 tests. La v4.0.0 (plus petite) a pris 1 h 05 et a laissé un défaut d'écran. **Ma recommandation : deux lots** — v4.1.0 « Pilotage » (tâches, trois origines, journal, Ma journée v2, cockpit, signaux, notifications, rapport hebdo, pont heures) puis v4.2.0 « Primes & renfort » (points, séries, badges, niveaux, Primes du mois, missions renfort, heures supplémentaires, réglages, règlement). Le second se lance dès que le premier est vu à l'écran ; entre les deux, l'équipe commence à utiliser les tâches — et les points ont un journal réel sur lequel se calculer.
2. **Hors ligne** : reporté (recommandé) ou exigé maintenant.
3. **Arabe en miroir** : reporté (recommandé) ou exigé maintenant.
4. **Les défauts chiffrés** : mode strict non · renfort 50 / 200 / 300 DH · plafond 2 missions/mois · barème 3·3·2·1·1 · niveaux 60/75/90 % → 25/60/100 % · base insuffisante < 5 tâches. À confirmer tels quels (tout est réglable ensuite, effet au 1ᵉʳ du mois suivant).
5. **La maquette** : validée jusque dans la disposition (les 4 onglets), ou des retouches avant le prompt.

## 6. Ce que contiendra le prompt (dès tes réponses)

Le même format que les prompts précédents : règles absolues du socle ; le document de conception et la maquette cités par leur chemin relatif depuis la racine du dépôt (`docs/maquettes/pilotage-v3.38.html`, et le document de conception à poser dans `docs/conception/PILOTAGE.md`) ; volet A modèle (migrations additives, idempotentes) ; volet B services et règles (avec les liens du §2, nommés) ; volet C écrans (disposition épelée) ; volet D notifications et planificateur ; volet E rapport PDF ; volet F tests (les 22 points de la recette + base vide) ; livraison (Pint, suite, `npm run build` si des assets bougent, CHANGELOG, rapport, tag). Et, cette fois, une exigence tirée de la leçon v4.0.0 : **chaque écran nouveau a un test qui rend LA PAGE que l'utilisateur ouvre**, pas seulement le composant.
