--- id: KB-PLUGIN-039 title: "GLPI 11 — Substrato nativo de gestão de projetos/chamados (Kanban, precedência, planning) reutilizável por plugin" domain: plugin-dev tags: - glpi11 - plugin - kanban - project - projecttask - ticket - planning - gantt - precedence - teamwork - mindscrum - architecture status: active severity: high created_at: 2026-07-10 updated_at: 2026-07-10 applies_to: - GLPI 11.0.8 dev (container devportal_glpi) - plugin mindscrum (Kanban unificado + Gantt de recursos) related_records: - KB-PLUGIN-028 - KB-PLUGIN-029 - KB-PLUGIN-031 - KB-PLUGIN-036 --- # GLPI 11 — Substrato nativo de gestão de projetos/chamados reutilizável por plugin Mapa do que o **core do GLPI 11 já entrega** para gestão de projetos, chamados, tarefas, técnicos, precedência e agenda — levantado por leitura do código-fonte em `/var/www/glpi/src/` (não é suposição; cada item foi verificado no fonte). Base de decisão do plugin **mindscrum** (Kanban unificado + Gantt de recursos): **herdar o motor, construir só as superfícies que faltam.** ## Kanban nativo — trait + interface, single-itemtype - `Glpi\Features\Kanban` (trait) + `Glpi\Features\KanbanInterface` (contrato). - **Quem implementa:** `Project` e `CommonITILObject` (`use Glpi\Features\Kanban; implements KanbanInterface, TeamworkInterface`) → logo **Ticket, Change e Problem já têm Kanban nativo**, além de Projeto. - Cada board é de **um único itemtype**. Não há board multi-itemtype nativo. → **Este é o gap que o mindscrum preenche** (juntar Ticket + ProjectTask numa tela). - **Coluna = `column_field`:** `status` para ITIL (`getAllKanbanColumns('status')` em `CommonITILObject`), `projectstates_id` para `Project`/`ProjectTask`. Mover card grava o status/estado nativo — a regra de transição é do GLPI. - Métodos-chave do contrato (`KanbanInterface`): `getDataToDisplayOnKanban`, `getKanbanColumns`, `getAllKanbanColumns`, `showKanban`, `getAllForKanban`, `canModifyGlobalState`, `prepareKanbanStateForUpdate` (hook para vetar/alterar save), `canOrderKanbanCard`, e o ponto de extensão de plugin **`getKanbanPluginFilters($itemtype)`**. - **Persistência do board:** `Item_Kanban::saveStateForItem($itemtype,$items_id,$state)` / `loadStateForItem()` → tabela `glpi_items_kanbans` (state em JSON, por usuário ou global). Passa por `prepareKanbanStateForUpdate()` antes de gravar. - **UI reutilizável:** componente Twig `templates/components/kanban/kanban.html.twig` + componente JS do Kanban do core. ## Estados / colunas customizáveis - `ProjectState` (dropdown) é a lista de estados de projeto/task — **customizável**, serve de coluna. Status de chamado é fixo (enum 1..6: novo, atrib., planejado, pendente, resolvido, fechado). Reconciliar esses dois modelos numa coluna única é o **miolo da regra** do board unificado. ## Precedência entre tarefas (base de Gantt) — JÁ EXISTE - `ProjectTaskLink` → tabela `glpi_projecttasklinks`, campos `projecttasks_id_source`, `projecttasks_id_target`, `type`. - **4 tipos clássicos:** `finish_to_start=0`, `start_to_start=1`, `finish_to_finish=2`, `start_to_finish=3`. É exatamente o modelo de dependência de um Gantt — não precisa criar tabela nova para precedência. ## Elo Projeto ↔ Chamado — JÁ EXISTE - `ProjectTask_Ticket` → tabela `glpi_projecttasks_tickets`, liga `projecttasks_id` ↔ `tickets_id`. O relacionamento que o board unificado quer representar já é modelado (e a classe já cruza `ProjectState`). ## Planning / agenda / alocação — JÁ EXISTE - `ProjectTask` **é plannable:** `use Glpi\Features\PlanningEvent`, campos `plan_start_date`/`plan_end_date` e `real_start_date`/`real_end_date`; implementa `CalDAVCompatibleItemInterface` e `TeamworkInterface`. - **Detecção de conflito de recurso:** `Planning::checkAlreadyPlanned($users_id, $begin, $end)` já avisa quando um técnico é agendado em dobro — espinha dorsal da visão "capacidade por técnico" do Gantt de recursos. - Também plannable e alimentando o Planning: `TicketTask`, `ChangeTask`, `ProblemTask`, `PlanningExternalEvent`, `Reminder`. ## Equipe / técnicos — TeamworkInterface - `Glpi\Features\TeamworkInterface`: `getTeamRoles()`, `getTeamRoleName()`, `getTeamItemtypes()`, `addTeamMember()`, `deleteTeamMember()`, `getTeam()`. - Papéis via `Team::ROLE_*`: Projeto usa `ROLE_OWNER`/`ROLE_MEMBER`; ITIL usa `ROLE_REQUESTER`/`ROLE_OBSERVER`/`ROLE_ASSIGNED`. Vínculo técnico↔tarefa via `ProjectTaskTeam` / `ProjectTeam`. ## Gantt nativo é PLUGIN, não core - O core apenas condiciona: `$plugin->isActivated('gantt')` e expõe o campo `show_on_global_gantt`. O Gantt em si vem do plugin `gantt`. Ou seja, **estender a gestão de projeto por plugin é o caminho oficial** — o mindscrum segue o mesmo padrão, com foco em Gantt de *recursos* (por técnico), que o nativo não cobre. ## Implicações para o mindscrum | Necessidade | Veredito | O que usar | |---|---|---| | Mover card muda status | herdar | `update()` nativo do itemtype (Ticket/ProjectTask) | | Colunas = estados nativos | herdar | `status` (ITIL) / `ProjectState` | | Precedência de tarefas | herdar | `ProjectTaskLink` (4 tipos) | | Projeto ↔ chamado | herdar | `ProjectTask_Ticket` | | Conflito de alocação | herdar | `Planning::checkAlreadyPlanned()` | | Técnicos por tarefa | herdar | `TeamworkInterface` / `ProjectTaskTeam` | | **Board multi-itemtype (Ticket+ProjectTask)** | **construir** | página full-screen do plugin (nativo é single-itemtype) | | **Timeline de capacidade por técnico** | **construir** | consome Planning; render próprio | | Chat/notas de execução no card | construir | tickets têm `ITILFollowup`; ProjectTask exige tabela auxiliar leve | ## Regra para agentes Antes de recriar qualquer coisa de projeto/chamado/agenda no mindscrum, checar esta tabela: quase tudo é **herança do core**, não desenvolvimento novo. Escrever de volta sempre pelos models nativos (`->update()`), nunca `UPDATE` direto — assim transição de status, histórico (`Log`) e regras do GLPI continuam válidos.