diff --git a/administration.php b/administration.php index 301ac98..d98e64a 100644 --- a/administration.php +++ b/administration.php @@ -2,5 +2,13 @@ declare(strict_types=1); +/** + * Référentiels : agents, lieux d'affectation, postes, horaires de couverture. + * + * Point d'entrée de page. Le nom passé à runPage() est à la fois la méthode de + * PageController à appeler et la clé de page contrôlée dans acces_role_page : + * sans la ligne correspondante en base, la page est refusée. + */ + require __DIR__ . '/page_bootstrap.php'; runPage('administration'); diff --git a/agents.php b/agents.php index b66da60..7fe96c2 100644 --- a/agents.php +++ b/agents.php @@ -2,5 +2,14 @@ declare(strict_types=1); +/** + * Planning d'un agent mois par mois, tous lieux confondus. + * Un rôle AGENT y est verrouillé sur lui-même et l'écran devient « Mon planning ». + * + * Point d'entrée de page. Le nom passé à runPage() est à la fois la méthode de + * PageController à appeler et la clé de page contrôlée dans acces_role_page : + * sans la ligne correspondante en base, la page est refusée. + */ + require __DIR__ . '/page_bootstrap.php'; runPage('agents'); diff --git a/annual.php b/annual.php index 8277d9a..b7cb905 100644 --- a/annual.php +++ b/annual.php @@ -2,5 +2,13 @@ declare(strict_types=1); +/** + * Vue annuelle d'un agent et validation de l'année entière. + * + * Point d'entrée de page. Le nom passé à runPage() est à la fois la méthode de + * PageController à appeler et la clé de page contrôlée dans acces_role_page : + * sans la ligne correspondante en base, la page est refusée. + */ + require_once __DIR__ . '/page_bootstrap.php'; runPage('annual'); diff --git a/api/agent_assignments.php b/api/agent_assignments.php index adbb5eb..1dc76af 100644 --- a/api/agent_assignments.php +++ b/api/agent_assignments.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — liste des agents (Service Enfance). + * POST — change le lieu de rattachement principal d'un agent. + * Charge utile POST : agent_id, structure_id (nullable), csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AgentController; use App\Core\JsonResponse; diff --git a/api/agent_hours_contract_pdf.php b/api/agent_hours_contract_pdf.php index 3df69cc..46b3eb9 100644 --- a/api/agent_hours_contract_pdf.php +++ b/api/agent_hours_contract_pdf.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — contrat horaire annuel d'un agent, au format PDF. + * Paramètres : agent_id, puis date OU year. Sortie binaire : pas de bootstrap JSON. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AgentController; $pdo = require dirname(__DIR__) . '/app/bootstrap.php'; diff --git a/api/agent_month_overview.php b/api/agent_month_overview.php index b2f9b06..a76e4cb 100644 --- a/api/agent_month_overview.php +++ b/api/agent_month_overview.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — grille mensuelle d'un agent, tous lieux confondus. + * Paramètres : agent_id, month (« 2026-02 »). + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AgentController; use App\Core\JsonResponse; diff --git a/api/agent_overview.php b/api/agent_overview.php index 022a497..980447a 100644 --- a/api/agent_overview.php +++ b/api/agent_overview.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — semaine d'un agent, tous lieux confondus. + * Paramètres : agent_id, week (« 2026-W08 »). + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AgentController; use App\Core\JsonResponse; diff --git a/api/agent_planning_pdf.php b/api/agent_planning_pdf.php index 202424e..ddb12e2 100644 --- a/api/agent_planning_pdf.php +++ b/api/agent_planning_pdf.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — planning d'un agent sur 6 ou 7 semaines, au format PDF. + * Paramètres : agent_id, week (départ), weeks (6|7). Sortie binaire. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AgentController; $pdo = require dirname(__DIR__) . '/app/bootstrap.php'; diff --git a/api/agent_time_summary_pdf.php b/api/agent_time_summary_pdf.php index 56a2e2b..86e07b5 100644 --- a/api/agent_time_summary_pdf.php +++ b/api/agent_time_summary_pdf.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — bilan annuel d'heures d'un agent, au format PDF. + * Paramètres : agent_id, puis date OU year. Sortie binaire. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AgentController; $pdo = require dirname(__DIR__) . '/app/bootstrap.php'; diff --git a/api/agents.php b/api/agents.php index 563c090..72d95d4 100644 --- a/api/agents.php +++ b/api/agents.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — agents sélectionnables dans l'éditeur de planning. + * Paramètre : structure_id (0 ou absent = tous les lieux, Service Enfance). + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AgentController; use App\Core\JsonResponse; diff --git a/api/annual_overview.php b/api/annual_overview.php index d011411..8e318a1 100644 --- a/api/annual_overview.php +++ b/api/annual_overview.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — calendrier annuel d'un agent (Service Enfance). + * Paramètres : agent_id, year (facultatif, année en cours par défaut). + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AnnualOverviewController; use App\Core\JsonResponse; diff --git a/api/annual_validate.php b/api/annual_validate.php index f164237..48b3126 100644 --- a/api/annual_validate.php +++ b/api/annual_validate.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — contrôle puis valide TOUTE l'année d'un agent (Service Enfance). + * Tout ou rien : une seule erreur et aucune semaine n'est validée. + * Charge utile : agent_id, year, force_quota, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AnnualOverviewController; use App\Core\JsonResponse; diff --git a/api/apply_week_template.php b/api/apply_week_template.php index 7e13519..99a7917 100644 --- a/api/apply_week_template.php +++ b/api/apply_week_template.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — applique une semaine type à UNE semaine (Service Enfance). + * Charge utile : template_id, agent_id, week, mode (merge|replace), csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\WeekTemplateController; use App\Core\JsonResponse; diff --git a/api/apply_week_template_period.php b/api/apply_week_template_period.php index b4105d6..4af5492 100644 --- a/api/apply_week_template_period.php +++ b/api/apply_week_template_period.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — applique une semaine type sur une période (Service Enfance). + * Opération massive : passer d'abord par preview_week_template_period.php. + * Charge utile : template_id, agent_id, start_date, end_date, mode, period_filter, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\WeekTemplateController; use App\Core\JsonResponse; diff --git a/api/copy_agent_week.php b/api/copy_agent_week.php index 7c8f312..bd40d6e 100644 --- a/api/copy_agent_week.php +++ b/api/copy_agent_week.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — recopie une semaine entière d'un agent (Service Enfance). + * Porte sur tous les lieux de la semaine source. + * Charge utile : agent_id, source_week, target_week, mode (merge|replace), csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\PlanningController; use App\Core\JsonResponse; diff --git a/api/coverage_alerts.php b/api/coverage_alerts.php index 741160a..f7a12fb 100644 --- a/api/coverage_alerts.php +++ b/api/coverage_alerts.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — plages sous-effectif d'une semaine (responsable ou Service Enfance). + * Un responsable est forcé sur son propre lieu. + * Paramètres : week, structure_id (facultatif). + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\CoverageController; use App\Core\JsonResponse; diff --git a/api/create_agent.php b/api/create_agent.php index 60d68c4..9daacb2 100644 --- a/api/create_agent.php +++ b/api/create_agent.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — crée un agent, son quota annuel et son PTA (Service Enfance). + * Charge utile : matricule, nom, prenom, structure_id, id_poste, type_contrat, + * quotite_travail, date_debut_contrat, csrf_token, et champs facultatifs. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AgentController; use App\Core\JsonResponse; diff --git a/api/create_structure.php b/api/create_structure.php index 47b754c..9f4d992 100644 --- a/api/create_structure.php +++ b/api/create_structure.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — crée un lieu d'affectation (Service Enfance). + * Charge utile : code, nom, adresse, type_affectation, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\StructureController; use App\Core\JsonResponse; diff --git a/api/dashboard_summary.php b/api/dashboard_summary.php index 871859b..8334e6b 100644 --- a/api/dashboard_summary.php +++ b/api/dashboard_summary.php @@ -4,6 +4,15 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — données du tableau de bord (Service Enfance). + * scope=badges limite la réponse au compteur de la pastille de navigation : + * c'est la variante appelée depuis toutes les pages, elle doit rester légère. + * Paramètres : scope, week, year (tous facultatifs). + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\DashboardController; use App\Core\JsonResponse; diff --git a/api/delete_agent_entry.php b/api/delete_agent_entry.php index fc607a7..58310e8 100644 --- a/api/delete_agent_entry.php +++ b/api/delete_agent_entry.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — supprime un créneau depuis la fiche agent. + * Peut rouvrir un planning validé. Charge utile : entry_id, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\PlanningController; use App\Core\JsonResponse; diff --git a/api/delete_vacation_period.php b/api/delete_vacation_period.php index 93c8a40..db016c3 100644 --- a/api/delete_vacation_period.php +++ b/api/delete_vacation_period.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — supprime une période de vacances (Service Enfance). + * Charge utile : period_id, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\VacationController; use App\Core\JsonResponse; diff --git a/api/delete_week_template.php b/api/delete_week_template.php index e819d94..4fcaedc 100644 --- a/api/delete_week_template.php +++ b/api/delete_week_template.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — supprime une semaine type (Service Enfance). + * Les créneaux déjà appliqués ne sont pas touchés. + * Charge utile : template_id, agent_id, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\WeekTemplateController; use App\Core\JsonResponse; diff --git a/api/move_or_duplicate_entry.php b/api/move_or_duplicate_entry.php index 3366cf8..6bb88c5 100644 --- a/api/move_or_duplicate_entry.php +++ b/api/move_or_duplicate_entry.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — déplace ou duplique un créneau (glisser-déposer). + * Charge utile : entry_id, target_date, action (move|duplicate), csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\PlanningController; use App\Core\JsonResponse; diff --git a/api/pending_plannings.php b/api/pending_plannings.php index d1ea996..ce02447 100644 --- a/api/pending_plannings.php +++ b/api/pending_plannings.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — file des plannings en attente de validation (Service Enfance). + * Triée du plus ancien au plus récent, brouillons vides exclus. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\PlanningController; use App\Core\JsonResponse; diff --git a/api/planning.php b/api/planning.php index 8c90dd6..621a06d 100644 --- a/api/planning.php +++ b/api/planning.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — état complet d'une semaine de saisie. + * Inclut les créneaux de l'agent sur les AUTRES lieux, en lecture seule. + * Paramètres : structure_id, agent_id, week. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\PlanningController; use App\Core\JsonResponse; diff --git a/api/preview_school_holidays.php b/api/preview_school_holidays.php index facc083..e1638d4 100644 --- a/api/preview_school_holidays.php +++ b/api/preview_school_holidays.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — propositions de vacances de l'API data.education.gouv.fr, SANS écriture. + * Un échec du service distant ressort en 502. + * Paramètres : academy, year (année civile). + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\VacationController; use App\Core\JsonResponse; diff --git a/api/preview_week_template_period.php b/api/preview_week_template_period.php index c92f450..81596e4 100644 --- a/api/preview_week_template_period.php +++ b/api/preview_week_template_period.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — SIMULE l'application d'une semaine type sur une période, sans écrire. + * Étape imposée avant apply_week_template_period.php. + * Charge utile : template_id, agent_id, start_date, end_date, mode, period_filter, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\WeekTemplateController; use App\Core\JsonResponse; diff --git a/api/pta_constraint.php b/api/pta_constraint.php index 0ff25a1..6f5e19e 100644 --- a/api/pta_constraint.php +++ b/api/pta_constraint.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — enregistre ou supprime une contrainte prioritaire (Service Enfance). + * Double action selon le champ `action` (SAVE par défaut, ou DELETE). + * Charge utile : action, agent_id, csrf_token, puis constraint_id ou les champs de la contrainte. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\PtaController; use App\Core\JsonResponse; diff --git a/api/pta_summary.php b/api/pta_summary.php index 7938517..c917391 100644 --- a/api/pta_summary.php +++ b/api/pta_summary.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — synthèse du PTA d'un agent à une date de référence (Service Enfance). + * Paramètres : agent_id, date (facultative, aujourd'hui par défaut). + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\PtaController; use App\Core\JsonResponse; diff --git a/api/pta_wish.php b/api/pta_wish.php index 8583ce2..a4088b7 100644 --- a/api/pta_wish.php +++ b/api/pta_wish.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — enregistre ou supprime un souhait de lieu (Service Enfance). + * Double action selon le champ `action` (SAVE par défaut, ou DELETE). + * Charge utile : action, agent_id, csrf_token, puis wish_id ou les champs du souhait. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\PtaController; use App\Core\JsonResponse; diff --git a/api/save_structure_coverage_rules.php b/api/save_structure_coverage_rules.php index 10222e2..9b698cf 100644 --- a/api/save_structure_coverage_rules.php +++ b/api/save_structure_coverage_rules.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — remplace INTÉGRALEMENT les règles de couverture d'un lieu (Service Enfance). + * Une liste vide supprime toute règle. + * Charge utile : structure_id, rules[], csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\CoverageController; use App\Core\JsonResponse; diff --git a/api/save_vacation_periods.php b/api/save_vacation_periods.php index 5ae31dd..473d954 100644 --- a/api/save_vacation_periods.php +++ b/api/save_vacation_periods.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — enregistre les périodes de vacances retenues (Service Enfance). + * Plafonné à 50 périodes par envoi. + * Charge utile : periods[], csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\VacationController; use App\Core\JsonResponse; diff --git a/api/save_week_template.php b/api/save_week_template.php index 8f9a9a5..eddd081 100644 --- a/api/save_week_template.php +++ b/api/save_week_template.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — enregistre la semaine planifiée comme semaine type (Service Enfance). + * Charge utile : agent_id, week, name, replace, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\WeekTemplateController; use App\Core\JsonResponse; diff --git a/api/save_week_template_entries.php b/api/save_week_template_entries.php index 33ed354..5b25672 100644 --- a/api/save_week_template_entries.php +++ b/api/save_week_template_entries.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — enregistre une semaine type composée dans l'éditeur (Service Enfance). + * Charge utile : agent_id, name, entries[], replace, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\WeekTemplateController; use App\Core\JsonResponse; diff --git a/api/structure_coverage_rules.php b/api/structure_coverage_rules.php index ce0a208..8e661bb 100644 --- a/api/structure_coverage_rules.php +++ b/api/structure_coverage_rules.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — règles de couverture d'un lieu (Service Enfance). + * Paramètre : structure_id. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\CoverageController; use App\Core\JsonResponse; diff --git a/api/structure_overview.php b/api/structure_overview.php index 654b499..d021012 100644 --- a/api/structure_overview.php +++ b/api/structure_overview.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — semaine d'un lieu, agent par agent. + * Inclut les agents ponctuellement planifiés, pas seulement les rattachés. + * Paramètres : structure_id, week. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\StructureController; use App\Core\JsonResponse; diff --git a/api/structure_planning_pdf.php b/api/structure_planning_pdf.php index 9ef0080..7692ee2 100644 --- a/api/structure_planning_pdf.php +++ b/api/structure_planning_pdf.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — planning hebdomadaire d'un lieu, au format PDF. + * Paramètres : structure_id, week. Sortie binaire : pas de bootstrap JSON. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\StructureController; $pdo = require dirname(__DIR__) . '/app/bootstrap.php'; diff --git a/api/team_members.php b/api/team_members.php index 1f59272..49709fc 100644 --- a/api/team_members.php +++ b/api/team_members.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — ajoute ou retire un agent d'une équipe (Service Enfance). + * Charge utile : action (ADD|REMOVE), team_id, agent_id, fonction_equipe, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\TeamController; use App\Core\JsonResponse; diff --git a/api/team_status.php b/api/team_status.php index 42b64d5..549e060 100644 --- a/api/team_status.php +++ b/api/team_status.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — change le statut d'une équipe (Service Enfance). + * Charge utile : team_id, statut (BROUILLON|A_CONTROLER|VALIDEE), csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\TeamController; use App\Core\JsonResponse; diff --git a/api/teams.php b/api/teams.php index ad5a11a..160068a 100644 --- a/api/teams.php +++ b/api/teams.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — liste des équipes, filtrable par date_debut / date_fin. + * POST — crée une équipe (Service Enfance). + * Charge utile POST : structure_id, type_equipe, libelle, date_debut, date_fin, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\TeamController; use App\Core\JsonResponse; diff --git a/api/update_agent.php b/api/update_agent.php index 573b26c..e4b2f21 100644 --- a/api/update_agent.php +++ b/api/update_agent.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — modifie la fiche d'un agent (Service Enfance). + * Ni le matricule ni la quotité de travail ne sont modifiables ici. + * Charge utile : agent_id, champs de la fiche, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\AgentController; use App\Core\JsonResponse; diff --git a/api/update_agent_entry.php b/api/update_agent_entry.php index 0438955..025cd2b 100644 --- a/api/update_agent_entry.php +++ b/api/update_agent_entry.php @@ -4,6 +4,14 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — modifie un créneau depuis la fiche agent. + * Peut changer de jour, de semaine et de lieu ; peut rouvrir un planning validé. + * Charge utile : entry_id, structure_id, motif_id, date, start, end, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\PlanningController; use App\Core\JsonResponse; diff --git a/api/update_structure.php b/api/update_structure.php index 5a2ce11..cf3c285 100644 --- a/api/update_structure.php +++ b/api/update_structure.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * POST — change le type d'un lieu d'affectation (Service Enfance). + * Charge utile : structure_id, type_affectation, csrf_token. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\StructureController; use App\Core\JsonResponse; diff --git a/api/vacation_periods.php b/api/vacation_periods.php index 302c4a0..166202d 100644 --- a/api/vacation_periods.php +++ b/api/vacation_periods.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — périodes de vacances enregistrées (Service Enfance). + * Paramètre : school_year (facultatif, « 2026-2027 »). + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\VacationController; use App\Core\JsonResponse; diff --git a/api/week_template.php b/api/week_template.php index a5f95f4..649b0b6 100644 --- a/api/week_template.php +++ b/api/week_template.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — contenu détaillé d'une semaine type (Service Enfance). + * Paramètres : agent_id, template_id — le couple sert de contrôle de périmètre. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\WeekTemplateController; use App\Core\JsonResponse; diff --git a/api/week_templates.php b/api/week_templates.php index 40cc564..4258f12 100644 --- a/api/week_templates.php +++ b/api/week_templates.php @@ -4,6 +4,13 @@ declare(strict_types=1); require_once dirname(__DIR__) . '/app/autoload.php'; +/** + * GET — semaines types d'un agent, avec leurs compteurs (Service Enfance). + * Paramètre : agent_id. + * + * Point d'entrée mince : toute la logique est dans le contrôleur appelé. + * Voir CLAUDE.md, section « Deux types de points d'entrée ». + */ use App\Controllers\WeekTemplateController; use App\Core\JsonResponse; diff --git a/app/Controllers/AgentController.php b/app/Controllers/AgentController.php index b57e1dc..1c6543d 100644 --- a/app/Controllers/AgentController.php +++ b/app/Controllers/AgentController.php @@ -20,6 +20,18 @@ use DateTimeImmutable; use PDO; use Throwable; +/** + * Fiche agent : consultation, référentiel des agents et documents PDF. + * + * Deux familles de méthodes cohabitent ici, avec des conventions d'erreur + * DIFFÉRENTES et qu'il ne faut pas mélanger : + * - les endpoints JSON, qui répondent via JsonResponse::send() ; + * - les endpoints PDF (pdf, timeSummaryPdf, hoursContractPdf), qui produisent + * un flux binaire. Leurs points d'entrée n'appellent PAS + * JsonResponse::bootstrap(), et ils signalent donc leurs erreurs par un + * http_response_code() suivi d'un `return` et d'un message en texte brut. + * Y écrire du JSON corromprait le document téléchargé. + */ final class AgentController { private AgentModel $agentModel; @@ -35,6 +47,13 @@ final class AgentController $this->access = new Access($pdo); } + /** + * GET api/agents.php — agents sélectionnables dans l'éditeur de planning. + * + * structure_id à 0 (ou absent) signifie « tous les lieux » : ce n'est licite + * que pour le Service Enfance, un responsable étant renvoyé en 403 par + * requireStructureEdit() dès qu'il vise un autre lieu que le sien. + */ public function listForPlanning(): void { $this->access->requireDraftEditor(); @@ -45,6 +64,15 @@ final class AgentController JsonResponse::send(200, ['agents' => $this->agentModel->listForLocation((int) $selectedLocation)]); } + /** + * GET api/agent_overview.php — semaine d'un agent, tous lieux confondus. + * + * Vue transverse par agent (et non par lieu comme api/planning.php) : c'est + * la seule qui donne la charge réelle d'un agent planifié à plusieurs + * endroits. En lecture seule pour le rôle AGENT. + * + * Paramètres GET : agent_id, week (« 2026-W08 »). + */ public function overview(): void { $agentId = filter_input(INPUT_GET, 'agent_id', FILTER_VALIDATE_INT); @@ -73,6 +101,21 @@ final class AgentController ]); } + /** + * GET api/agent_month_overview.php — grille mensuelle d'un agent. + * + * Construit un calendrier lundi→vendredi ALIGNÉ SUR LES SEMAINES ISO : la + * grille commence au lundi de la semaine du 1er du mois et finit au vendredi + * de la semaine du dernier jour. Elle déborde donc du mois, et le drapeau + * `in_month` de chaque jour permet à l'interface de griser les débordements. + * Sans cet alignement, une semaine serait coupée en deux et les cumuls + * hebdomadaires affichés seraient faux. + * + * Les créneaux sont chargés sur toute l'étendue de la grille, débordements + * compris, pour que les totaux de semaine restent justes. + * + * Paramètres GET : agent_id, month (« 2026-02 »). + */ public function monthOverview(): void { $agentId = filter_input(INPUT_GET, 'agent_id', FILTER_VALIDATE_INT); @@ -149,6 +192,16 @@ final class AgentController ]); } + /** + * GET api/agent_time_summary_pdf.php — bilan annuel d'heures (PDF). + * + * La période couverte n'est pas choisie par l'appelant : elle est celle + * calculée par QuotaModel (année civile 01/01 → 31/12), d'où la lecture de + * date_debut_periode / date_fin_periode dans le quota. Le paramètre `year` + * n'est qu'un raccourci vers le 1er janvier correspondant. + * + * Paramètres GET : agent_id, puis date OU year. + */ public function timeSummaryPdf(): void { $agentId = filter_input(INPUT_GET, 'agent_id', FILTER_VALIDATE_INT); @@ -194,6 +247,15 @@ final class AgentController ); } + /** + * GET api/agent_planning_pdf.php — planning d'un agent sur plusieurs semaines. + * + * `weeks` n'accepte que 6 ou 7 (7 par défaut) : au-delà, la grille ne tient + * plus sur une page A4 paysage et SimplePdf ne gère pas le report de tableau + * sur page suivante. + * + * Paramètres GET : agent_id, week (semaine de départ), weeks (6|7). + */ public function pdf(): void { $agentId = filter_input(INPUT_GET, 'agent_id', FILTER_VALIDATE_INT); @@ -257,6 +319,14 @@ final class AgentController ); } + /** + * GET api/agent_hours_contract_pdf.php — contrat horaire annuel (PDF). + * + * Document contractuel : il n'affiche que le volume annualisé dû, sans le + * détail des créneaux planifiés. + * + * Paramètres GET : agent_id, puis date OU year. + */ public function hoursContractPdf(): void { $agentId = filter_input(INPUT_GET, 'agent_id', FILTER_VALIDATE_INT); @@ -296,6 +366,19 @@ final class AgentController ); } + /** + * api/agent_assignments.php — rattachement principal d'un agent. + * + * Endpoint à double verbe, exception au reste de l'API : GET liste les + * agents, POST modifie un rattachement. Le GET sort par JsonResponse::send() + * qui termine le script, ce qui rend le `Request::requireMethod('POST')` + * suivant inatteignable en lecture — le flux tombe donc bien en séquence. + * + * Un structure_id nul est VALIDE : il détache l'agent de tout lieu par + * défaut, sans l'empêcher d'être planifié ponctuellement ailleurs. + * + * Charge utile (POST) : agent_id, structure_id (nullable), csrf_token. + */ public function assignments(): void { $this->access->requireService(); @@ -338,6 +421,19 @@ final class AgentController ]); } + /** + * POST api/create_agent.php — création d'un agent. + * + * Réservé au Service Enfance. Les contrôles vont au-delà du « non vide » : + * poste existant en base, type de contrat dans l'énumération, dates + * cohérentes entre elles, quotité dans ]0;100], longueurs alignées sur les + * colonnes SQL (une chaîne trop longue serait sinon tronquée silencieusement + * par MariaDB), et unicité du matricule (409, pas 422 : c'est un conflit + * avec l'existant, pas une saisie malformée). + * + * La réponse renvoie l'agent complet reconstitué, pour que l'interface + * l'insère dans sa liste sans avoir à recharger toute la page. + */ public function create(): void { $this->access->requireService(); @@ -411,6 +507,10 @@ final class AgentController 'commentaire_pta' => $ptaComment !== '' ? $ptaComment : null, ]); } catch (Throwable $e) { + // Seul endroit du projet qui utilise correctement + // Security::debugEnabled() (fermé par défaut). Les autres blocs + // catch testent `getenv('PTA_DEBUG') ?: '1'`, dont le défaut est + // OUVERT — voir la note dans PlanningController::save(). JsonResponse::send(500, [ 'error' => 'Impossible de créer l’agent.', 'details' => Security::debugEnabled() ? $e->getMessage() : null, @@ -444,6 +544,16 @@ final class AgentController ]); } + /** + * POST api/update_agent.php — modification de la fiche d'un agent. + * + * Mêmes contrôles que create(), matricule excepté : celui-ci n'est jamais + * modifiable, c'est la clé de rapprochement avec les outils RH. + * + * La quotité de travail n'est pas modifiable ici non plus : elle détermine + * le quota annuel déjà consommé, et la changer en cours d'année fausserait + * rétroactivement tous les suivis. + */ public function updateProfile(): void { $this->access->requireService(); @@ -523,6 +633,12 @@ final class AgentController ]); } + /** + * Décode « AAAA-Www ». Dupliqué dans plusieurs contrôleurs, chacun n'ayant + * pas de base commune ; toute correction doit être reportée partout. + * + * @return array{0: int, 1: int}|null [année ISO, semaine], ou null. + */ private function parseWeek(string $value): ?array { if (!preg_match('/^(\d{4})-W(\d{2})$/', $value, $matches)) { diff --git a/app/Controllers/AnnualOverviewController.php b/app/Controllers/AnnualOverviewController.php index 8ee008c..175d19c 100644 --- a/app/Controllers/AnnualOverviewController.php +++ b/app/Controllers/AnnualOverviewController.php @@ -14,12 +14,28 @@ use App\Models\QuotaModel; use PDO; use Throwable; +/** + * Vue annuelle d'un agent et validation de l'année en une opération. + * + * L'année de référence est l'année CIVILE (01/01 → 31/12), jamais l'année + * scolaire ni la date d'anniversaire du contrat : c'est la période sur laquelle + * s'apprécie le quota annualisé (voir QuotaModel). + * + * Réservé au Service Enfance : valider une année couvre par nature tous les + * lieux où l'agent est intervenu. + */ final class AnnualOverviewController { public function __construct(private PDO $pdo) { } + /** + * GET api/annual_overview.php — répartition de l'année d'un agent. + * + * L'année est facultative et retombe sur l'année en cours. + * Paramètres GET : agent_id, year (facultatif, borné à [2000, 2100]). + */ public function overview(): void { (new Access($this->pdo))->requireService(); @@ -42,12 +58,27 @@ final class AnnualOverviewController } /** + * POST api/annual_validate.php — contrôle puis validation de toute l'année. + * * Contrôle puis validation en une seule opération de tous les plannings * en brouillon de l'agent pour l'année civile affichée. * * Aucune validation partielle : si une erreur est trouvée, aucun planning * n'est validé. Les semaines concernées sont retournées au front afin de - * pouvoir les ouvrir dans un nouvel onglet et les corriger. + * pouvoir les ouvrir dans un nouvel onglet et les corriger. Un succès + * partiel laisserait l'utilisateur devant une année à moitié validée, sans + * moyen simple de savoir ce qui reste. + * + * Trois issues, alignées sur PlanningController::validate() : + * - 422 + status « errors » : au moins une ERREUR, rien n'est validé ; + * - 409 + status « warning » : quota annuel dépassé, confirmation attendue + * par un rappel avec force_quota: true ; + * - 200 + status « validated » ou « nothing_to_validate ». + * + * Contrairement à validate() unitaire, le quota est ici évalué à l'échelle + * de l'ANNÉE (annualForApi) et non de la semaine. + * + * Charge utile : agent_id, year, force_quota (bool), csrf_token. */ public function validateYear(): void { @@ -153,6 +184,24 @@ final class AnnualOverviewController } } + /** + * Contrôles bloquants d'un planning, dans la variante « année ». + * + * DIFFÉRENCE VOULUE avec PlanningController::validate() : les chevauchements + * inter-lieux sont recherchés via externalOverlaps() (tous statuts) et non + * validatedExternalOverlaps() (validés seulement). Une validation annuelle + * traite en un bloc l'ensemble des brouillons de l'agent : ils vont tous + * devenir opposables, deux brouillons qui se recouvrent doivent donc être + * signalés dès maintenant. + * + * Un contrôle INFO est ajouté quand rien n'a été trouvé, pour que + * l'interface affiche « aucune anomalie » plutôt qu'une liste vide + * indistincte d'une absence de contrôle. + * + * @param array $planning + * + * @return array + */ private function controlsForPlanning(PlanningModel $model, array $planning): array { $planningId = (int) $planning['id_planning']; @@ -203,6 +252,13 @@ final class AnnualOverviewController return $controls; } + /** + * Empile un contrôle au format commun {niveau, code, message}. + * Copie de PlanningController::addControl(), les deux contrôleurs n'ayant + * pas de base commune. + * + * @param array $controls + */ private function addControl(array &$controls, string $level, string $code, string $message): void { $controls[] = ['niveau' => $level, 'code' => $code, 'message' => $message]; diff --git a/app/Controllers/CoverageController.php b/app/Controllers/CoverageController.php index 8bef9fe..1b70f17 100644 --- a/app/Controllers/CoverageController.php +++ b/app/Controllers/CoverageController.php @@ -13,6 +13,19 @@ use App\Models\StructureModel; use PDO; use Throwable; +/** + * Contrôle de couverture : effectif planifié comparé au minimum attendu. + * + * Chaque lieu peut déclarer des règles de couverture (jour, plage horaire, + * nombre minimum d'agents). Ce contrôleur confronte ces règles aux plannings + * réels et remonte les « trous ». + * + * Deux niveaux de droits distincts : + * - alerts() : responsable et Service Enfance, un responsable étant forcé sur + * son propre lieu quoi qu'il demande ; + * - rules() / saveRules() : Service Enfance seul, les règles étant un + * référentiel et non une donnée de saisie. + */ final class CoverageController { private CoverageModel $coverageModel; @@ -26,6 +39,22 @@ final class CoverageController $this->access = new Access($pdo); } + /** + * GET api/coverage_alerts.php — trous de couverture d'une semaine. + * + * Sans structure_id, balaie TOUS les lieux actifs. Le structure_id demandé + * est ignoré pour un responsable, écrasé par son propre lieu : un simple 403 + * l'empêcherait de consulter son écran avec une URL partagée. + * + * Trois familles de retours, à ne pas confondre : + * - `alerts` : plages réellement sous-couvertes ; + * - `validation_warnings` : couverture assurée par des plannings encore en + * brouillon, donc pas encore fiable ; + * - `unconfigured_structures` : lieux sans aucune règle. Ils ne peuvent pas + * produire d'alerte, et les taire les ferait passer pour conformes. + * + * Paramètres GET : week, structure_id (facultatif). + */ public function alerts(): void { $this->access->requireRoles([Access::ROLE_RESPONSABLE, Access::ROLE_SERVICE]); @@ -100,6 +129,9 @@ final class CoverageController ]); } + /** + * GET api/structure_coverage_rules.php — règles de couverture d'un lieu. + */ public function rules(): void { $this->access->requireService(); @@ -119,6 +151,19 @@ final class CoverageController ]); } + /** + * POST api/save_structure_coverage_rules.php — remplace les règles d'un lieu. + * + * Remplacement INTÉGRAL : la liste reçue devient l'unique jeu de règles du + * lieu, et une liste vide supprime toute règle (le lieu redevient « non + * configuré »). Il n'y a pas d'ajout ni de suppression unitaire. + * + * Les règles sont validées ici — jour ouvré, horaires au quart d'heure, fin + * après début, minimum dans [1, 50], puis absence de chevauchement — avant + * d'être confiées au modèle, qui n'effectue aucun contrôle métier. + * + * Charge utile : structure_id, rules[], csrf_token. + */ public function saveRules(): void { $this->access->requireService(); @@ -182,6 +227,15 @@ final class CoverageController ]); } + /** + * Refuse deux plages de couverture qui se recouvrent le même jour. + * + * Les règles sont regroupées par jour puis triées : il suffit alors de + * comparer chaque début à la fin précédente, en O(n log n) et non en O(n²). + * Des plages jointives sont acceptées (une fin égale à un début). + * + * @param array $rules + */ private function assertNoOverlap(array $rules): void { $byDay = []; @@ -203,6 +257,7 @@ final class CoverageController } } + /** HH:MM au quart d'heure, entre 00:00 et 23:45. */ private function validQuarterHour(string $time): bool { if (!preg_match('/^(?:[01]\d|2[0-3]):(?:00|15|30|45)$/', $time)) { @@ -211,17 +266,24 @@ final class CoverageController return true; } + /** « 09:30 » → 570. Comparer des minutes évite les pièges de tri de chaînes. */ private function timeToMinutes(string $time): int { [$hours, $minutes] = array_map('intval', explode(':', $time)); return ($hours * 60) + $minutes; } + /** Durée en minutes, plancher à 0 : jamais de total négatif dans les cumuls. */ private function durationMinutes(string $start, string $end): int { return max(0, $this->timeToMinutes($end) - $this->timeToMinutes($start)); } + /** + * Décode « AAAA-Www ». Copie locale, comme dans les autres contrôleurs. + * + * @return array{0: int, 1: int}|null [année ISO, semaine], ou null. + */ private function parseWeek(string $value): ?array { if (!preg_match('/^(\d{4})-W(\d{2})$/', $value, $matches)) { diff --git a/app/Controllers/DashboardController.php b/app/Controllers/DashboardController.php index 18880b6..dc51738 100644 --- a/app/Controllers/DashboardController.php +++ b/app/Controllers/DashboardController.php @@ -25,6 +25,8 @@ use PDO; */ final class DashboardController { + /** Nombre d'éléments détaillés par bloc : un aperçu, pas une liste complète. + * Chaque bloc renvoie vers l'écran dédié pour la suite. */ private const APERCU_MAX = 5; private const QUOTA_APERCU_MAX = 8; @@ -45,6 +47,19 @@ final class DashboardController $this->vacationModel = new VacationModel($pdo); } + /** + * GET api/dashboard_summary.php — données du tableau de bord. + * + * Deux portées : + * - scope=badges : uniquement le compteur de plannings en attente. Cette + * variante est appelée depuis TOUTES les pages pour alimenter la pastille + * de navigation ; elle doit rester à une seule requête SQL ; + * - portée complète : les quatre blocs de l'écran, ce qui représente + * plusieurs dizaines de requêtes et n'est acceptable que sur le tableau + * de bord lui-même. + * + * Paramètres GET : scope (badges|absent), week, year (facultatifs). + */ public function summary(): void { $this->access->requireService(); @@ -264,6 +279,12 @@ final class DashboardController } /** + * Décode la semaine demandée, avec repli SILENCIEUX sur la semaine courante. + * + * Contrairement aux endpoints de saisie, une semaine illisible n'est pas une + * erreur ici : le tableau de bord doit toujours s'afficher, quitte à montrer + * la semaine en cours. Fuseau explicite, le conteneur PHP tournant en UTC. + * * @return array{value: string, iso_year: int, iso_week: int, start: DateTimeImmutable} */ private function resolveWeek(mixed $value): array @@ -294,6 +315,9 @@ final class DashboardController ]; } + /** + * Année du suivi de quota, avec repli sur l'année ISO de la semaine affichée. + */ private function resolveYear(mixed $value, int $fallback): int { $year = filter_var($value, FILTER_VALIDATE_INT, ['options' => ['min_range' => 2000, 'max_range' => 2100]]); diff --git a/app/Controllers/PageController.php b/app/Controllers/PageController.php index f824215..80fa2d0 100644 --- a/app/Controllers/PageController.php +++ b/app/Controllers/PageController.php @@ -15,6 +15,27 @@ use DateTimeImmutable; use DateTimeZone; use PDO; +/** + * Rendu de toutes les pages HTML de l'application. + * + * Chaque fichier .php de la racine appelle runPage(''), qui appelle la + * méthode homonyme de cette classe. Le NOM DE LA MÉTHODE fait donc trois choses + * à la fois : il est la route, la clé de page dans acces_role_page, et la valeur + * de $activePage qui surligne l'onglet courant. + * + * Ajouter une page suppose donc, ensemble : + * 1. un fichier mince à la racine ; + * 2. une méthode ici ; + * 3. une vue app/Views/pages/ et son partiel app/Views/partials/ ; + * 4. un module JS ; + * 5. l'inscription de la clé dans $navigation / $navigationGroups + * (Views/layouts/header.php) ; + * 6. une migration SQL insérant la ligne dans acces_role_page — les droits + * sont lus en base, jamais écrits en PHP. Sans elle, la page est refusée. + * + * Chaque méthode déclare les scripts et modules JS à charger ; footer.php les + * injecte et page-bootstrap.js appelle init() sur chaque module. + */ final class PageController extends Controller { private Access $access; @@ -24,6 +45,10 @@ final class PageController extends Controller $this->access = new Access($pdo); } + /** + * Tableau de bord du Service Enfance (V7.9) — page d'accueil de ce rôle. + * Voir Access::homeUrl() pour le repli si la migration n'est pas jouée. + */ public function dashboard(): void { $this->access->requirePage('dashboard'); @@ -38,6 +63,20 @@ final class PageController extends Controller ]); } + /** + * Écran de saisie — cœur de l'application. + * + * Le lieu est VERROUILLÉ pour un responsable de structure + * (`structureLocked`) : il ne peut saisir que chez lui. Le verrou n'est + * qu'un confort d'interface, le serveur retranche de toute façon. + * + * Les scripts de semaine type ne sont chargés que si la permission + * can_use_templates est accordée : inutile d'envoyer 1 300 lignes de JS à un + * utilisateur qui n'y a pas droit. La page ouvre alors deux modes exclusifs + * (éditeur de semaine type / saisie semaine par semaine, voir + * README_V7_10.md) ; `focus` et `week` forcent le second mode, car ce sont + * les paramètres des liens profonds venus des autres écrans. + */ public function planning(): void { $this->access->requirePage('planning'); @@ -71,6 +110,7 @@ final class PageController extends Controller ]); } + /** File des plannings en attente de validation (Service Enfance). */ public function pending(): void { $this->access->requirePage('pending'); @@ -81,6 +121,7 @@ final class PageController extends Controller ]); } + /** Contrôle de couverture : plages où l'effectif passe sous le minimum du lieu. */ public function coverage(): void { $this->access->requirePage('coverage'); @@ -98,6 +139,7 @@ final class PageController extends Controller ]); } + /** Planning d'un lieu sur une semaine, en lecture seule. */ public function structures(): void { $this->access->requirePage('structures'); @@ -115,6 +157,12 @@ final class PageController extends Controller ]); } + /** + * Planning d'un agent, mois par mois et tous lieux confondus. + * + * Un AGENT est verrouillé sur lui-même (`agentLocked`) et le titre bascule + * sur « Mon planning » : la page sert alors de vue personnelle. + */ public function agents(): void { $this->access->requirePage('agents'); @@ -136,6 +184,7 @@ final class PageController extends Controller ]); } + /** Vue annuelle (janvier -> décembre) et validation de l'année entière. */ public function annual(): void { $this->access->requirePage('annual'); @@ -151,6 +200,7 @@ final class PageController extends Controller ]); } + /** PTA détaillé d'un agent : souhaits de lieux, contraintes, répartition. */ public function pta(): void { $this->access->requirePage('pta'); @@ -167,6 +217,7 @@ final class PageController extends Controller ]); } + /** Composition des équipes sur les mercredis et les vacances. */ public function teams(): void { $this->access->requirePage('teams'); @@ -183,6 +234,11 @@ final class PageController extends Controller ]); } + /** + * Périodes de vacances scolaires : elles déterminent le contexte + * périscolaire / extrascolaire de chaque journée, et sont importables depuis + * l'API data.education.gouv.fr (SchoolHolidayApiService). + */ public function vacations(): void { $this->access->requirePage('vacations'); @@ -193,6 +249,7 @@ final class PageController extends Controller ]); } + /** Référentiels : agents, lieux, postes, règles de couverture. */ public function administration(): void { $this->access->requirePage('administration'); @@ -220,6 +277,21 @@ final class PageController extends Controller ]); } + /** + * Fabrique commune à toutes les pages : en-têtes de sécurité puis rendu. + * + * Pose les clés attendues par header.php et footer.php avec des valeurs par + * défaut, que $data écrase. Une page qui oublie 'scripts' ou 'motifs' rendra + * donc correctement au lieu de lever une notice sur variable indéfinie. + * + * Security::sendHtmlHeaders() DOIT être appelé avant tout rendu : il pose la + * CSP à nonce, et $cspNonce est ce que chaque