Módulo de Agendamento
Documentação técnica detalhada do módulo de agendamento, incluindo regras de negócio, validações e fluxos.
Regras de Negócio
Validações na Criação
Ao criar um agendamento, as seguintes validações são aplicadas em ordem:
- Profissional ativo na unidade selecionada
- Disponibilidade do profissional: O horário deve estar dentro da grade de disponibilidade configurada
- Sem conflito de agendamento: O profissional não pode ter outro agendamento ativo no mesmo horário
- Disponibilidade da sala (se informada): A sala não pode estar em uso no mesmo horário
- Duração coerente: O horário de fim é calculado com base na duração do procedimento
Grade de Disponibilidade
Cada profissional define sua grade por dia da semana, por unidade:
- Intervalos de 15 minutos mínimos
- Suporte a múltiplos turnos no mesmo dia (ex: 08h–12h e 14h–18h)
- Exceções por data sobrescrevem a regra semanal (férias, feriados)
- Alteração da grade não cancela agendamentos existentes — apenas exibe conflito
Máquina de Estados
Transições permitidas e quem pode executá-las:
| De | Para | Quem pode |
|---|---|---|
AGENDADO | CONFIRMADO | Receptionist, Admin, Owner |
AGENDADO | CANCELADO | Receptionist, Admin, Owner |
CONFIRMADO | EM_ATENDIMENTO | Receptionist, Admin, Owner |
CONFIRMADO | CANCELADO | Receptionist, Admin, Owner |
EM_ATENDIMENTO | CONCLUÍDO | Professional (próprio), Admin, Owner |
EM_ATENDIMENTO | CANCELADO | Admin, Owner |
AGENDADO | NO_SHOW | Receptionist, Admin, Owner |
CONFIRMADO | NO_SHOW | Receptionist, Admin, Owner |
Campos imutáveis após criação: tenantId, patientId, professionalId.
Cancelamento
Ao cancelar um agendamento:
- O motivo de cancelamento é obrigatório
- O status muda para
CANCELADO - Uma notificação é enviada ao paciente (quando e-mail disponível)
- O slot é liberado imediatamente na agenda
Conclusão e Faturamento
Ao marcar um agendamento como CONCLUÍDO:
- Uma fatura é gerada automaticamente com os itens do procedimento
- O profissional é notificado (in-app)
- O prontuário está disponível para preenchimento
Disponibilidade de Slots
Consulta de Disponibilidade
GET /availability
Query params:
professional_id: UUID (obrigatório)
date: YYYY-MM-DD (obrigatório)
procedure_id: UUID (obrigatório)
unit_id: UUID (obrigatório)
Response 200:
{
"slots": [
{ "start_at": "2026-05-20T09:00:00Z", "end_at": "2026-05-20T09:30:00Z", "available": true },
{ "start_at": "2026-05-20T09:30:00Z", "end_at": "2026-05-20T10:00:00Z", "available": false }
]
}O algoritmo de disponibilidade:
- Carrega a grade de disponibilidade do profissional para o dia da semana
- Verifica se existe exceção para a data específica
- Gera todos os slots possíveis no intervalo configurado
- Remove slots que colidem com agendamentos existentes (status ≠ CANCELADO)
- Remove slots que colidem com bloqueios de agenda
- Retorna o array com flag
availablepor slot
Cache de Disponibilidade
A disponibilidade de agenda é cacheada no Redis por 5 minutos para evitar queries repetidas em alta carga. O cache é invalidado quando:
- Um novo agendamento é criado para o profissional
- Um agendamento é cancelado
- A grade de disponibilidade é alterada
Notificações do Módulo
Eventos disparados via Hangfire (fila background):
| Evento | Delay | Ação |
|---|---|---|
| Criação de agendamento | Imediato | E-mail de confirmação ao paciente |
| Criação de agendamento | 24h antes | E-mail de lembrete ao paciente |
| Criação de agendamento | 2h antes | E-mail de lembrete ao paciente |
| Cancelamento | Imediato | E-mail de cancelamento ao paciente |
Tempo Real (SignalR)
O hub AppointmentHub emite eventos via SignalR para todos os clientes da organização autenticada:
appointment.created → Novo agendamento criado
appointment.updated → Status ou dados alterados
appointment.cancelled → Agendamento canceladoO frontend Angular assina esses eventos e atualiza o calendário em tempo real sem polling.
Endpoints da API
| Método | Endpoint | Papel mínimo | Descrição |
|---|---|---|---|
GET | /appointments | Viewer | Listar agendamentos (com filtros) |
POST | /appointments | Receptionist | Criar agendamento |
GET | /appointments/:id | Viewer | Detalhe de um agendamento |
PATCH | /appointments/:id/status | Receptionist | Alterar status |
GET | /availability | Viewer | Consultar slots disponíveis |
Exemplo de Criação
POST /appointments
Authorization: Bearer {token}
Content-Type: application/json
{
"patient_id": "uuid-do-paciente",
"professional_id": "uuid-do-profissional",
"procedure_id": "uuid-do-procedimento",
"unit_id": "uuid-da-unidade",
"room_id": "uuid-da-sala",
"start_at": "2026-05-25T10:00:00Z",
"notes": "Paciente com alergia a látex"
}Possíveis Erros
| Código HTTP | Erro | Situação |
|---|---|---|
| 409 | SLOT_NOT_AVAILABLE | Horário já ocupado pelo profissional |
| 409 | PROFESSIONAL_UNAVAILABLE | Profissional fora da grade de disponibilidade |
| 409 | ROOM_CONFLICT | Sala já em uso no horário |
| 422 | PATIENT_NOT_FOUND | ID de paciente inválido |
| 422 | PROFESSIONAL_NOT_IN_UNIT | Profissional não atua na unidade informada |
Funcionalidades Planejadas (V1 e V2)
- [ ] Drag & drop para reagendamento no calendário
- [ ] Visualização mensal do calendário
- [ ] Agendamentos recorrentes (
/appointments/:id/recurrence) - [ ] Lista de espera com preenchimento automático de slot
- [ ] Lock otimista de 5 minutos no slot (portal do paciente)
- [ ] Notificações via WhatsApp