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

Enquetes (Forms com Trava de Tela)

Marco M8: Comunicação & Documentos (SULTS-inspired)

👤Wellington Santiago (via ZCode)

✅ EXECUÇÃO — 15/08/2026

Implementado e validado em produção (homolog). Commits: 2062f6c (fundação: 21 tabelas), 080c857 (features), bbfa277 (lint). Deploy CI verde.

Validação ao vivo: página(s) da feature respondendo 200 com a role correta + procedures tRPC testadas via HTTP (respostas JSON corretas). Ver relatório da sessão.

Detalhes de implementação e decisões: conforme o design acima deste documento (schema, procedures e páginas seguidos conforme especificado; ajustes menores documentados no commit).

📄 Card 47 [M8] — Enquetes (Forms com Trava de Tela)

📚 Referência SULTS: https://www.sults.com.br/produtos/enquete Pesquisa e coleta de dados com bloqueio de tela no login (máxima adesão sem cobrança manual), modelos reutilizáveis e dashboards em tempo real. Estilo Google Forms corporativo.

🎯 Objetivo

Criar o módulo Enquetes — pesquisa com pais/professores/alunos/colaboradores com:

  • Tipos de campo: texto livre, múltipla escolha, seleção única, escala de avaliação
  • Modelos reutilizáveis (salva como template)
  • Trava de tela no login: formulário em tela cheia — colaborador responde pra acessar
  • Segmentação por filial/role
  • Dashboards em tempo real (pizza/barra)
  • Exportação Excel

📚 Documentação de Referência

  • docs/DESIGN_SYSTEM.md §6 — componentes nativos
  • prisma/schema.prisma — novos models

🛠️ Especificação Técnica

Schema Prisma (novo)

model Survey {
  id              String        @id @default(cuid())
  title           String
  description     String?
  status          SurveyStatus  @default(DRAFT)       // DRAFT, ACTIVE, CLOSED
  isBlocking      Boolean       @default(false)       // trava de tela
  isTemplate      Boolean       @default(false)       // template reutilizável
  targetScope     NewsScope     @default(ALL)         // reusa enum do Card 44
  branches        String[]                            // filiais-alvo
  roles           String[]                            // roles-alvo
  questions       SurveyQuestion[]
  responses       SurveyResponse[]
  startsAt        DateTime?
  endsAt          DateTime?
  createdBy       String
  createdAt       DateTime      @default(now())
  updatedAt       DateTime      @updatedAt
}

model SurveyQuestion {
  id              String   @id @default(cuid())
  surveyId        String
  survey          Survey   @relation(fields: [surveyId], references: [id])
  text            String
  type            QuestionType                       // TEXT, SINGLE_CHOICE, MULTI_CHOICE, SCALE, RATING
  required        Boolean  @default(true)
  options         String[]                           // para CHOICE
  scaleMin        Int?                                // para SCALE
  scaleMax        Int?
  order           Int      @default(0)
}

model SurveyResponse {
  id              String   @id @default(cuid())
  surveyId        String
  survey          Survey   @relation(fields: [surveyId], references: [id])
  respondentId    String
  respondent      User     @relation(fields: [respondentId], references: [id])
  answers         Json                                // {questionId: value}
  submittedAt     DateTime @default(now())

  @@unique([surveyId, respondentId])
}

enum SurveyStatus { DRAFT  ACTIVE  CLOSED }
enum QuestionType { TEXT  SINGLE_CHOICE  MULTI_CHOICE  SCALE  RATING }

Rotas (page.tsx)

  • /master/enquetes — painel admin (CRUD + criar + agendar)
  • /master/enquetes/[id]/resultados — dashboards (Recharts)
  • Componente <SurveyGate /> — wrapper que bloqueia navegação se há enquete pendente

Procedures tRPC (master.surveys, student.surveys, parent.surveys, etc.)

  • create / update / delete / publish / close
  • saveAsTemplate / createFromTemplate
  • pendingForUser (retorna enquetes pendentes para o usuário logado)
  • submit (registra resposta)
  • results (agregado por questão com %)

Lógica de trava de tela

  • Hook useSurveyGate(): ao montar AppShell, verifica se há pendingForUser com isBlocking=true
  • Se sim, renderiza <SurveyGate /> em tela cheia — usuário responde pra liberar
  • Não bloqueante: isBlocking=false → só badge + lembrete

✅ Critérios de Aceite

  1. MASTER cria/edita enquetes com 5 tipos de pergunta
  2. isBlocking=true trava a tela no próximo login do usuário-alvo
  3. Salvar como template + criar a partir de template
  4. Dashboards em tempo real (pizza/barra) por questão
  5. Exportação Excel das respostas
  6. Segmentação: por filial/role
  7. Build passa + lint OK

🔌 Handoff

  • Hook useSurveyGate() plugado no AppShell
  • Procedures *.surveys em cada router de role
  • Cron survey-reminder (Job Bull): lembrete diário se pendente

🎯 Próximo

Card 48: LGPD Editor de Termos Versionado

← Voltar para a visão geral