Command Agenda

Sistema de Agendamento Médico — Documentação Técnica Completa v2.0

Introdução

O Command Agenda é um sistema completo de agendamento médico desenvolvido para a gestão de consultas em unidades de saúde. O sistema é composto por três módulos principais:

Painel Administrativo (ADM)

Interface para gestores e operadores gerenciarem agendas, pacientes, médicos, unidades, especialidades, grades de horários, fila de espera (backlog), cancelamento em massa e gestão de usuários com RBAC.

Portal do Paciente

Interface para pacientes se cadastrarem, solicitarem agendamentos, acompanharem solicitações na fila de espera, confirmarem ou recusarem propostas, e exportarem consultas confirmadas para calendários (Google / iCal).

API REST

Backend Cloudflare Workers (Hono) com 4 bancos D1 distribuídos, 14 módulos de rotas, autenticação JWT dupla (admin + paciente), RBAC com 5 níveis, upload R2 e integração WhatsApp/Mailjet.

Arquitetura do Sistema

Camada de Apresentação

ADM (React + Vite) Gestão completa de agendas
Paciente (React + Vite) Solicitação e acompanhamento
↕ HTTPS / JWT

Camada de API

Cloudflare Workers (Hono) 14 módulos de rotas · CORS · Auth dupla · RBAC
↕ D1 Bindings

Camada de Dados

DB (Principal) Grades, Slots, Dias Cancelados
DB_HISTORICO Agendamentos, Backlog
DB_USUARIOS Pacientes, Médicos, Admin, Sessões
DB_PARAMETROS Especialidades, Unidades, Consultórios, Tipos de Slot, Cotas
↕ Integrações

Serviços Externos

Whapi.cloud WhatsApp OTP e Notificações
Mailjet E-mails de primeiro acesso
Cloudflare R2 Upload de fotos (médicos)

Stack Tecnológico

Frontend (ADM e Paciente)

  • React 18 — SPA com componentes funcionais e hooks
  • Vite — Build tool e dev server
  • Tailwind CSS — Estilização utilitária
  • React Beautiful DnD — Drag-and-drop (ADM)
  • Context API — AuthContext, LoadingContext, ToastContext

Backend (API)

  • Cloudflare Workers — Serverless runtime
  • Hono — Framework HTTP leve
  • Cloudflare D1 — Banco SQLite distribuído (×4)
  • Cloudflare R2 — Object storage (fotos)
  • Wrangler — Deploy e gerenciamento

Autenticação

  • JWT — Tokens com JTI e sessões (8h admin, 24h paciente)
  • bcrypt — Hash de senhas
  • RBAC — 5 níveis hierárquicos
  • Primeiro Acesso — Token + e-mail + senha temporária
  • Auth Dupla — Admin e Paciente compartilham rotas

Integrações

  • Whapi.cloud — WhatsApp API (OTP + propostas + confirmações)
  • Mailjet — E-mails transacionais (primeiro acesso)
  • Google Calendar — Link direto para criar evento
  • iCalendar (.ics) — Download para Outlook/Apple Calendar

Modelo de Dados

O sistema utiliza 4 bancos de dados Cloudflare D1 para isolamento e escalabilidade:

DB (Principal)

  • ca_gradeagenda — Grades de horários dos médicos
  • ca_slotagenda — Slots individuais de atendimento
  • ca_grade_dia_cancelado — Dias cancelados/restaurados em grades

DB_HISTORICO

  • ca_agendamento — Agendamentos realizados
  • ca_backlog — Fila de espera (solicitações)

DB_USUARIOS

  • ca_paciente — Cadastro de pacientes
  • ca_medico — Cadastro de médicos
  • ca_medico_especialidade — Médico × Especialidade (N:N)
  • ca_paciente_tiposlot — Paciente × Tipo Slot (N:N)
  • ca_usuario_admin — Usuários administrativos
  • ca_sessao — Sessões admin
  • ca_sessao_paciente — Sessões paciente

DB_PARAMETROS

  • ca_especialidade — Especialidades médicas
  • ca_especialidade_cota — Cotas de vagas por tipo de slot
  • ca_unidade — Unidades de saúde (com endereço e horários)
  • ca_consultorio — Consultórios por unidade
  • ca_tiposlot — Tipos de slot (Normal, Prioritário, etc.)

Principais Tabelas

TabelaCampos PrincipaisBanco
ca_pacientepacienteid, nomecompleto, cpf, datanascimento, telefone, email, senhahash, tipo (Comum/Prioritário/Gestante/Idoso/PcD), tipo_vinculo, nome_mae, status, telefone_validado, funcionario, origemDB_USUARIOS
ca_medicomedicoid, nomecompleto, crm, crm_uf, cpf, datanascimento, telefone, email, endereco, unidadeid, status, limitevagas, observacoes, foto_url, dadosbancariosDB_USUARIOS
ca_gradeagendagradeagendaid, medicoid, especialidadeid, unidadeid, consultorioid, vigencia, overbooking, limitevagas, statusDB
ca_slotagendaslotagendaid, gradeagendaid, medicoid, tiposlotid, datainicio, datafim, status (Livre/Ocupado/Cancelado), isoverbooking, periodo, limitevagasDB
ca_agendamentoagendamentoid, slotagendaid, pacienteid, protocolo, ordem, status (Ativo/Cancelado/Confirmado/Não Compareceu), datasolicitacaoDB_HISTORICO
ca_backlogbacklogid, pacienteid, especialidadeid, medicoid, unidadeid, data_preferida, periodo_preferido, horario_preferido, prioridade, origem, status, tipos_slot_elegiveis, cpf, telefone, ativoDB_HISTORICO
ca_usuario_adminusuarioid, nome, email, cpf, cargo, role, ativo, senhahash, senha_temporaria, token_primeiro_acesso, primeiro_acessoDB_USUARIOS
ca_unidadeunidadeid, nome, tipo, status, logradouro, numero, complemento, bairro, cidade, uf, cep, telefone, horario_abertura, horario_fechamento, dias_funcionamento, horarios_por_diaDB_PARAMETROS
ca_especialidadeespecialidadeid, nome, limitevagas, statusDB_PARAMETROS
ca_tiposlottiposlotid, nome, finalidade, status, canalorigem, cor, agendavelDB_PARAMETROS

Autenticação do Administrador

Fluxo de Login

1
Tela de Login

E-mail e senha. Branding Prefeitura de Barueri / NIB.

2
Validação

POST /api/auth/login → JWT com JTI + sessão

3
Dashboard

Acesso baseado no role (RBAC)

Primeiro Acesso

  1. Admin cria usuário → sistema gera senha temporária + token de primeiro acesso
  2. E-mail enviado (Mailjet) com link contendo o token
  3. Novo usuário acessa link → informa e-mail + senha temporária + nova senha
  4. Requisitos: mínimo 10 caracteres, maiúscula, minúscula, número e símbolo
  5. Token expirado? Admin pode reenviar via POST /api/auth/resend-first-access

Endpoints

POST/api/auth/login — Login com e-mail e senha
POST/api/auth/logout — Revoga sessão JWT
GET/api/auth/me — Dados do usuário logado
POST/api/auth/validate-first-access — Valida token de primeiro acesso
POST/api/auth/first-access — Define nova senha
POST/api/auth/resend-first-access — Reenvia e-mail de primeiro acesso

Dashboard Principal

Tela principal do painel administrativo com visão completa da agenda médica.

Funcionalidades

Calendário Multi-Visão

Mês, Semana e Dia com indicadores de vagas disponíveis e ocupadas por dia.

Filtros Sincronizados

Filtre por unidade, especialidade e médico. Sincronização bidirecional com o backlog.

Drag-and-Drop

Arraste pacientes do backlog para o calendário para alocação inteligente.

Estatísticas da Grade

Totais de slots, médicos e especialidades por dia. API: GET /api/grade-stats/day/:date

Busca de Pacientes

Pesquise por nome ou CPF. API: GET /api/agendamentos/buscar-paciente

Detalhe do Dia

Modal com todos os agendamentos, filtros, confirmação de presença e marcação de não comparecimento.

Modal de Detalhe do Dia

  • Estatísticas: Total, ativos, cancelados, especialidades e médicos
  • Filtros: Nome/CPF, status, especialidade, médico, unidade
  • Ordenação: Data cadastro, horário, paciente, médico
  • Ações: Confirmar presença (PUT /:id/confirmar-presenca), marcar não comparecimento (PUT /:id/nao-compareceu), expandir detalhes

Painel do Operador

Visão otimizada para operadores com layout dividido 60/40:

Painel Esquerdo (60%)

Agenda diária com grupos de slots por hora, vagas, médico e tipo de slot. Agendamento direto.

Painel Direito (40%)

Fila de espera com drag-and-drop para o painel esquerdo.

Alocação Inteligente

Auto-busca do melhor slot baseado nas preferências do paciente. API: POST /api/backlog/:id/alocar-inteligente

Detalhes do Paciente

Perfil completo: CPF, telefone (validado ✓), tipo, vínculo, tipos de slot elegíveis, tempo na fila, preferências.

Configurações

Abas filtradas por permissão RBAC:

Especialidades
Médicos
Unidades
Tipos de Slot
Pacientes
Gerar Grade
Gestão de Grades

Especialidades

  • CRUD com inativação/reativação (soft delete)
  • Cotas por tipo de slot: Distribuição de vagas (ex: 3 Normal, 2 Prioritário, 1 Encaixe)
  • Validação: soma das cotas = limite de vagas da especialidade
  • API: GET/POST /api/especialidades, GET/POST /api/especialidades/:id/cotas

Médicos

  • CRUD com inativação/reativação
  • Multi-especialidades (N:N), upload/remoção de foto (R2), CRM/CPF/telefone
  • Filtro por especialidade e status
  • API: GET/POST/PUT/DELETE /api/medicos, POST/DELETE /api/upload/medico/:id/foto

Unidades de Saúde

  • CRUD com inativação/reativação. Tipos: Clínica, Hospital, Consultório, Outro
  • Endereço completo (logradouro, número, bairro, cidade, UF, CEP)
  • Horários de funcionamento: global ou individual por dia da semana
  • Gestão inline de consultórios (criar, renomear, inativar)
  • API: GET/POST/PUT/DELETE /api/unidades, PATCH /api/unidades/:id/reativar

Tipos de Slot

  • CRUD com soft delete. Campos: nome, finalidade, canal de origem, cor, flag "agendável"
  • Exemplos: Normal, Prioritário, Encaixe, Retorno, Programa Municipal
  • API: GET/POST/PUT/DELETE /api/tipos-slot

Consultórios

  • CRUD vinculado à unidade. Soft delete com verificação de grades ativas
  • Reativação disponível
  • API: GET/POST/PUT/DELETE /api/consultorios, PATCH /api/consultorios/:id/reativar

Pacientes

  • Listagem com busca (nome/CPF), estatísticas (total, ativos, inativos, telefone validado)
  • Cadastro completo: CPF validado, tipo, vínculo, mãe, tipos de slot elegíveis
  • Validação de telefone via SMS (6 dígitos), detecção automática de funcionário
  • API: /api/pacientes + sub-rotas de validação e tipos-slot

Gerador de Grade de Horários

Wizard de 5 etapas para criação em massa de grades de agenda:

1
Seleção Base

Unidade, especialidade, médico, consultório

2
Período

Data início e fim

3
Horários por Dia

Horas para cada dia da semana (Seg-Sáb)

4
Distribuição de Tipos

Quantidade por tipo de slot (auto-preenchimento via cotas)

5
Preview & Gerar

Resumo com detecção de conflitos. Gera via POST /api/slots/generate-bulk

Como funciona: Cria ou reutiliza uma ca_gradeagenda e gera slots em massa para cada dia/hora configurado. O gerador reutiliza grades existentes para o mesmo médico/unidade/especialidade.

Gestão de Dias da Grade

Mini-calendário para cancelar/restaurar dias específicos de grades recorrentes:

  • Cancelar dia: Com motivo obrigatório. Cancela automaticamente slots livres do dia
  • Restaurar dia: Mantém histórico e reativa slots cancelados
  • Histórico: Quem cancelou, quando, e se foi restaurado
  • Filtros: unidade, especialidade, médico

Endpoints

GET/api/grade-agenda/:id/cancelled-days — Dias cancelados
GET/api/grade-agenda/:id/cancelled-days/range — Dias cancelados por período
POST/api/grade-agenda/:id/cancel-day — Cancelar dia
PUT/api/grade-agenda/:id/restore-day — Restaurar dia
GET/api/grade-agenda/:id/day-history/:data — Histórico do dia

Cancelamento em Massa

Ferramenta multi-etapa para cancelar slots em lote:

  • Filtros: Intervalo de datas, período (manhã/tarde/noite), médico, especialidade, unidade, tipo de slot
  • Preview: Lista de slots afetados antes da execução
  • Realocação: Opção de mover pacientes com agendamentos cancelados para o backlog

Backlog / Fila de Espera

Gestão da fila de pacientes aguardando agendamento:

Priorização

🔴 Alta, 🟡 Média, 🟢 Baixa. Ordenação automática.

Multi-Filtros

Prioridade, especialidade, unidade, médico, status. Sincronização com calendário.

Alocação

Drag-and-drop, alocação inteligente, ou manual (modal 3 passos: data → unidade → horário).

Adicionar à Fila

Busca paciente (autocomplete), filtros cascata, preferências, prioridade e origem.

Fluxo de Status

1
Pendente

Na fila aguardando

2
Aguardando Confirmação

Proposta enviada (WhatsApp)

3
Agendado / Recusado

Confirma → cria agendamento. Recusa → volta para Pendente

Endpoints do Backlog

GET/api/backlog — Listar (paginado, filtros, RBAC)
GET/api/backlog/:id — Detalhes (RBAC)
POST/api/backlog — Criar solicitação
PUT/api/backlog/:id — Atualizar solicitação
PATCH/api/backlog/:id/alocar — Alocar em slot
PATCH/api/backlog/:id/confirmar — Paciente confirma
PATCH/api/backlog/:id/recusar — Paciente recusa
POST/api/backlog/:id/alocar-dia — Alocação por dia
POST/api/backlog/:id/alocar-inteligente — Alocação inteligente
PATCH/api/backlog/:id/inativar — Soft-delete
DELETE/api/backlog/:id — Cancelar solicitação

Regra D-30

Retenção: Itens "Agendado", "Compareceu", "Não Compareceu" ou "Cancelado" com data passada são exibidos apenas nos últimos 30 dias.

Gestão de Pacientes

Endpoints

GET/api/pacientes — Listar (filtros: cpf, search). Limite: 50
GET/api/pacientes/:id — Detalhes
POST/api/pacientes — Criar (com detecção de funcionário)
PUT/api/pacientes/:id — Atualizar
DELETE/api/pacientes/:id — Inativar (soft delete)
PATCH/api/pacientes/:id/reativar — Reativar
POST/api/pacientes/:id/validar-telefone — Gerar código SMS
POST/api/pacientes/:id/confirmar-telefone — Confirmar código
DELETE/api/pacientes/:id/validacao-telefone — Remover validação
GET/api/pacientes/:id/tipos-slot — Tipos de slot elegíveis
PUT/api/pacientes/:id/tipos-slot — Atualizar elegíveis

Gestão de Usuários

Apenas para administrador_master.

Endpoints

GET/api/usuarios — Listar (paginado, busca, filtros role/status)
GET/api/usuarios/:id — Detalhes
POST/api/usuarios — Criar (gera senha temp + envia e-mail)
PUT/api/usuarios/:id — Atualizar (nome, email, cpf, cargo, role, senha, ativo)

Controle de Acesso (RBAC)

5 níveis hierárquicos:

administrador_master

Acesso total. Gerencia usuários e todas as configurações.

administrador

Todas as configurações, grades, backlog, dashboard. Sem gestão de usuários.

gerenciador

Configurações, geração de grades, backlog.

operador

Opera backlog e dashboard. Agenda/cancela, sem alterar configurações.

visualizador

Apenas leitura.

Funcionalidadevisualizadoroperadorgerenciadoradministradoradmin_master
Dashboard (leitura)
Agendar / Cancelar
Backlog (alocar)
Configurações
Gerar Grades
Pacientes
Gestão de Usuários

Cadastro do Paciente

Campos

  • Nome completo (obrigatório), CPF (obrigatório, validação de dígitos), Senha (mínimo 6 caracteres)
  • Data de nascimento, e-mail, telefone (validação WhatsApp OTP 4 dígitos), até 3 contatos adicionais

Validação WhatsApp OTP

1
Envio

Código 4 dígitos via Whapi.cloud

2
Digitação

4 campos auto-foco, auto-submit, paste

3
Validação

5 min expiração, 3 tentativas, cooldown 60s

POST/api/auth/paciente/register — Cadastro (CPF + senha + nome)

Login do Paciente

POST/api/auth/paciente/login — Login CPF + senha (JWT 24h)
GET/api/auth/paciente/me — Dados do paciente logado
POST/api/auth/paciente/logout — Revogar sessão

Solicitar Agendamento

Wizard de 3 etapas (adicionado ao backlog como "Pendente"):

1
Especialidade

Selecionar especialidade (obrigatório), unidade e médico (opcionais)

2
Preferências

Data (amanhã a +60 dias), período, urgência, observações

3
Confirmação

Resumo e envio

Cálculo de Prioridade

  • Alta: Urgência + sem data, ou urgência + data ≤ 7 dias
  • Média: Urgência + data > 7 dias
  • Baixa: Sem urgência

Minhas Solicitações

Abas

  • Em Andamento: Pendente e Aguardando Confirmação
  • Histórico: Agendadas, Canceladas, etc.

Proposta de Agendamento

Quando "Aguardando Confirmação":

  • Detalhes do slot proposto (data, hora, médico, especialidade, unidade, endereço)
  • Diferenças entre preferências e proposta
  • Confirmar → cria agendamento + notificação WhatsApp
  • Recusar → volta para "Pendente"

Histórico de Agendamentos

Via GET /api/agendamentos/meus:

  • Data, hora, médico, especialidade, unidade, protocolo
  • Status: Agendado, Confirmado, Cancelado, Não Compareceu
  • Cancelamento de agendamentos futuros
  • Exportação para calendário (Google / iCal)

Exportar para Calendário

Google Calendar

Link direto com título, detalhes (médico, especialidade, protocolo), local (unidade), duração 30 min.

Download .ics

Arquivo iCalendar para Outlook, Apple Calendar, etc. 2 lembretes: 1h e 1 dia antes.

Diagramas UML

Diagrama de Componentes

┌─────────────────────────────────────────────────────────────────┐
│                      COMMAND AGENDA SYSTEM                       │
│                                                                   │
│  ┌──────────────┐   ┌──────────────────┐   ┌──────────────────┐  │
│  │  ADM Frontend │   │ Paciente Frontend │   │   API (Hono)     │  │
│  │   (React)     │   │    (React)        │   │   Workers        │  │
│  │              │   │                  │   │                  │  │
│  │ - Dashboard  │   │ - Cadastro/Login │   │ - Auth (Admin)   │  │
│  │ - Operador   │   │ - Solicitar Ag.  │   │ - Auth (Paciente)│  │
│  │ - Config     │   │ - Solicitações   │   │ - Agendamentos   │  │
│  │ - Grade Gen  │   │ - Histórico      │   │ - Backlog        │  │
│  │ - Grade Dias │   │ - Calendário     │   │ - Slots          │  │
│  │ - Cancel.Mas.│   │ - WhatsApp OTP   │   │ - Grade Agenda   │  │
│  │ - Backlog    │   │                  │   │ - Grade Stats    │  │
│  │ - Pacientes  │   │                  │   │ - Médicos        │  │
│  │ - Usuários   │   │                  │   │ - Pacientes      │  │
│  │              │   │                  │   │ - Especialidades │  │
│  └──────┬───────┘   └────────┬─────────┘   │ - Unidades       │  │
│         │                    │              │ - Consultórios   │  │
│         │    HTTPS / JWT     │              │ - Tipos Slot     │  │
│         └────────┬───────────┘              │ - Usuários       │  │
│                  │                          │ - Upload (R2)    │  │
│                  └──────────────────────────┤                  │  │
│                                             └────────┬─────────┘  │
│                                                      │            │
│  ┌───────────┐ ┌────────────┐ ┌───────────┐ ┌──────────────────┐  │
│  │    DB     │ │ DB_HISTORICO│ │DB_USUARIOS│ │  DB_PARAMETROS   │  │
│  │ Grades   │ │ Agendament │ │ Pacientes │ │ Especialidades   │  │
│  │ Slots    │ │ Backlog    │ │ Médicos   │ │ Unidades         │  │
│  │ DiasCan  │ │            │ │ Admins    │ │ Consultórios     │  │
│  └──────────┘ └────────────┘ │ Sessões   │ │ TiposSlot/Cotas  │  │
│                              └───────────┘ └──────────────────┘  │
│  Integrações: Whapi.cloud (WhatsApp) · Mailjet · R2 Storage     │
└─────────────────────────────────────────────────────────────────┘

Fluxo: Solicitação → Backlog → Agendamento

Paciente         Portal              API               DB_HISTORICO      WhatsApp
  │                   │                │                    │              │
  │ 1. Solicitar      │                │                    │              │
  ├──────────────────→│ POST /backlog  │                    │              │
  │                   ├───────────────→│ INSERT ca_backlog  │              │
  │                   │                │ (Pendente)         │              │
  │                   │                ├───────────────────→│              │
  │  ← "Na fila"      │                │                    │              │
  │←─────────────────┤                │                    │              │
  │                   │                │                    │              │
  │       ── OPERADOR ALOCA ──         │                    │              │
  │              ADM  │                │                    │              │
  │                   │ PATCH /:id/alocar                   │              │
  │                   ├───────────────→│ UPDATE →            │              │
  │                   │                │ "Ag. Confirmação"  │              │
  │                   │                ├───────────────────→│              │
  │                   │                │ Notify              │─────────→│
  │                   │                │                    │              │
  │ 2. Ver proposta   │                │                    │              │
  ├──────────────────→│ GET /backlog   │                    │              │
  │  ← detalhes       │                │                    │              │
  │                   │                │                    │              │
  │ 3. Confirmar      │                │                    │              │
  ├──────────────────→│ PATCH /:id/confirmar                │              │
  │                   ├───────────────→│ CREATE agendamento │              │
  │                   │                │ UPDATE → "Agendado"│              │
  │                   │                ├───────────────────→│              │
  │                   │                │ Notify confirmação  │─────────→│
  │  ← Agendado!      │                │                    │              │
  │←─────────────────┤                │                    │              │

Diagrama ER (Simplificado)

┌──────────────┐  ┌───────────────┐  ┌──────────────┐  ┌──────────────┐
│ ca_unidade   │  │ca_especialidade│ │  ca_medico   │  │ ca_tiposlot  │
│──────────────│  │───────────────│  │──────────────│  │──────────────│
│PK unidadeid  │  │PK especialid. │  │PK medicoid   │  │PK tiposlotid │
│   nome       │  │   nome        │  │   nomecompleto│ │   nome       │
│   tipo       │  │   limitevagas │  │   crm        │  │   cor        │
│   endereco...│  │   status      │  │   foto_url   │  │   agendavel  │
└──────┬───────┘  └───────┬───────┘  └──────┬───────┘  └──────────────┘
       │                  │                  │
       │           ┌──────┴──────┐    ┌──────┴──────┐
       │           │ca_espec_cota│    │ca_med_espec │
       │           │   vagas     │    │  N:N        │
       │           └─────────────┘    └─────────────┘
       │
┌──────┴───────┐  ┌───────────────┐
│ca_consultorio│  │ca_gradeagenda │──→ ca_slotagenda ──→ ca_agendamento
│   nome       │  │ FK medico     │
│ FK unidadeid │  │ FK especialid.│         ↑
└──────────────┘  │ FK unidade    │    ca_paciente ──→ ca_backlog
                  │ FK consultorio│
                  └───────────────┘