Skip to content

Vigência e Renovação: Especificação de Endpoints

Visão Geral

API RESTful para vigência estruturada, renovação automática, rescisão programada, garantias e dashboard de risco. Implementada no contrasync-nest-api (módulo renewals). Tabelas isoladas (hub contracts_renew + alertas/execuções/garantias); a tabela contracts não recebe colunas novas. Migração additive-only.

Todos os endpoints exigem JWT (Bearer) + header x-company-id e são escopados pela empresa do usuário.


Endpoints

1. Configurar vigência/renovação

POST /contracts/:id/validity

Request:

ts
interface SetValidityRequest {
  strategy: 'OFF' | 'SAME_TERMS' | 'INDEX_ADJUSTED' | 'NEGOTIATE';
  index?: 'IPCA' | 'IGPM' | 'INPC';
  alertOffsets?: number[]; // dias antes do vencimento; default [90,60,30,15,7,1]
  renewalNoticeDays?: number; // default 30
  autoRenewEnabled?: boolean;
  autonomyLevel?: number; // 0..3 (gate L2/L3)
  valueGate?: number;
  responsibleUserId?: string; // uuid
}

Response:

ts
interface RenewalResponse {
  id: string;
  contractId: string;
  strategy: 'OFF' | 'SAME_TERMS' | 'INDEX_ADJUSTED' | 'NEGOTIATE';
  index: 'IPCA' | 'IGPM' | 'INPC' | null;
  alertOffsets: number[];
  renewalNoticeDays: number;
  autoRenewEnabled: boolean;
  autonomyLevel: number;
  valueGate: number | null;
  responsibleUserId: string | null;
  state:
    | 'ACTIVE'
    | 'RENEWAL_DUE_SOON'
    | 'RENEWING'
    | 'RENEWED'
    | 'TERMINATING'
    | 'TERMINATED'
    | 'LAPSED'
    | 'RENEWAL_FAILED'
    | 'NEEDS_HUMAN';
  terminationScheduledAt: string | null;
  terminationNoticeDays: number;
  nextRenewalAt: string | null;
}

2. Agendar renovação

POST /contracts/:id/renewal/schedule
ts
interface ScheduleRenewalRequest {
  strategy: 'OFF' | 'SAME_TERMS' | 'INDEX_ADJUSTED' | 'NEGOTIATE';
  index?: 'IPCA' | 'IGPM' | 'INPC';
  renewalNoticeDays?: number;
}

Resposta: RenewalResponse.

3. Cancelar renovação

POST /contracts/:id/renewal/cancel

Sem body. Define strategy=OFF, state=ACTIVE, limpa nextRenewalAt. Resposta: RenewalResponse.

4. Simular renovação (preview de valor)

POST /contracts/:id/renewal/simulate
ts
interface SimulateRenewalRequest {
  strategy?: 'OFF' | 'SAME_TERMS' | 'INDEX_ADJUSTED' | 'NEGOTIATE';
  index?: 'IPCA' | 'IGPM' | 'INPC';
}

interface SimulateRenewalResponse {
  contractId: string;
  strategy: string;
  oldValue: number | null;
  newValue: number | null;
  adjustmentPct: number;
  index: 'IPCA' | 'IGPM' | 'INPC' | null;
  referenceMonth: string | null;
  breakdown: string;
}

5. Executar renovação agora (manual / IA L2-L3)

POST /contracts/:id/renewal/execute

Sem body. Aplica o gate de política (L3 só com autoRenewEnabled, autonomyLevel>=3, valor abaixo do valueGate e sem garantia em risco; caso contrário rebaixa para L2 → NEEDS_HUMAN). NEGOTIATE nunca executa automaticamente. Resposta: RenewalResponse.

6. Agendar rescisão programada

POST /contracts/:id/termination/schedule
ts
interface ScheduleTerminationRequest {
  terminationAt: string; // ISO date
  terminationNoticeDays?: number; // >= 30
}

Valida o aviso prévio mínimo (30 dias). Resposta: RenewalResponse.

7. Adicionar garantia/marco

POST /contracts/:id/warranties
ts
interface CreateWarrantyRequest {
  type: 'CAUCAO' | 'FIANCA' | 'SEGURO' | 'NOTA_PROMISSORIA';
  description?: string;
  amount?: number;
  expiresAt?: string; // ISO date
}

interface WarrantyResponse {
  id: string;
  type: 'CAUCAO' | 'FIANCA' | 'SEGURO' | 'NOTA_PROMISSORIA';
  description: string | null;
  amount: number | null;
  expiresAt: string | null;
  releasedAt: string | null;
  status: 'ACTIVE' | 'EXPIRING' | 'EXPIRED' | 'RELEASED';
}

8. Contratos em risco

GET /contracts/at-risk?daysAhead=90
ts
interface AtRiskItem {
  contractId: string;
  name: string;
  endDate: string;
  daysToEnd: number;
  strategy: string;
  state: string;
  responsibleUserId: string | null;
  hasOpenWarrantyRisk: boolean;
}

interface AtRiskResponse {
  data: AtRiskItem[];
}

9. Snapshot de vigência (dashboard)

GET /dashboard/validity-snapshot
ts
interface ValiditySnapshot {
  total: number;
  structured: number;
  structuredPct: number;
  dueSoon: number;
  renewing: number;
  lapsed: number;
  terminated: number;
  warrantiesExpiring: number;
}

Jobs assíncronos

  • Alerta de vencimento (0 6 * * *): por config, calcula o offset corrente (D-90/60/30/15/7/1 e D+1 atrasado), idempotente por (renewalId, offsetDays), notifica e-mail/WhatsApp/in-app do responsável, audita RENEWAL_ALERT_SENT. Mesmo job sinaliza garantias expirando em 30 dias (WARRANTY_EXPIRING).
  • Renovação devida (0 7 * * *): executa rescisão programada vencida, dispara renovação quando nextRenewalAt chega (SAME_TERMS/INDEX_ADJUSTED), e marca LAPSED contratos sem renovação com strategy=OFF vencidos.

Ambos protegidos por DistributedLockService (lock distribuído via Redis).

Tools IA (acesso só via REST, token do usuário propagado)

schedule_renewal, simulate_renewal, list_contracts_at_risk, draft_renewal_communication, auto_renew_batch (WRITE, exige confirm=true; gate de política aplicado pelo produto). Definidas em contrasync-ai-api/src/modules/tools/contracts.tools.ts.

Auditoria

EntityHistory (entityType=CONTRACT): RENEWAL_SCHEDULED, RENEWAL_CANCELLED, RENEWAL_SIMULATED, CONTRACT_RENEWED, RENEWAL_FAILED, RENEWAL_ALERT_SENT, TERMINATION_SCHEDULED, CONTRACT_LAPSED, WARRANTY_ADDED, WARRANTY_EXPIRING, WARRANTY_RELEASED. Logs duráveis de execução em contracts_renew_executions (inclui policyGateApplied e aiToolCallId quando originado por IA).