fix(pagination) : éviter la troncature silencieuse des collections paginées (LST-52) #9

Merged
matthieu merged 2 commits from fix/lst-52-pagination-audit into develop 2026-06-15 09:24:06 +00:00
Owner

LST-52 — Audit : listes impactées par la pagination API Platform non gérée

Suite au bug LST-51 (time entries tronquées à 30 par la pagination par défaut, lue sur une seule page côté front), audit complet de l'app pour éviter que le piège se reproduise + garde-fous de prévention.

Le mécanisme du piège

  • API Platform pagine par défaut à 30 éléments / page.
  • Le helper front extractHydraMembers() (frontend/utils/api.ts) ne lit que la première page (hydra:member), il ignore hydra:view.next → toute liste > 30 sur une ressource paginée est tronquée silencieusement.

Audit (croisement back × front)

Beaucoup de gros suspects côté front se sont avérés déjà protégés côté back :

Ressource Back pagination Consommée en entier (front) Verdict Action
/tasks false oui OK
/time_entries/range + /active false (route dédiée bornée) oui OK
/absence_requests /absence_policies /absence_balances false oui OK
/task_documents /task_recurrences false oui OK
/notifications paginée oui ⚠️ volume non borné fetchAllHydra() côté front
/clients paginée oui ⚠️ risque paginationEnabled: false
/projects paginée oui ⚠️ risque paginationEnabled: false
/users paginée oui ⚠️ risque paginationEnabled: false
/task_tags paginée oui ⚠️ risque modéré paginationEnabled: false
/task_groups /task_statuses /task_priorities /task_efforts /workflows paginée oui référentiels bornés paginationEnabled: false (robustesse)
/gitea/* /bookstack/* paginée (providers externes) borné par tâche/repo faible laissés tels quels, à surveiller

Changements

BackpaginationEnabled: false sur le GetCollection des ressources consommées intégralement et à volume borné/modéré : Client, Project, User, TaskTag, TaskGroup, TaskStatus, TaskPriority, TaskEffort, Workflow. (Cohérent avec le choix déjà fait pour Task/TimeEntry.)

Front — nouveau helper fetchAllHydra() (frontend/utils/api.ts) qui parcourt toutes les pages via hydra:totalItems + param page (garde-fou anti-boucle à 1000 pages). Utilisé pour /notifications, qui reste paginé côté back (volume non borné).

Doc — règle anti-troncature ajoutée au CLAUDE.md du projet : toute collection lue via extractHydraMembers doit être non paginée (volume borné), gérée via fetchAllHydra(), ou servie par une route dédiée bornée.

Vérifications

  • make php-cs-fixer-allow-risky : 0 correction.
  • make test : 89 tests OK (les 16 « Notices » sont des dépréciations préexistantes).
  • nuxi typecheck : aucune erreur sur les fichiers modifiés (erreurs préexistantes ailleurs, hors scope).

Closes LST-52.

## LST-52 — Audit : listes impactées par la pagination API Platform non gérée Suite au bug LST-51 (time entries tronquées à 30 par la pagination par défaut, lue sur une seule page côté front), audit complet de l'app pour éviter que le piège se reproduise + garde-fous de prévention. ### Le mécanisme du piège - API Platform pagine par défaut à **30 éléments / page**. - Le helper front `extractHydraMembers()` (`frontend/utils/api.ts`) ne lit **que la première page** (`hydra:member`), il ignore `hydra:view.next` → toute liste > 30 sur une ressource paginée est **tronquée silencieusement**. ### Audit (croisement back × front) Beaucoup de gros suspects côté front se sont avérés **déjà protégés** côté back : | Ressource | Back pagination | Consommée en entier (front) | Verdict | Action | |---|---|---|---|---| | `/tasks` | `false` ✅ | oui | OK | — | | `/time_entries/range` + `/active` | `false` ✅ (route dédiée bornée) | oui | OK | — | | `/absence_requests` `/absence_policies` `/absence_balances` | `false` ✅ | oui | OK | — | | `/task_documents` `/task_recurrences` | `false` ✅ | oui | OK | — | | **`/notifications`** | paginée | oui | ⚠️ volume **non borné** | `fetchAllHydra()` côté front | | **`/clients`** | paginée | oui | ⚠️ risque | `paginationEnabled: false` | | **`/projects`** | paginée | oui | ⚠️ risque | `paginationEnabled: false` | | **`/users`** | paginée | oui | ⚠️ risque | `paginationEnabled: false` | | **`/task_tags`** | paginée | oui | ⚠️ risque modéré | `paginationEnabled: false` | | **`/task_groups` `/task_statuses` `/task_priorities` `/task_efforts` `/workflows`** | paginée | oui | référentiels bornés | `paginationEnabled: false` (robustesse) | | `/gitea/*` `/bookstack/*` | paginée (providers externes) | borné par tâche/repo | faible | laissés tels quels, à surveiller | ### Changements **Back** — `paginationEnabled: false` sur le `GetCollection` des ressources consommées intégralement et à volume borné/modéré : `Client`, `Project`, `User`, `TaskTag`, `TaskGroup`, `TaskStatus`, `TaskPriority`, `TaskEffort`, `Workflow`. (Cohérent avec le choix déjà fait pour `Task`/`TimeEntry`.) **Front** — nouveau helper `fetchAllHydra()` (`frontend/utils/api.ts`) qui parcourt toutes les pages via `hydra:totalItems` + param `page` (garde-fou anti-boucle à 1000 pages). Utilisé pour `/notifications`, qui reste paginé côté back (volume non borné). **Doc** — règle anti-troncature ajoutée au `CLAUDE.md` du projet : toute collection lue via `extractHydraMembers` doit être non paginée (volume borné), gérée via `fetchAllHydra()`, ou servie par une route dédiée bornée. ### Vérifications - `make php-cs-fixer-allow-risky` : 0 correction. - `make test` : **89 tests OK** (les 16 « Notices » sont des dépréciations préexistantes). - `nuxi typecheck` : aucune erreur sur les fichiers modifiés (erreurs préexistantes ailleurs, hors scope). Closes LST-52.
matthieu added 1 commit 2026-06-15 09:08:54 +00:00
API Platform pagine par défaut à 30 éléments/page et le helper front
extractHydraMembers ne lit que la première page (il ignore hydra:view.next),
ce qui tronque silencieusement toute liste de plus de 30 éléments.

- Back : paginationEnabled false sur les GetCollection consommées en entier
  et à volume borné/modéré (Client, Project, User, TaskTag, TaskGroup,
  TaskStatus, TaskPriority, TaskEffort, Workflow).
- Front : nouveau helper fetchAllHydra() qui parcourt toutes les pages ;
  utilisé pour /notifications (volume non borné, reste paginé côté back).
- Doc : règle anti-troncature ajoutée au CLAUDE.md.

Déjà protégés (vérifiés) : Task, TimeEntry, TaskDocument, TaskRecurrence,
AbsenceRequest/Policy/Balance (paginationEnabled false) et /time_entries/range.
matthieu added 1 commit 2026-06-15 09:21:44 +00:00
NotificationProvider retournait findBy(..., 30) : limite codée en dur,
paramètre page ignoré et tableau brut (pas un Paginator). hydra:totalItems
valait donc 30 → fetchAllHydra s'arrêtait à la 1re page et les notifications
restaient tronquées à 30 malgré le correctif front.

- NotificationProvider : vraie pagination Doctrine (Pagination + DoctrinePaginator
  + TraversablePaginator), totalItems réel et hydra:view.next exposés
- NotificationRepository : createUserNotificationsQueryBuilder (filtre user + tri)
- fetchAllHydra : ne retronque plus silencieusement quand hydra:totalItems est
  absent, pagine jusqu'à une page non pleine
matthieu merged commit d874aebbed into develop 2026-06-15 09:24:06 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: MALIO-DEV/Lesstime#9