Módulo de Pacientes
Documentação técnica detalhada do módulo de pacientes.
Modelo de Dados
typescript
interface PatientDTO {
id: string; // UUID
organizationId: string; // Tenant owner
fullName: string; // Nome completo
cpf: string; // CPF único por organização
birthDate: string; // ISO 8601
gender: 'MALE' | 'FEMALE' | 'OTHER' | 'NOT_INFORMED';
phonePrimary: string;
phoneSecondary?: string;
email?: string;
address?: {
street: string;
number: string;
complement?: string;
city: string;
state: string;
zip: string;
};
photoUrl?: string;
bloodType?: string;
allergies: string[]; // Ex: ["Penicilina", "Dipirona"]
observations?: string; // Criptografado (AES-256)
tags: string[]; // Segmentação
referralSource?: string;
insuranceId?: string; // ID do convênio
responsibleId?: string; // ID do responsável (menor de 18 anos)
isActive: boolean;
createdAt: string;
updatedAt: string;
}Regras de Negócio
Unicidade do CPF
- O CPF deve ser único por organização
- O mesmo CPF pode existir em organizações diferentes (tenants separados)
- A detecção de duplicata ocorre em tempo real ao digitar o CPF
- Ao detectar duplicata: retorna
409 Conflictcom{ existing_id: UUID }
Menor de Idade
Pacientes com menos de 18 anos devem ter um responsible_id vinculado:
- O responsável deve ser um paciente adulto já cadastrado na mesma organização
- A validação é aplicada na criação e na edição
Criptografia de Dados Sensíveis
O campo observations é criptografado com AES-256 antes de ser armazenado no banco. A descriptografia ocorre transparentemente na camada de infraestrutura ao consultar o registro.
Imutabilidade do CPF
O CPF não pode ser alterado após o cadastro — apenas no fluxo de merge de duplicatas, onde o CPF do cadastro principal é mantido.
Inativação (Não Exclusão)
Por conformidade com regulação clínica:
- Pacientes nunca são excluídos fisicamente
- A inativação define
is_active: false - Dados históricos são mantidos integralmente
- Novos agendamentos são bloqueados para pacientes inativos
Endpoints da API
| Método | Endpoint | Papel mínimo | Descrição |
|---|---|---|---|
GET | /patients | Receptionist | Listar pacientes com paginação e busca |
POST | /patients | Receptionist | Criar paciente |
GET | /patients/:id | Receptionist | Detalhe do paciente |
PUT | /patients/:id | Receptionist | Atualizar dados do paciente |
POST | /patients/:id/tags | Receptionist | Adicionar/remover tags |
POST | /patients/merge | Admin | Mesclar dois cadastros |
GET | /patients/:id/appointments | Viewer | Histórico de agendamentos |
GET | /patients/:id/export | Admin | Exportação LGPD (JSON completo) |
Listagem com Paginação
http
GET /patients?q=maria&page=1&per_page=20&tag=vip
Response 200:
{
"data": [PatientSummaryDTO],
"meta": {
"total": 150,
"page": 1,
"per_page": 20,
"total_pages": 8
}
}Criação de Paciente
http
POST /patients
Content-Type: application/json
{
"fullName": "Maria Aparecida Silva",
"cpf": "123.456.789-09",
"birthDate": "1985-03-15",
"gender": "FEMALE",
"phonePrimary": "(11) 99999-9999",
"email": "maria@email.com",
"bloodType": "A+",
"allergies": ["Penicilina"],
"tags": ["VIP", "Convênio"]
}
Response 201: PatientDTO
Response 409: { "error": "CPF_ALREADY_EXISTS", "existing_id": "uuid" }Merge de Pacientes
http
POST /patients/merge
Content-Type: application/json
{
"primary_id": "uuid-paciente-principal",
"secondary_id": "uuid-paciente-duplicado"
}
Response 200: PatientDTO (paciente principal consolidado)O merge consolida:
- Todos os agendamentos do secundário → transferidos para o principal
- Todos os registros de prontuário → transferidos para o principal
- Todas as faturas → transferidas para o principal
- O cadastro secundário é desativado com flag
merged_into: primary_id
Índices do Banco de Dados
sql
-- Performance em buscas comuns
CREATE UNIQUE INDEX idx_patients_org_cpf ON patients(organization_id, cpf);
CREATE INDEX idx_patients_org_active ON patients(organization_id, is_active);
CREATE INDEX idx_patients_fullname_fts ON patients USING gin(to_tsvector('portuguese', full_name));Exportação LGPD
O endpoint GET /patients/:id/export retorna um JSON completo com:
json
{
"patient": { ... dados cadastrais ... },
"appointments": [ ... histórico de atendimentos ... ],
"medical_records": [ ... prontuários ... ],
"invoices": [ ... faturas ... ],
"audit_access_logs": [ ... quem acessou seus dados e quando ... ],
"exported_at": "2026-05-19T10:00:00Z",
"exported_by": "uuid-do-admin"
}A exportação é registrada no audit log.