# Workflow/BPM isolado — possibilidade de alto valor (fora da sequência)

| Campo | Valor |
|---|---|
| **Prioridade** | **Alto valor — somente sob demanda real** |
| **Status** | **Possibilidade** (não é fase, não entra em P0–P29, não é padrão) |
| **Origem** | Análise do requisito contratual de BPMS para e-SIC/Ouvidoria (Fundão 008476/2025) + padrão “landing sections” |
| **ADR provável** | ADR própria — “Workflow/BPM como serviço isolado, por demanda” |
| **Relaciona** | Diário Oficial (P15), e-SIC/Ouvidoria (P11/P25), Notícias (P6), Carta de Serviços (P15), LGPD (P25); ADR-001, ADR-002, ADR-009, ADR-013, ADR-015, ADR-016, ADR-017, ADR-019, ADR-020, ADR-025, ADR-028, ADR-033, ADR-035, ADR-038/039/040, ADR-041, ADR-043 |

## 1. Veredito e posicionamento

**É uma possibilidade de alto valor, não uma obrigação do produto.** Deve ser construída **totalmente
isolada**, como um serviço opcional, do mesmo jeito que “landing sections” é uma capacidade de
layout usada por um módulo — não um módulo que todos importam.

- **Não entra na sequência P0–P29.**
- **Não é instalada por padrão**, não é ativada por padrão e não é requisito de nenhum módulo.
- **Só nasce mediante demanda real** de um processo com dono, volume e ROI claros.
- **Integra-se quando cabível** ao Diário Oficial, e-SIC/Ouvidoria, Notícias ou Carta de Serviços;
  nenhum deles passa a depender dela.
- **Não é um BPMS completo.** É um motor de workflow com um subconjunto explícito; BPMN 2.0 é
  notação de autoria/intercâmbio, não o runtime.
- Se o contrato exigir “BPMN 2.0 completo + motor BPMS”, a decisão é outra: integrar um BPMS
  separado (Camunda 7/Flowable) — ver [`bpms-ouvidoria-esic.md`](./bpms-ouvidoria-esic.md).

## 2. Por que alto valor

| Ganho | Consequência |
|---|---|
| Reuso de aprovações, filas, prazos, notificações e inbox | Evita reimplementar o mesmo fluxo em Diário, e-SIC, Notícias e Carta de Serviços |
| Fluxo versionado como dado | Mudança de processo sem deploy; versões antigas continuam válidas |
| Auditoria única de transições | Eventos, ator, antes/depois e prazos coerentes entre módulos |
| Trilha pública sanitizada | Cidadão acompanha status/timeline sem expor lanes, scripts ou PII |
| Isolamento | O serviço evolui e é testado sozinho; módulos só conhecem o contrato |
| Opcionalidade | Quem não precisa continua com enums/Actions simples; sem custo de complexidade |

O valor é **alto** porque o custo de repetir isso em cada módulo também é alto. O risco é igualmente
alto: motor de workflow é uma das peças mais fáceis de errar (concorrência, timers, versão,
idempotência, auditoria e autorização).

## 3. Isolamento (contrato com o resto do V7)

```mermaid
flowchart LR
  M[Modules: Diario, Esic, Noticias] -->|Contracts| W[Services/Workflow]
  W --> DB[(Postgres: workflow_*)]
  W --> CORE[Core: Clock, IdGen, Audit, Permissions]
  W --> UI[Admin /cms/workflow]
  W -. opcional .-> N[Notifications]
  W -. opcional .-> MEDIA[Media]
```

- **Serviço:** `src/services/Workflow` com `ServiceProvider` implementando `Core\Contracts\Service`;
  descoberto por convenção (ADR-015), sem registro manual em `bootstrap/providers.php`.
- **Contrato no service:** `Services\Workflow\Contracts\WorkflowEngine`,
  `WorkflowRegistry`, `WorkflowSubject`, `WorkflowHandler`; módulos dependem da **interface**, nunca
  da implementação.
- **O service nunca importa módulos.** Módulos registram definições/handlers no
  `WorkflowRegistry` a partir do próprio `ModuleProvider::register()`.
- **UI administrativa opcional:** módulo isolado `Ferramentas/Workflow` (ou superfície admin do
  service, se ADR-015/ADR-033 permitirem), em `/cms/workflow`; permissões `workflow.*` declaradas
  pelo módulo. O engine funciona headless sem essa UI.
- **Sem flag global**: a instalação do service é a “flag”. Nenhum módulo o consome por acidente.
- **Sem seed de processo em produção** (ADR-041); demonstração só em `src/demonstration/**`.

## 4. Conceitos gerais

### 4.1 Definição × instância × tarefa

- **Definição** (`workflow_definitions`): chave estável (`diario.publicacao`,
  `esic.pedido`), nome, dono, ativa/inativa.
- **Versão** (`workflow_versions`): grafo imutável em `jsonb`, checksum, status
  `draft|published|archived`. Instâncias **pinam** a versão; publicar não muda processos em curso.
- **Instância** (`workflow_instances`): um caso concreto; `subject_type`/`subject_id` apontam para
  o registro do módulo (ex.: `diario_edicoes:{id}`), `current_node`, `context` `jsonb`, prazos.
- **Tarefa** (`workflow_tasks`): unidade de trabalho humana ou manual; `ready|claimed|completed|
  cancelled`, fila/usuário, formulário, prazo.
- **História** (`workflow_history`): transições e eventos de negócio para a linha do tempo; a
  evidência forense continua no audit trail do Core (ADR-035).

### 4.2 Subconjunto BPMN suportado (v1)

| Elemento | v1 | Observação |
|---|---|---|
| Start/End simples | Sim | Um start por definição |
| User Task | Sim | Obrigatório formulário versionado |
| Manual Task | Sim | Sem formulário; conclusão registrada |
| Service Task | Sim, via handler registrado | Nunca HTTP/script arbitrário |
| Exclusive Gateway (XOR) | Sim | Condições declarativas |
| Parallel Gateway (AND) | Sim | Fork/join com token determinístico |
| Inclusive Gateway (OR) | Fase 2 | Só com semântica testada |
| Timer intermediário/boundary | Sim | `due_at` + comando `workflow:tick` |
| Message/Send/Receive | Sim, via Notifications/porta | E-mail primeiro; WhatsApp é adaptador |
| Subprocess/Call Activity | Fase 2 | Reuso de definição, não de código |
| Event-based Gateway | Fase 2 | Exige correlação de eventos |
| Error/Escalation/Compensation | Fase 2/3 | Não no MVP |
| Script Task | **Não** | Execução de código no PHP é proibida |
| DMN | Fase 3 | Decisão tabular JSON antes de DMN |
| Choreography/Collaboration | **Não** | Fora do escopo de workflow interno |

**Sem promessa de conformidade BPMN 2.0.** O rótulo honesto é “baseado em um subconjunto BPMN 2.0”.
Se o cliente exigir conformidade, usar um BPMS separado.

### 4.3 Dados e formulários

BPMN não define estrutura de dados nem linguagem de expressão (cláusula 10.4); o serviço precisa de
um contrato próprio:

- **Formulário** (`workflow_forms`): `schema` `jsonb` com campos, tipos, validação, máscara,
  visibilidade condicional, somente leitura, upload; versão imutável.
- **Submissão** (`workflow_form_submissions`): snapshot `jsonb` do que foi enviado + versão do
  formulário; mudar o formulário não reescreve o passado.
- **Contexto da instância** (`workflow_instances.context`): dados derivados e referências, não HTML.
- **Condições**: avaliador declarativo e allowlist (comparações, `and/or/not`, presença, data);
  **nunca** `eval`, JavaScript, Groovy ou Python.
- **Formulário inicial**: vinculado ao start event; cria a instância e valida o schema.
- **Formulário por tarefa**: obrigatório em `user_task`; o botão “Concluir” valida e transiciona.

### 4.4 Documentos e templates

- `workflow_document_types`: chave, nome, `digital` bool, tamanho máximo, template AST, permissões.
- `workflow_documents`: instância, tipo, `media_id`, status, gerado em.
- Templates usam **TipTap AST** (ADR-028), nunca HTML/CSS no banco; geração de PDF é renderer, não
  editor livre.
- Tipos de documento podem ser obrigatórios/únicos por processo; exclusão é **soft delete** e
  bloqueada se houver instância ativa.
- Não é um DMS genérico: é o conjunto de documentos do processo.

### 4.5 Filas, grupos e atribuição

O modelo atual (ADR-033) tem **um perfil por usuário** e não tem grupos. O workflow precisa de
**filas de trabalho**, que são diferentes de perfis de autorização:

- `workflow_queues` (`key`, `name`, `active`) — ex.: `ouvidoria.triagem`, `diario.revisao`.
- `workflow_queue_members` (`queue_id`, `user_id`) — múltiplos usuários por fila.
- Tarefa pode ser atribuída a **fila** ou a **usuário**; `claim` é explícito e auditado.
- Permissões continuam sendo as quatro ações do módulo; a fila não concede permissão, só organiza
  trabalho.
- **Não** criar grupos de autenticação paralelos; se o cliente exigir “grupos” como autorização,
  isso é uma ADR de identidade separada.

### 4.6 Inbox de tarefas

- Lista com filtros por nome, prioridade, responsável, fila e datas; paginação, ordenação e
  tamanho de página (atende 215–221).
- Ações: assumir, liberar, concluir, encaminhar, abandonar em lote; cada uma com transação,
  autorização, idempotência e auditoria.
- Índices: `(queue_id, status, due_at)`, `(assignee_id, status, due_at)`, `(instance_id, status)`.
- Sem “tempo real” por WebSocket no v1; polling/ETag ou SSE é suficiente e cacheável.

## 5. Modelo de dados (esboço)

| Tabela | Campos principais |
|---|---|
| `workflow_definitions` | `id` uuidv7, `key` unique, `name`, `owner_module`, `active`, `current_version_id`, timestamps |
| `workflow_versions` | `id`, `definition_id`, `version` int, `schema` jsonb, `checksum`, `status`, `published_at`, `created_by`, timestamps; unique `(definition_id, version)` |
| `workflow_instances` | `id`, `definition_id`, `version_id`, `subject_type`, `subject_id`, `status`, `current_node`, `context` jsonb, `due_at`, `started_at`, `ended_at`, `correlation_id`, timestamps |
| `workflow_tasks` | `id`, `instance_id`, `node_key`, `type`, `status`, `queue_id`, `assignee_id`, `form_version_id`, `data` jsonb, `due_at`, `claimed_at`, `completed_at`, timestamps |
| `workflow_queues` | `id`, `key` unique, `name`, `active`, timestamps |
| `workflow_queue_members` | `queue_id`, `user_id`, unique; FK `cascade` |
| `workflow_forms` | `id`, `key`, `version`, `schema` jsonb, `status`, timestamps; unique `(key, version)` |
| `workflow_form_submissions` | `id`, `instance_id`, `form_version_id`, `data` jsonb, `submitted_by`, timestamps |
| `workflow_document_types` | `id`, `key`, `name`, `digital`, `max_bytes`, `template_ast` jsonb, `active`, timestamps |
| `workflow_documents` | `id`, `instance_id`, `document_type_id`, `media_id`, `status`, `generated_at`, timestamps |
| `workflow_history` | `id`, `instance_id`, `task_id` null, `from_node`, `to_node`, `event`, `actor_id`, `metadata` jsonb, `created_at` |

Regras:

- `jsonb` para definição/contexto/schema/template; **nada de HTML/CSS** (ADR-017).
- `uuidv7()` nativo (ADR-007); `timestamptz`; `text`; índices explícitos.
- Migrations idempotentes; `down()` nunca dropa dado (`backup_*`, ADR-017).
- Snapshot de versão: instância sempre aponta para `version_id` imutável.
- Contadores por diagrama (170) e “sincronizado” (171) são consultas/derivados de
  `definition_id`/`checksum`, não colunas mágicas.

## 6. Execução, concorrência e determinismo

- **Transição em transação:** `SELECT ... FOR UPDATE` na instância; validar estado atual; gravar
  tarefa/histórico; commit; jobs de notificação só após commit.
- **Idempotência:** `Idempotency-Key` nas ações de API; unique em `(instance_id, node_key, status)`
  para evitar dupla conclusão.
- **Timers:** comando `workflow:tick` (scheduler de 1 min) varre `due_at <= now()` com índice;
  recalcula com `Clock` injetado; não cria um job por instância.
- **Determinismo:** `Clock`/`IdGen` injetados; ordem de transições explícita; nenhum `now()`/
  `rand()` no corpo; testes com relógio fixo.
- **Eventos:** Laravel Events/Listeners **após commit**, com IDs, sem payload de PII; a trilha
  forense usa `AuditWriter` (ADR-035).
- **Falha:** service task/handler pode falhar; tarefa vai para `failed`, com retry limitado e
  histórico; não “perde” a instância.
- **Cancelamento:** encerra tarefas abertas, grava motivo e ator; não apaga histórico.

## 7. Integração com módulos

### 7.1 Contrato

```php
interface WorkflowEngine
{
    public function start(string $definitionKey, WorkflowSubject $subject, array $context = []): WorkflowInstance;
    public function claim(string $taskId, string $userId): WorkflowTask;
    public function complete(string $taskId, string $userId, array $formData = []): WorkflowInstance;
    public function cancel(string $instanceId, string $userId, string $reason): void;
    public function status(string $instanceId): WorkflowStatus;
}
```

- `WorkflowSubject` expõe `type(): string`, `id(): string`, `onTransition(WorkflowEvent): void`.
- O módulo guarda **apenas** `workflow_instance_id` (ou deriva o status do service); não duplica
  `status` em duas colunas.
- Se o módulo já tem status legal (`esic.status`), decidir uma **fonte da verdade**:
  recomendação = workflow é a orquestração; o módulo mantém o status legal e sincroniza por
  `onTransition`, com teste de consistência. Nunca duas máquinas de estado independentes.

### 7.2 Diário Oficial

- Processo `diario.publicacao`: `rascunho → revisão → aprovado → publicado` com quatro olhos.
- User task “Revisar” e “Publicar” com formulários; `workflow_queues`: `diario.revisao`,
  `diario.publicacao`.
- A publicação continua sendo ação do módulo; o workflow não gera PDF sozinho.
- Integração opcional: o Diário pode continuar com seus enums se não houver demanda.

### 7.3 e-SIC/Ouvidoria

- Processos `esic.pedido` e `ouvidoria.manifestacao`: recebida, análise, resposta, recurso,
  encerramento; prazos e prorrogação; fila por setor.
- Formulário inicial = formulário público do módulo; tarefas internas = análise/resposta.
- Notificação por e-mail em cada transição; timeline pública sanitizada.
- Sem scripts/DMN no MVP; regras de prazo e indeferimento são campos/ações do módulo.

### 7.4 Notícias/Carta de Serviços

- Notícias: aprovação editorial (rascunho → pendente → publicado/rejeitado) se o módulo quiser
  sair do enum atual.
- Carta de Serviços: backoffice de solicitação, não a jornada pública.
- Nenhum módulo é migrado à força; cada um opta.

## 8. BPMN: autoria × runtime

- **Runtime canônico = JSON** do serviço (`workflow_versions.schema`), validado por schema.
- **BPMN XML é adaptador**: `BpmnSubsetImporter` lê um subconjunto, rejeita o resto e converte para
  JSON; `BpmnExporter` gera XML para documentação/intercâmbio.
- Importação segura: `DOMDocument` com `LIBXML_NONET`, sem entidades externas, sem `bpmn:import`
  remoto, limite de tamanho, sem `scriptTask`; erros explícitos.
- **Validação**: XSD é necessário, mas não suficiente; regras semânticas (um start, reachability,
  gateways balanceados, tarefas com formulário) são do serviço. O XSD local atual está incompleto
  (falta `xmlns:xsd`, `DC.xsd`/`DI.xsd`), então não prometer validação BPMN sem o conjunto oficial.
- **Sem alegar conformidade**: “subset BPMN 2.0” é o máximo honesto sem BPMS.
- **Canvas**: se um dia houver editor visual, `bpmn-js`/`diagram-js` são MIT, mas são JS pesado e
  reativo; exigem ADR-009 e fallback acessível. O v1 é editor de lista/estado + swimlanes, sem
  canvas livre.

## 9. Segurança e LGPD

- **Sem scripts** (JS/Groovy/Python) no processo PHP; se o contrato exigir, sandbox isolado,
  sem rede, CPU/memória/tempo limitados, allowlist e ADR específica.
- **Sem API arbitrária** no v1: service task chama um `WorkflowHandler` registrado no código; HTTP
  externo é um handler do módulo, com allowlist, timeout, retry e idempotência.
- **Sem PII em log/telemetria**: IDs, status, prazos; conteúdo de formulário/documento fica no
  banco, com classificação/retention (ADR-019).
- **CSP/Trusted Types**: admin sem inline; sem HTML de template; PDF renderizado server-side.
- **Autorização**: tarefa só é concluída por quem tem a permissão do módulo + vínculo com a fila;
  `claim` não contorna policy.
- **Auditoria**: toda transição, atribuição, cancelamento e geração de documento gera `AuditEntry`;
  `workflow_history` é timeline de negócio, não substitui evidência.
- **Portal**: timeline sanitizada, link assinado, sem lanes internas, sem scripts, sem IDs de API.

## 10. Acessibilidade e UI

- V1 sem canvas: lista de estados/transições, formulários Blade, inbox com tabela semântica,
  filtros nativos, paginação acessível (ADR-025).
- Se houver canvas: paleta restrita, atalhos de teclado, descrição textual equivalente, fallback
  em tabela; o canvas não pode ser o único caminho.
- Formulário público funciona sem JS; condicionais são server-side quando possível.
- Mensagens de erro por campo, `aria-describedby`, foco gerenciado; axe/e2e no CMS e portal.

## 11. O que NÃO é

- Não é um BPMS completo, Camunda/Flowable, DMN, choreography ou WS-BPEL.
- Não é um DMS genérico, helpdesk, chat/WhatsApp ou portal de identidade.
- Não é um motor de scripts/API arbitrária.
- Não é uma dependência padrão de P6/P11/P15/P25.
- Não é um diagrama BPMN público bruto.
- Não é uma fase P0–P29; não tem data; só entra com demanda real.

## 12. Riscos

| Risco | Mitigação |
|---|---|
| Complexidade desproporcional | Subconjunto fechado; v1 sem scripts/DMN/OR/call activity |
| Duas fontes de status | Fonte da verdade explícita; `onTransition` + teste de consistência |
| Concorrência/dupla conclusão | Transação + `FOR UPDATE` + idempotência + unique |
| Timers não determinísticos | `Clock` injetado; tick idempotente; testes com relógio fixo |
| Versão antiga quebrar | Instância pina versão; migração de processo é decisão explícita |
| PII vazar | Sem PII em log/audit metadata; classificação/retention; timeline sanitizada |
| Acessibilidade do editor | Lista/estado no v1; canvas só com ADR/fallback |
| Diferença entre módulos | Contrato mínimo; handlers no módulo; sem import cruzado |
| Escopo virar BPMS | ADR “subconjunto, não conformidade”; BPMS separado se contrato exigir |

## 13. Fases se promovido (não é a sequência atual)

| Etapa | Entrega | Prova |
|---|---|---|
| W0 | ADR + contratos + schema + service provider | arch-check; service discovery |
| W1 | Motor: definição, versão, start, user/manual task, XOR/AND, timer | testes determinísticos; concorrência |
| W2 | Admin: lista/versão/ativação, editor de estados, inbox | e2e CMS; a11y |
| W3 | Formulários versionados + notificações + timeline pública | snapshot; e-mail; sem PII |
| W4 | Piloto Diário **ou** e-SIC (um só) | fluxo real; 2× check; cobertura |
| W5 | Documentos/templates + import/export BPMN (opcional) | PDF/AST; subset validation |
| W6 | OR/call activity/DMN/BPMS (só se contrato exigir) | ADR e matriz de conformidade |

## 14. Critérios de promoção

- [ ] Um processo real com dono, volume, prazo e ROI; não “vamos construir porque é bonito”.
- [ ] Decisão escrita: subconjunto próprio **ou** BPMS separado (não os dois).
- [ ] ADR do serviço isolado + ADR de grupos/filas (extensão da ADR-033).
- [ ] Contrato `WorkflowEngine` e `WorkflowSubject` revisados; nenhum módulo importa o service.
- [ ] Piloto único; nenhum módulo existente é migrado à força.
- [ ] Gate de a11y, segurança, auditoria e determinismo verde.
- [ ] `make check` 2× + E2E; cobertura ≥90%; mutation/estático viáveis.

## 15. Notas

- **“Ao final do backlog”**: este item não entra no grafo de fases; é uma reserva de capacidade.
- **“Como landing sections”**: schema em `jsonb`, serviço headless, módulo usa contrato; sem
  HTML/CSS no banco e sem dependência padrão.
- **BPMN**: a especificação 2.0.2 não define dados/expressão nem versionamento/deploy; o serviço
  complementa com contrato próprio. A cláusula 13 é semântica de execução, não um produto.
- **Conformidade**: não alegar “BPMN 2.0” sem matriz; o rótulo do v1 é “subset BPMN 2.0”.
- **Custo**: é um programa, não uma fase G; a decisão de construir precisa considerar manutenção,
  testes, a11y e segurança.
