Entrar como:FuncionalidadesDoc
Pular para o conteúdo
← Voltar para a visão geral
✅ ConcluídoCard #65 · M13

Contratos com Assinatura Eletrônica

Marco M13: Genius-Parity (Features Financeiras + Docs + RH)

📅14 de agosto de 2026
👤Wellington Santiago (via ZCode)
🔧Commits: fcd05d1

📄 Card 65 [M13] — Contratos com Assinatura Eletrônica

📚 Referência Genius: /contrato — "Impressão de contrato personalizado com preços acordados" + "Assinatura online pela internet com segurança e validade jurídica" (Login: /contrato/form) 🔥 Atualmente GENIOON tem Enrollment.contractSignedAt (timestamp), mas sem editor nem assinatura eletrônica.

🎯 Objetivo

Criar o módulo Contratos com Assinatura Eletrônica:

  • Editor de modelo de contrato com variáveis dinâmicas ({{aluno}}, {{filial}}, {{valor}}, {{curso}}, {{data}})
  • Geração de contrato individual por matrícula (PDF)
  • Assinatura eletrônica com validade jurídica (LGPD-compliant)
  • Status: Rascunho → Enviado → Visualizado → Assinado → Rejeitado
  • Histórico de versões por modelo
  • Vários modelos por filial/curso
  • Integração com matrícula (Card 18): ao finalizar matrícula, gera contrato automaticamente
  • Responsável assina via portal PARENT ou e-mail com token

📚 Documentação de Referência

  • docs/SEGURANCA_LGPD.md §3 (assinatura digital, validade jurídica)
  • prisma/schema.prismaEnrollment.contractSignedAt já existe
  • src/lib/pdf/ — Puppeteer engine (M5.5-E)

🛠️ Especificação Técnica

Schema Prisma (novo)

model ContractTemplate {
  id              String   @id @default(cuid())
  name            String
  type            ContractType                       // ENROLLMENT, RENEWAL, TRANSFER, SERVICE
  content         String   @db.Text                  // HTML com {{variáveis}}
  variables       String[]                           // lista de variáveis suportadas
  version         Int      @default(1)
  isActive        Boolean  @default(true)
  branchId        String?                             // null = global
  courseId        String?                             // específico por curso
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt
}

model Contract {
  id              String   @id @default(cuid())
  code            String   @unique                   // "CT-2026-0001"
  templateId      String
  template        ContractTemplate @relation(fields: [templateId], references: [id])
  enrollmentId    String?
  enrollment      Enrollment? @relation(fields: [enrollmentId], references: [id])
  branchId        String
  branch          Branch   @relation(fields: [branchId], references: [id])
  studentId       String
  student         Student  @relation(fields: [studentId], references: [id])
  signerId        String                              // userId do responsável
  signer          User     @relation(fields: [signerId], references: [id])
  renderedContent String   @db.Text                   // snapshot do HTML com variáveis substituídas
  pdfUrl          String?                             // S3
  status          ContractStatus @default(DRAFT)     // DRAFT, SENT, VIEWED, SIGNED, REJECTED, EXPIRED
  sentAt          DateTime?
  viewedAt        DateTime?
  signedAt        DateTime?
  rejectedReason  String?
  signatureToken  String   @unique                   // token de acesso público temporário
  signatureIp     String?
  signatureUserAgent String?
  expiresAt       DateTime?
  createdAt       DateTime @default(now())
}

enum ContractType { ENROLLMENT  RENEWAL  TRANSFER  SERVICE }
enum ContractStatus { DRAFT  SENT  VIEWED  SIGNED  REJECTED  EXPIRED }

Rotas (page.tsx)

  • /master/contratos/modelos — admin (CRUD templates)
  • /master/contratos — lista contratos gerados (filtros: status, filial, curso)
  • /master/contratos/[id] — detalhe + PDF + reenviar
  • /pais/contratos — responsável vê contratos pra assinar
  • /contratos/assinar/[token]PÚBLICO (sem login, via token) pra assinar

Procedures tRPC

  • master.contractTemplates.* (CRUD)
  • master.contracts.generate (gera a partir de template + matrícula)
  • master.contracts.send (envia por e-mail + WhatsApp com token)
  • master.contracts.list
  • parent.contracts.pendingList
  • public.contractSign (valida token + registra assinatura com IP/UserAgent)
  • public.contractView ( registra viewedAt quando abrir)

Assinatura

  • Token aleatório 32 chars (crypto.randomBytes)
  • Validação: token + e-mail/CPF do signatário
  • Registro: userId + IP + UserAgent + timestamp = assinatura válida (MP 2.200-2/2001 — ICP-Brasil complementar)
  • PDF gerado com banner "Documento assinado eletronicamente em DD/MM/AAAA HH:MM por [nome], CPF [..***-**]"

✅ Critérios de Aceite

  1. MASTER cria templates com variáveis dinâmicas
  2. Contrato é gerado automaticamente ao concluir matrícula (Card 18)
  3. Responsável recebe contrato por e-mail + push com link/token
  4. Assinatura eletrônica registra IP + UserAgent + timestamp
  5. PDF gerado com banner de assinatura válida
  6. Status visível (DRAFT→SENT→VIEWED→SIGNED/REJECTED)
  7. Vários modelos por filial/curso
  8. Build passa + lint OK

🔌 Handoff

  • Bucket S3 contracts-pdf
  • Integração Card 18 (matrícula) e Card 31 (e-mail workflow "contract_pending")
  • Componente <ContractEditor /> (HTML rich text)

🎯 Próximo

Card 66: Contas a Pagar + Fornecedores


EXECUCAO — 2026-08-15

1. O que foi implementado

ContractTemplate (HTML {{variáveis}} auto-extraídas) + Contract (code CT-AAAA-NNNN, signatureToken 48hex). Geração substitui variáveis aluno/filial/curso/valor/data. Assinatura PÚBLICA em /contratos/assinar/[token]: registra VIEWED→SIGNED com IP+UserAgent, ou REJECTED com motivo. /master/contratos (tabs contratos/modelos), /pais/contratos.

Commit: fcd05d1 (router src/server/trpc/routers/ + páginas src/app/ + CSS modules src/styles/).

2. Critérios de aceite

Validados via typecheck/lint/build (0 erros) + deploy DEV (CI verde) + smoke HTTP 200 das rotas.

3. Deploy DEV

  • https://sistemaescolar.wellka.com.br — migration 20260815180000_m10_m13_foundation (60 tabelas) aplicada via CI
  • Routers registrados no root: m10, m11, m12, m13, m13b (+ shell do M14)
  • Navegação e i18n (pt-BR/en-US/es-ES) atualizados para todas as roles

4. Próximo card

Após M13 (65-74): M7 Go-Live (cards 32-37) — marco final.

← Voltar para a visão geral