REF-501-04: Contract Lifecycle
ADR: ADR-501 — Service DeliveryEscopo: Auto-ativação via POLICY, renovação automatizada, fidelidade, reajuste, pipeline de renovação, cancelamento
1. Auto-Ativação (POLICY)
Contract é OPTIONAL e ativa automaticamente conforme POLICY configurável:
| Configuração | Comportamento |
|---|---|
contract_auto_activate: service | Contract criado quando Service provisionado |
contract_auto_activate: environment | Contract criado quando Environment provisionado |
contract_auto_activate: both | Contract criado para Service E Environment |
contract_auto_activate: none | Sem auto-ativação — somente criação manual |
Default: both (para MIDDAG). Adotantes podem mudar conforme modelo.
2. Dados do Contract
| Campo | Tipo | Descrição |
|---|---|---|
entitlement_id | FK | Entitlement SVC (ou ENV) pai |
start_date | date | Início do contrato |
end_date | date | Término do contrato |
renewal_date | date | Data para iniciar processo de renovação |
monthly_value | decimal | Valor mensal (se aplicável) |
annual_value | decimal | Valor anual (se aplicável) |
sla_terms | json | Termos de SLA vinculados (classe de serviço) |
loyalty_months | int | Período de fidelidade (default: 12) |
adjustment_pct | decimal | Percentual de reajuste anual (configurável) |
signed_document | FK | Documento PDF assinado (domínio Document) |
status | enum | active / expiring / expired / cancelled |
3. Pipeline de Renovação
90 dias antes da expiração:
→ Contract status: active → expiring
→ Notificação ao admin
→ Hook: middag_contract_expiring
60 dias antes:
→ Notificação ao cliente via portal/email
45 dias antes:
→ Quote de renovação gerado automaticamente
→ Valor: annual_value × (1 + adjustment_pct) se reajuste aplicável
→ Quote enviado ao cliente
Cliente aceita:
→ Pipeline padrão: Quote → Order → Payment → Entitlement estendido
→ Contract: end_date atualizado, status: active
→ Histórico de renovação registrado
Cliente não aceita:
→ Lembretes adicionais (30, 15, 7 dias)
→ Expiração → CancellationPolicy governa expired→cancelled4. Fidelidade
| Aspecto | Detalhe |
|---|---|
| Período | Configurável (default: 12 meses) |
| Multa rescisória | Configurável por contrato (% do valor restante) |
| Cancelamento antecipado | Permitido com aviso prévio (30 dias) + multa |
| Renovação após fidelidade | Sem fidelidade no próximo período (mensal, cancelável) |
| Dispensa de fidelidade | Admin pode dispensar manualmente |
5. Reajuste Anual
| Aspecto | Detalhe |
|---|---|
| Percentual | Configurável por contrato (adjustment_pct) |
| Aplicação | Na renovação — novo valor = anterior × (1 + pct) |
| Teto | Configurável (default: sem teto) |
| Notificação | Cliente informado do novo valor no quote de renovação |
| Override | Admin pode definir valor fixo no quote (ignora percentual) |
6. Cancelamento
| Aspecto | Detalhe |
|---|---|
| Aviso prévio | 30 dias (termos de uso) |
| Dentro da fidelidade | Multa rescisória aplicável |
| Após fidelidade | Sem multa, cancelamento com 30 dias de aviso |
| Entitlement associado | Entitlement → expired → CancellationPolicy governa |
| Dados | Preservados conforme CancellationPolicy.data_retention_days |
| Exportação | Oferecida no processo de cancelamento |
7. Hooks
| Hook | Parâmetros | Quando |
|---|---|---|
middag_contract_expiring | $contract, $days_left | 90/60/45 dias antes da expiração |
middag_contract_renewed | $contract, $new_dates | Renovação confirmada |
middag_contract_cancelled | $contract, $reason | Cancelamento processado |
8. Contract Identification Fields
Além dos campos financeiros e de SLA (seção 2), o Contract possui campos de identificação e partes para rastreamento operacional:
| Campo | Tipo | Descrição |
|---|---|---|
contract_number | string | Número único do contrato (gerado ou manual) |
contract_title | string | Título descritivo |
contract_type | enum | Tipo (ex: sla, hosting, development, consulting) |
client_name | string | Nome do cliente (desnormalizado para exibição rápida) |
client_cnpj | string (nullable) | CNPJ da Organization (desnormalizado para documentos) |
currency | string | Moeda (default: BRL) |
payment_terms | string (nullable) | Termos de pagamento (ex: "30 dias", "a vista") |
contract_pdf_url | string (nullable) | URL do PDF do contrato no R2 (versão original) |
signed_pdf_url | string (nullable) | URL do PDF assinado no R2 (versão com assinaturas) |
9. Extended Lifecycle States
Além dos 4 estados operacionais (seção 2: active/expiring/expired/cancelled), o Contract suporta estados de elaboração:
| Estado | Significado | Transições permitidas |
|---|---|---|
draft | Contrato em elaboração, nao visivel para o cliente | -> pending_signature |
pending_signature | Enviado para assinatura do cliente | -> active, cancelled |
active | Assinado e vigente | -> expiring (automático via cron) |
expiring | Proximo da data de vencimento (pipeline de renovação) | -> expired, active (renovado) |
expired | Vencido, aguardando renovação ou encerramento | -> cancelled, active (renovado) |
renewed | Renovado — vinculado ao novo contrato via renewed_to | Estado terminal (histórico) |
cancelled | Cancelado | Estado terminal |
Estados draft e pending_signature sao visíveis apenas no admin. O portal do cliente ve apenas contratos active, expiring e expired. Transições de estado disparam notificações e registram log de auditoria.
10. R2 File Storage (Signed Documents)
Documentos PDF de contratos sao armazenados no Cloudflare R2:
| Aspecto | Detalhe |
|---|---|
| Upload | Via admin WordPress — arquivo enviado ao R2, URL persistida no Contract |
| Download | Signed URLs com token temporario (expiração configurável, default 1h) |
| Metadata | Nome, tipo MIME, tamanho, hash SHA-256 armazenados no registro |
| Limite | 50MB por arquivo |
| Tipos aceitos | PDF (primario), DOCX (configurável) |
| Links expirados | Portal trata gracefully — solicita novo signed URL ao backend |
| Dois slots | contract_pdf_url (original) e signed_pdf_url (assinado) sao independentes |
REST API endpoints para download de PDFs usam signed URLs com validação de contexto de Organization via header X-Middag-Organization:
GET /middag-account/v1/contracts/{id}/pdf— download do PDF original (signed URL)GET /middag-account/v1/contracts/{id}/signed-pdf— download do PDF assinado (signed URL)