{
  "id": "migration-16-generated-documents",
  "title": "Migration 16 — generated_documents",
  "description": "Contrato dos documentos gerados ou registrados no estágio.",
  "type": "migration-reference",
  "status": "implemented",
  "visibility": "public",
  "tags": [
    "sge/migrations",
    "sge/documentos",
    "sge/historico"
  ],
  "related": [
    "migration-15-internships",
    "migration-14-template-versions",
    "enum-generateddocumenttype",
    "enum-generateddocumentstatus",
    "geracao-de-documentos-docx-e-variaveis",
    "enum-generateddocumentorigin"
  ],
  "sourceRefs": [],
  "authors": [],
  "updated": null,
  "diagram": null,
  "body": "> [!success] Estado\n> Migration, Model, factory, relações e validações do registro implementados. A geração/transmissão e a análise de assinaturas continuam no fluxo funcional.\n\n## Contrato\n\n| Campo                 | Regra                                                                 |\n| --------------------- | --------------------------------------------------------------------- |\n| `id`                  | bigint, chave primária.                                               |\n| `internship_id`       | FK obrigatória.                                                       |\n| `template_version_id` | nullable; obrigatório para origem `sge` e nulo para `granting_party`. |\n| `origin`              | `sge` ou `granting_party`, conforme `GeneratedDocumentOrigin`.        |\n| `type`                | [Enum — GeneratedDocumentType](doc:enum-generateddocumenttype) (`GeneratedDocumentType`).     |\n| `status`              | [Enum — GeneratedDocumentStatus](doc:enum-generateddocumentstatus) (`GeneratedDocumentStatus`). |\n| `signature_availability_location` | texto curto nullable; obrigatório ao mover documento assinável para `awaiting_signature`, com o local informado pelo Setor. |\n| `snapshot`            | JSONB dos dados usados na geração; obrigatório para `sge` e nulo para `granting_party`. |\n| `generation_token`    | UUID idempotente, único para impedir duplicação por retry da mesma ação.        |\n| `output_filename` / `template_sha256` | nome entregue e hash do template usado; não são caminho de arquivo final. |\n| `generated_at` | instante da geração bem-sucedida pelo SGE; a autoria é registrada no Activity Log. |\n| `cancelled_at`        | timestamp nullable, obrigatório quando o documento for cancelado.     |\n| `cancellation_reason` | texto nullable, obrigatório quando o documento for cancelado.         |\n\n| timestamps            | auditoria.                                                            |\n\nO SGE registra a geração ou a existência, mas não armazena PDF, DOCX de saída ou documentos assinados. Cada geração pelo SGE referencia a versão validada mais recente no momento da geração; não cria uma linha em `template_versions`. A FK para a versão deve restringir sua exclusão física após uso, e a versão usada não pode ser alterada de forma destrutiva. Versões nunca usadas podem ser excluídas com sua mídia. O SGE armazena apenas templates, versões e snapshots. Para documento de origem `sge`, a `snapshot` preserva o catálogo/valores resolvidos, os valores monetários e o texto do §1º de remuneração efetivamente inserido no marcador `${PARAGRAFO_REMUNERACAO}`. Nunca inclui prova de emancipação, token, senha ou log. O status de assinatura é do documento; cancelar o documento não cancela automaticamente o estágio.\n\nO arquivo é produzido em diretório privado temporário, transmitido e removido em `finally`. Geração em lote futura poderá manter temporário com expiração curta, sem convertê-lo em acervo. O contrato operacional completo está em [Geração de documentos DOCX e variáveis](doc:geracao-de-documentos-docx-e-variaveis).\n\nAo mudar um documento assinável para `awaiting_signature`, o Setor informa o campo **Local de disponibilização para assinatura**. Ele é texto livre de até 500 caracteres, por exemplo “SIPAC” ou “portal institucional de assinaturas”; o nome de uma plataforma não é constante, enum nem regra do código. O valor permanece como contexto histórico da disponibilização, inclusive depois de assinado ou cancelado.\n\nNa mesma tela, o Setor pode marcar os interessados que receberão o aviso imediatamente. As opções são calculadas a partir das partes atuais do estágio e do tipo documental — discente, orientador, supervisor e, quando houver e-mail cadastrado, contato da concedente — e não aceitam digitação livre de destinatário. Ao confirmar o envio, pelo menos um interessado deve estar selecionado. O Activity Log registra a transição, o local e a quantidade/categorias escolhidas, sem copiar endereços de e-mail; os snapshots de destinatário e conteúdo pertencem às estruturas de comunicação.\n\nUm aditivo é um `generated_documents` com `type = addendum`, versão de template e snapshot próprios.\n\n## Regras de combinação\n\n- `origin = sge` exige template e snapshot da geração.\n- `origin = granting_party` registra somente a existência do documento, exige `template_version_id = null`, não usa snapshot de geração e não aceita upload ou armazenamento do arquivo externo.\n- `OrientationCertificate` usa `generated` e não passa por assinatura.\n- Os únicos status documentais são `generated`, `awaiting_signature`, `signed` e `cancelled`; `registered` e `released` não existem para documentos.\n- `awaiting_signature` exige `signature_availability_location` para documento que requer assinatura; `generated`, `signed` e `cancelled` podem preservar o valor histórico sem torná-lo uma nova obrigação de preenchimento.\n- Quando a data de início vencer antes da assinatura, não há ação agendada. O documento continua `awaiting_signature` e o estágio continua aguardando assinaturas até que o Setor decida manualmente registrar a assinatura, cancelar o documento com motivo ou abrir uma correção. Somente após decisão, eventual correção e aprovação o término é recalculado e uma nova versão documental pode ser gerada para assinatura.\n- Falha de Job não cria status persistente novo sem decisão explícita.\n\n## Checklist\n\n- [x] Confirmar catálogo de tipos e transições de status atuais.\n- [x] Criar migration com FKs, índice por estágio/status e nulabilidade condicional.\n- [x] Criar Model com casts dos três enums e JSONB.\n- [x] Validar combinações de origem, tipo, template e status no Model.\n- [x] Implementar snapshot imutável no Model e Activity Log de criação/alteração.\n- [x] Exigir local de disponibilização genérico ao marcar `awaiting_signature`, sem nome de plataforma hardcoded.\n- [ ] Exibir interessados elegíveis como checkboxes e enviar o aviso selecionado após o commit da transição.\n- [ ] Implementar acompanhamento manual de assinatura externa quando aplicável.\n- [ ] Testar geração, assinatura, cancelamento, aditivo e documento da concedente.\n- [x] Testar que nenhum arquivo final seja armazenado.\n- [x] Testar migrate/rollback na ordem completa após as migrations dependentes.\n\n## Enums relacionados\n\n- [GeneratedDocumentType](doc:enum-generateddocumenttype)\n- [GeneratedDocumentStatus](doc:enum-generateddocumentstatus)\n- [GeneratedDocumentOrigin](doc:enum-generateddocumentorigin)",
  "sections": [
    {
      "id": "contrato",
      "level": 2,
      "title": "Contrato",
      "text": "| Campo                 | Regra                                                                 | | --------------------- | --------------------------------------------------------------------- | | `id`                  | bigint, chave primária.                                               | | `internship_id`       | FK obrigatória.                                                       | | `template_version_id` | nullable; obrigatório para origem `sge` e nulo para `granting_party`. | | `origin`              | `sge` ou `granting_party`, conforme `GeneratedDocumentOrigin`.        | | `type`                | [Enum — GeneratedDocumentType](doc:enum-generateddocumenttype) (`GeneratedDocumentType`).     | | `status`              | [Enum — GeneratedDocumentStatus](doc:enum-generateddocumentstatus) (`GeneratedDocumentStatus`). | | `signature_availability_location` | texto curto nullable; obrigatório ao mover documento assinável para `awaiting_signature`, com o local informado pelo Setor. | | `snapshot`            | JSONB dos dados usados na geração; obrigatório para `sge` e nulo para `granting_party`. | | `generation_token`    | UUID idempotente, único para impedir duplicação por retry da mesma ação.        | | `output_filename` / `template_sha256` | nome entregue e hash do template usado; não são caminho de arquivo final. | | `generated_at` | instante da geração bem-sucedida pelo SGE; a autoria é registrada no Activity Log. | | `cancelled_at`        | timestamp nullable, obrigatório quando o documento for cancelado.     | | `cancellation_reason` | texto nullable, obrigatório quando o documento for cancelado.         |  | timestamps            | auditoria.                                                            |  O SGE registra a geração ou a existência, mas não armazena PDF, DOCX de saída ou documentos assinados. Cada geração pelo SGE referencia a versão validada mais recente no momento da geração; não cria uma linha em `template_versions`. A FK para a versão deve restringir sua exclusão física após uso, e a versão usada não pode ser alterada de forma destrutiva. Versões nunca usadas podem ser excluídas com sua mídia. O SGE armazena apenas templates, versões e snapshots. Para documento de origem `sge`, a `snapshot` preserva o catálogo/valores resolvidos, os valores monetários e o texto do §1º de remuneração efetivamente inserido no marcador `${PARAGRAFO_REMUNERACAO}`. Nunca inclui prova de emancipação, token, senha ou log. O status de assinatura é do documento; cancelar o documento não cancela automaticamente o estágio.  O arquivo é produzido em diretório privado temporário, transmitido e removido em `finally`. Geração em lote futura poderá manter temporário com expiração curta, sem convertê-lo em acervo. O contrato operacional completo está em [Geração de documentos DOCX e variáveis](doc:geracao-de-documentos-docx-e-variaveis).  Ao mudar um documento assinável para `awaiting_signature`, o Setor informa o campo **Local de disponibilização para assinatura**. Ele é texto livre de até 500 caracteres, por exemplo “SIPAC” ou “portal institucional de assinaturas”; o nome de uma plataforma não é constante, enum nem regra do código. O valor permanece como contexto histórico da disponibilização, inclusive depois de assinado ou cancelado.  Na mesma tela, o Setor pode marcar os interessados que receberão o aviso imediatamente. As opções são calculadas a partir das partes atuais do estágio e do tipo documental — discente, orientador, supervisor e, quando houver e-mail cadastrado, contato da concedente — e não aceitam digitação livre de destinatário. Ao confirmar o envio, pelo menos um interessado deve estar selecionado. O Activity Log registra a transição, o local e a quantidade/categorias escolhidas, sem copiar endereços de e-mail; os snapshots de destinatário e conteúdo pertencem às estruturas de comunicação.  Um aditivo é um `generated_documents` com `type = addendum`, versão de template e snapshot próprios.",
      "line": 4
    },
    {
      "id": "regras-de-combinacao",
      "level": 2,
      "title": "Regras de combinação",
      "text": "- `origin = sge` exige template e snapshot da geração. - `origin = granting_party` registra somente a existência do documento, exige `template_version_id = null`, não usa snapshot de geração e não aceita upload ou armazenamento do arquivo externo. - `OrientationCertificate` usa `generated` e não passa por assinatura. - Os únicos status documentais são `generated`, `awaiting_signature`, `signed` e `cancelled`; `registered` e `released` não existem para documentos. - `awaiting_signature` exige `signature_availability_location` para documento que requer assinatura; `generated`, `signed` e `cancelled` podem preservar o valor histórico sem torná-lo uma nova obrigação de preenchimento. - Quando a data de início vencer antes da assinatura, não há ação agendada. O documento continua `awaiting_signature` e o estágio continua aguardando assinaturas até que o Setor decida manualmente registrar a assinatura, cancelar o documento com motivo ou abrir uma correção. Somente após decisão, eventual correção e aprovação o término é recalculado e uma nova versão documental pode ser gerada para assinatura. - Falha de Job não cria status persistente novo sem decisão explícita.",
      "line": 34
    },
    {
      "id": "checklist",
      "level": 2,
      "title": "Checklist",
      "text": "- [x] Confirmar catálogo de tipos e transições de status atuais. - [x] Criar migration com FKs, índice por estágio/status e nulabilidade condicional. - [x] Criar Model com casts dos três enums e JSONB. - [x] Validar combinações de origem, tipo, template e status no Model. - [x] Implementar snapshot imutável no Model e Activity Log de criação/alteração. - [x] Exigir local de disponibilização genérico ao marcar `awaiting_signature`, sem nome de plataforma hardcoded. - [ ] Exibir interessados elegíveis como checkboxes e enviar o aviso selecionado após o commit da transição. - [ ] Implementar acompanhamento manual de assinatura externa quando aplicável. - [ ] Testar geração, assinatura, cancelamento, aditivo e documento da concedente. - [x] Testar que nenhum arquivo final seja armazenado. - [x] Testar migrate/rollback na ordem completa após as migrations dependentes.",
      "line": 44
    },
    {
      "id": "enums-relacionados",
      "level": 2,
      "title": "Enums relacionados",
      "text": "- [GeneratedDocumentType](doc:enum-generateddocumenttype) - [GeneratedDocumentStatus](doc:enum-generateddocumentstatus) - [GeneratedDocumentOrigin](doc:enum-generateddocumentorigin)",
      "line": 58
    }
  ],
  "sourcePath": "content/migration-16-generated-documents.md",
  "visuals": [],
  "apiVersion": 1
}
