Files
Lesstime/docs/superpowers/specs/2026-05-22-mcp-absence-crud-tools-design.md
Matthieu 2b148fa65a feat(absences) : outils MCP CRUD pour les absences
Expose le module Absences via le serveur MCP et comble les trous CRUD
existants (projets, groupes, métadonnées de tâches, clients, users RH).

Absences (réutilise AbsenceDayCalculator + AbsenceBalanceService pour ne
pas contourner la logique de soldes) :
- list/get/create/review/cancel/delete-absence-request
- list/update-absence-policy, list/update-absence-balance
- create-absence-request prend un userId explicite (agir au nom d'un employé) ;
  review/cancel maintiennent les soldes (pending/taken) cohérents
- AbsenceRequestRepository::findFiltered pour les filtres de liste

Trous CRUD comblés :
- delete-project, delete-group
- CRUD tag, effort, priority
- CRUD status (couplé au workflow, avec category)
- CRUD client, get/update-user (champs RH, sans password ni roles)

Sérialisation centralisée (Serializer::absenceRequest/Policy/Balance/client/userFull).
Instructions MCP (mcp.yaml) mises à jour : statuts par workflow + domaine absences.

Tests : tests/Functional/Mcp/AbsenceRequestLifecycleTest (création / approbation /
annulation admin) vérifient le cycle complet et la cohérence des soldes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 14:10:56 +02:00

7.5 KiB

Spec — Extension des outils MCP : module Absences + trous CRUD

Date : 2026-05-22 Branche : feat/absence-management

Contexte & objectif

Le serveur MCP Lesstime (src/Mcp/Tool/) expose aujourd'hui les projets, tâches, métadonnées de tâches, time tracking et workflows. Le nouveau module Absences (AbsenceRequest, AbsencePolicy, AbsenceBalance) n'est pas exposé, et plusieurs entités existantes n'ont qu'une couverture partielle (souvent list sans create/update/delete).

Objectif : permettre de piloter l'app via MCP (assistant) sur ces domaines, en respectant strictement la logique métier déjà en place.

Conventions reprises de l'existant

  • Une classe par outil, attribut #[McpTool(name, description)] sur la classe.
  • Discovery automatique : config/packages/mcp.yaml scanne src/ (exclut DataFixtures). Aucune config à ajouter — créer la classe suffit.
  • Constructeur : injection de repos/services + Security.
  • __invoke(...) : check de rôle en première ligne (AccessDeniedException sinon), validation des IDs (InvalidArgumentException si introuvable), retour json_encode(...).
  • Sérialisation centralisée dans App\Mcp\Tool\Serializer.
  • Rôle : ROLE_USER pour la lecture/écriture courante ; ROLE_ADMIN pour les opérations sensibles (déjà le cas pour list-clients/list-users, et pour les opérations admin du module absences).

Décision clé — réutilisation de la logique métier (pas les Processors)

Les Processors API Platform (AbsenceRequestProcessor, AbsenceReviewProcessor, AbsenceCancelProcessor) sont liés à Security::getUser() (l'utilisateur courant) et à l'Operation HTTP. En MCP, l'utilisateur courant est le propriétaire du token (admin), or on veut pouvoir agir au nom d'un employé.

→ Les outils MCP n'appellent pas les Processors ; ils répliquent leur orchestration en réutilisant les services partagés qui portent la vraie règle métier :

  • AbsenceDayCalculator::countWorkingDays(...) — calcul des jours décomptés.
  • AbsenceBalanceServicereservePending, applyApproval, release, periodFor.
  • AbsencePolicyRepository::findOneByType(...) — politique active du type.
  • AbsenceRequestRepository::hasOverlap(...) — règle anti-chevauchement.

create-absence-request prend un userId explicite (l'employé cible) ; review/cancel posent reviewedBy = utilisateur du token MCP.

Ainsi soldes (pending/taken/acquired) et statuts restent cohérents avec ce que produit l'UI.

Inventaire des outils

Module Absences — src/Mcp/Tool/Absence/ (10 outils)

Outil Rôle Paramètres Logique
list-absence-requests USER userId?, status?, type?, from?, to? Filtre ; sans userId renvoie tout (token admin).
get-absence-request USER id
create-absence-request USER userId, type, startDate, endDate, startHalfDay?, endHalfDay?, reason? Vérifie policy active + overlap, calcule countedDays, refuse si ≤ 0, statut Pending, reservePending.
review-absence-request ADMIN id, decision (approve|reject), rejectionReason? Seulement si Pending. Approve → applyApproval ; reject → rejectionReason requis + release(false). Pose reviewedAt/reviewedBy.
cancel-absence-request USER id Pendingrelease(false) ; Approved → ADMIN requis + release(true) ; sinon conflit. Statut Cancelled.
delete-absence-request ADMIN id Suppression définitive.
list-absence-policies USER Toutes les policies (ordre type).
update-absence-policy ADMIN id, daysPerYear?, daysPerEvent?, justificationRequired?, noticeDays?, countWorkingDaysOnly?, active? Seuls les champs fournis changent.
list-absence-balances USER userId?, type?, period? Soldes filtrés.
update-absence-balance ADMIN id, acquired?, acquiring?, taken? Ajustement manuel (régularisation).

type et status acceptés en valeur d'enum string (ex. cp, maladie, pending) ; erreur de validation explicite si invalide. startDate/endDate au format YYYY-MM-DD.

Trous CRUD sur l'existant

Projets / groupes

  • delete-project (ADMIN) — id.
  • delete-group (USER) — id.

Métadonnées de tâchessrc/Mcp/Tool/TaskMeta/

  • create-tag / update-tag / delete-tag (USER) — label, color?.
  • create-effort / update-effort / delete-effort (USER) — label (+ ordre éventuel).
  • create-priority / update-priority / delete-priority (USER) — label, color?.
  • create-status / update-status / delete-status (ADMIN) — workflowId requis
    • category (todo|in_progress|blocked|review|done), label, color?, position?, isFinal?. (Les statuts ne sont PAS globaux : ils appartiennent à un workflow.)

Clientssrc/Mcp/Tool/Reference/ (ADMIN, aligné sur list-clients)

  • get-clientid.
  • create-clientname (+ email?, phone?, street?, city?, postalCode?).
  • update-clientid + champs optionnels.
  • delete-clientid.

Utilisateurssrc/Mcp/Tool/Reference/ (ADMIN)

  • get-userid (profil complet RH).
  • update-userid + champs RH/profil : isEmployee?, hireDate?, endDate?, contractType?, workTimeRatio?, annualLeaveDays?, referencePeriodStart?, initialLeaveBalance?, familySituation?, nbChildren?. Hors périmètre (décision utilisateur) : pas de create-user, pas de modification de password ni roles via MCP.

Sérialisation — ajouts à Serializer.php

  • absenceRequest(AbsenceRequest) : id, user{id,username}, type{value,label}, startDate, endDate, startHalfDay, endHalfDay, countedDays, reason, status{value,label}, rejectionReason, createdAt, reviewedAt, reviewedBy, justificationFileName.
  • absencePolicy(AbsencePolicy) : id, type{value,label}, daysPerYear, daysPerEvent, justificationRequired, noticeDays, countWorkingDaysOnly, active.
  • absenceBalance(AbsenceBalance) : id, user, type{value,label}, period, acquired, acquiring, taken, pending, acquiredTotal, available.
  • client(Client) : id, name, email, phone, street, city, postalCode.
  • userFull(User) : id, username, roles, isEmployee, hireDate, endDate, contractType, workTimeRatio, annualLeaveDays, referencePeriodStart, initialLeaveBalance, familySituation, nbChildren.

Mise à jour de la doc MCP

config/packages/mcp.yaml — bloc instructions :

  • corriger la mention « statuses … are GLOBAL » (faux : par workflow) ;
  • ajouter une phrase sur le domaine Absences (requests/policies/balances, lifecycle approve/reject/cancel, userId pour agir au nom d'un employé).

Découpage du plan d'implémentation (jalons)

  1. Absences : Serializer + 10 outils + tests de cohérence des soldes.
  2. Métadonnées tâches : delete-project/group, CRUD tag/effort/priority/status.
  3. Clients & users : CRUD clients, get/update user + maj mcp.yaml.

Chaque jalon est livrable et testable indépendamment.

Tests

Tests fonctionnels MCP (si une infra de test MCP existe) ou tests unitaires sur la réplication de la logique de solde : créer → review(approve) → cancel et vérifier pending/taken à chaque étape ; vérifier le refus sur chevauchement et sur plage sans jour ouvré.

Hors périmètre

  • Mail, BookStack, Gitea, Zimbra, Notifications, TaskDocument (non demandés).
  • Création d'utilisateurs et gestion mot de passe/rôles via MCP.
  • Upload de justificatif d'absence via MCP.