Agenda do Médico — Mapeamento de Banco de Dados (v3.0)

Documentos desta funcionalidade: 01 - Definição (v3.0) · 02 - Especificação (v3.0) · 03 - Protótipo (v3.0, código executável em 03 - Protótipo v3.0.html) · 04 - Mapeamento de Banco de Dados (v3.0).


SEÇÃO 4 — MAPEAMENTO DE BANCO DE DADOS

Fonte da estrutura: Biblioteca de Schema (DDL), Para IA/Biblioteca de Schema (DDL)/catalog.json. Base de referência: GescomClienteAlfa (banco já adaptado à arquitetura do Gemed 2.1) e IpSeguranca/IpTerminologia. Nenhuma tabela nova proposta por esta funcionalidade (usa IpTerminologia.DomEstadoAgendaConsulta, criada em 27/10/2026 — ver “Tabelas novas”). Campos novos: o fuso IANA da clínica (ClienteEmpresa.FusoHorarioOficial, IpSeguranca) e o padrão de auditoria em UnidadeAtendimento — ver “Campos novos”.

Regras do sistema aplicadas aqui:

  • Exclusão lógica: um registro excluído tem RemovidoEm preenchido (com UsuarioIdRemovido); toda consulta ignora registros com RemovidoEm preenchido. O campo Status com A/I (ativo/inativo) do legado está sendo descontinuado e não é usado como critério de “ativo” — Log de Mudanças Estruturais do Banco de Dados, 07/10/2026.
  • Clínicas do cliente: as clínicas que estão no mesmo banco de cliente (ClienteBD).

Itens ainda não confirmados estão marcados [A DEFINIR] (falta um fato) ou [PROPOSTA] (decisão do Designer a confirmar); a lista consolidada está em “Pendências”, ao final.

4.1 Endpoint: GET /api/v1/agenda/doctor/day

Retorna as consultas do médico logado num dia (date), de qualquer status, das clínicas do cliente a que o médico tem acesso (RN-AGM-002, D-CM-068), e, em lista separada (blocks), os horários bloqueados pela Recepção na agenda dele (RN-AGM-019).

Tabelas envolvidas

TabelaBancoFunção no endpoint
AgendaGescomClienteAlfaTabela principal — uma linha por consulta ou por bloqueio
PacienteGescomClienteAlfaNome e nome social; o indicador de paciente reservado separa bloqueios de consultas
PacienteFotoGescomClienteAlfaFoto do paciente
PEP / PEPDiagnosticoGescomClienteAlfaDiagnósticos oncológicos do paciente
ProgramaApoio / ProgramaApoioPacienteGescomClienteAlfaTags do paciente atribuídas no cadastro (RN-AGM-006)
PEPProgramaApoioPaciente / PEPGescomClienteAlfaTags do paciente atribuídas no prontuário, com a vigência do registro de PEP (RN-AGM-006)
ChaveGescomClienteAlfaNome curto da clínica e do convênio (RN-AGM-017)
UnidadeAtendimentoGescomClienteAlfaNome da unidade e contagem de unidades ativas para consultas (RN-AGM-017, b)
AgendaClassificacao / AgendaSubClassificacaoGescomClienteAlfaClassificação e subclassificação (RN-AGM-008)
TermoTraducaoIpTerminologiaRótulos traduzidos do modo de atendimento e do status
DomEstadoAgendaConsultaIpTerminologiaCores de cada status nos temas claro e escuro (status.colors)
ClienteEmpresaIpSegurancaIdioma e fuso horário (IANA, RN-AGM-018) da clínica em que o usuário entrou; contagem de clínicas acessíveis
ClientePerfilAcessoUsuario / UsuarioClienteIpSegurancaClínicas do cliente a que o médico tem acesso (RN-AGM-017, a)

Mapa de campos

Os campos herdados da Central do Médico têm a mesma origem do endpoint GET /api/v1/cockpit/doctor/appointments (Central do Médico, Mapeamento de Banco de Dados, Seção 4.1) — referenciados, não repetidos.

CampoTipoOrigemObservação
datedataparâmetro dateEco do dia pedido
timeZonestring (IANA)ClienteEmpresa.FusoHorarioOficial (IpSeguranca) da clínica em que o usuário entrouCampo novo (ver “Campos novos”); ex.: America/Sao_Paulo. Mesma linha de ClienteEmpresa que dá o idioma (IdiomaOficial)
serverNowdata/horarelógio do servidor, convertido para timeZoneISO 8601 com deslocamento
appointments[].idintAgenda.IdAgenda
startTimehorárioAgenda.DhAgendaIniUTC (NULL possível na DDL), convertido para timeZoneConsulta com DhAgendaIniUTC NULL não entra na lista (não tem dia nem posição)
endTimehorárioAgenda.DhAgendaFimUTC (NULL possível na DDL), convertido para timeZone[PROPOSTA] Se NULL, DhAgendaIniUTC + Agenda.Tempo minutos (Tempo, numeric(4,0) NOT NULL, é a duração gravada pela Recepção); se o fim cai no dia seguinte, "24:00" (o item termina no fim do dia exibido)
status.domainstringcalculado — AppointmentStatus()Central do Médico, 4.1 (“Funções de cálculo”): scheduled, waiting, checked, consultation, finished, canceled. Ver “Funções de cálculo”, abaixo, sobre precedência
status.namestringTermoTraducao.TermoValorTermo = CodEstado do status (tabela “Status × CodEstado”, em “Domínios”), Origem = DomEstadoAgendaConsulta, Idioma = ClienteEmpresa.IdiomaOficial. Sem tradução: vai a própria chave (CodEstado) e anomalia no log técnico (DT-011)
status.colors.light.background / .textchar(7)DomEstadoAgendaConsulta.CorClaroFundo / CorClaroTextoPela mesma chave CodEstado. Base global: iguais para todas as clínicas (DT-016)
status.colors.dark.background / .textchar(7)DomEstadoAgendaConsulta.CorEscuroFundo / CorEscuroTextoIdem. Se alguma das quatro colunas estiver NULL (são NULL na DDL), colors não vai na resposta (o front mostra o chip neutro)
attendanceMode.codecharAgenda.AtendimentoDomínio ModoAtendimento (Central do Médico, 4.1, “Domínios”)
attendanceMode.labelstringAgenda.Atendimento → TermoTraducao.TermoValorMesma tradução da Central: Termo = Agenda.Atendimento, Origem = Indicadores|ModoAtendimento, Idioma = ClienteEmpresa.IdiomaOficial. Sem tradução no idioma da clínica: vai a própria chave (Agenda.Atendimento) e o back-end registra anomalia no log técnico (Termo, Origem, Idioma); não há queda para pt-BR nem para outro idioma (DT-011)
delayMinutesintcalculadoMinutos entre agora e DhAgendaIniUTC, calculados em UTC. Positivo só quando date é hoje (em timeZone), o horário já passou, Agenda.Situacao IN ('A','V') e DhAtendimentoIniUTC IS NULL; em qualquer outro caso, 0 — inclusive canceladas
firstTimebooleanAgenda.PrimeiraConsulta = 'S'Domínio S/N
tags[].codestringProgramaApoio.SiglaTexto do chip
tags[].descriptionstringProgramaApoio.DescricaoDica e rótulo acessível
tags[].colorstringProgramaApoio.CorHexadecimal, fundo do chip (padrão .chip-tag)
tags (seleção)—União de duas origens, ambas → ProgramaApoio: (1) ProgramaApoioPaciente (por IdPaciente); (2) PEPProgramaApoioPaciente → PEP (por PEP.IdPaciente)Filtros comuns de RN-CM-025: (ProgramaApoio.MostrarEm & 32) = 32, vigência da tag (ProgramaApoio.DataInicio/DataFim) e ProgramaApoio.RemovidoEm IS NULL. Vigência da atribuição ao paciente: na origem (1), ProgramaApoioPaciente.DataInicio/DataFim e RemovidoEm IS NULL; na origem (2), PEP.DataInicioUTC/DataFimUTC e PEP.RemovidoEm IS NULL (PEPProgramaApoioPaciente não tem datas; a PK é IdPEP — um registro de PEP leva uma tag). Todas as vigências são avaliadas no dia date (RN-AGM-006). Um período vale para o dia quando começa até o fim do dia e termina no próprio dia ou depois (ou é aberto), no fuso timeZone — o dia do fim conta como vigente (ex.: DataFim = 23/09 00:00 vale para 23/09) — necessário porque PEP.DataInicioUTC/DataFimUTC têm hora. As duas origens separam as tags pela finalidade (ProgramaApoio.Finalidade): A (assistencial) só é atribuída no prontuário; D (administrativa) só no cadastro. Se a mesma tag vier das duas, aparece uma vez. Tag VIP: tag administrativa, atribuída no cadastro (ProgramaApoioPaciente), com as mesmas regras das demais tags, sem exceção (RN-AGM-006). Paciente.PacienteVip não é lido — fica fora de escopo até se decidir se o campo será descontinuado
complementstring | nullAgenda.Complemento (varchar(128), NULL)
patient.idintAgenda.IdPaciente
patient.preferredName / legalNamestringPaciente.NomeSocial / Paciente.NomeCentral do Médico, 4.1 (lá grafado prefferedName)
patient.photourl | nullPacienteFoto (Padrao = 'S', a mais recente)Central do Médico, 4.1 e “Infraestrutura de apoio” (MinIO)
patient.diagnosisarrayPEPDiagnostico.Diagnostico, Tipo = 'O'Central do Médico, 4.1 — todos os diagnósticos oncológicos ativos (critério de “ativo” herdado da Central; a Central não exibe o diagnóstico de um PEP que só começa depois de hoje — ver “Pendências”, item 2)
clinicstring | nullAgenda.IdChClinica → Chave.IdChave → Chave.DescricaoNome curto da clínica (Clinica.IdChClinica é FK para Portador, que é FK para Chave). null quando ClinicVisible() é falso (RN-AGM-017, a). [PROPOSTA] O nome aparece mesmo que a clínica tenha sido excluída logicamente depois — a consulta aconteceu ou acontecerá ali
unitstring | nullAgenda.IdUAtendimento (NULL possível) → UnidadeAtendimento.Descricao (varchar(30))null quando Agenda.IdUAtendimento é NULL ou quando UnitVisible(Agenda.IdChClinica) é falso (RN-AGM-017, b). [PROPOSTA] Quando aparece, o nome é exibido mesmo que aquela unidade tenha sido excluída depois
insurancestringAgenda.IdChConvenio (NOT NULL) → Chave.IdChave → Chave.DescricaoNome curto do convênio (Convenio.IdChConvenio é FK para Portador → Chave). Sempre preenchido; o particular é um registro de Convenio com Convenio.Convenio = 'T' e aparece pelo nome curto cadastrado. O plano (Agenda.Plano, Agenda.IdPlano → ConvenioPlano) não é usado (RN-AGM-017, c)
classificationobjeto | null—null quando Agenda.IdAgendaClassificacao é NULL (RN-AGM-008)
classification.namestringAgenda.IdAgendaClassificacao → AgendaClassificacao.Descricao (varchar(20))Exibida mesmo que a classificação tenha sido excluída depois (mesmo raciocínio de clinic)
classification.subNamestring | nullAgenda.IdAgendaSubClassificacao (FK) → AgendaSubClassificacao.Descricao (varchar(30))null quando não há subclassificação

Campos de Agenda que existem e não são usados: TipoConsulta (char(1) NOT NULL, significado não confirmado), Plano, IdPlano, IdChClinicaFat (clínica de faturamento — a tela mostra a clínica do atendimento, IdChClinica), Data/HoraIni/HoraFim (data e horário legados; a tela usa DhAgendaIniUTC/DhAgendaFimUTC, como a Central). Também não são usados ClienteEmpresa.FusoOficial (smallint, deslocamento) nem Clinica.FusoHorario (deslocamento, legado) — o fuso vem de ClienteEmpresa.FusoHorarioOficial.

Mapa de campos — blocks (RN-AGM-019)

Registros de Agenda do médico no dia cujo paciente é o paciente reservado de bloqueio (Paciente.Paciente = 'B') — mesma consulta de appointments, separados na aplicação por esse indicador. Não são lidos foto, diagnóstico, tags, convênio, classificação, modo de atendimento nem nome do paciente reservado.

CampoTipoOrigemObservação
blocks[].idintAgenda.IdAgenda
blocks[].startTime / endTimehorárioAgenda.DhAgendaIniUTC / DhAgendaFimUTCMesmas regras de startTime/endTime das consultas
blocks[].reasonstring | nullAgenda.Complemento (varchar(128), NULL)Motivo digitado pela Recepção. null quando vazio
blocks[].clinicstring | nulligual a clinicMesma regra de ClinicVisible() (RN-AGM-017, a)

Bloqueio não tem unidade de atendimento: Agenda.IdUAtendimento não é lido para os registros de bloqueio, e blocks não tem campo de unidade.

Um bloqueio entra em blocks só quando está vigente. A Recepção o desfaz de duas formas, e nas duas ele some da agenda: cancelamento formal, pela Agenda.Situacao — fica de fora quando AppointmentStatus() dele é canceled; e exclusão lógica, quando o bloqueio deixou de existir — Agenda.RemovidoEm IS NULL, já no filtro geral. Bloqueios nunca contam em days-with-appointments nem em next-appointment-date (4.2 e 4.3).

Funções de cálculo

AppointmentStatus() — a da Central do Médico (4.1). Precedência adotada aqui, porque as condições da Central se sobrepõem num caso: Situacao = 'V' com DhAtendimentoFimUTC preenchido e DhAtendimentoIniUTC NULL casa com checked e com finished — vale finished. As condições são avaliadas nesta ordem: canceled, finished, consultation, checked, waiting, scheduled. Agenda.Situacao é NOT NULL; um código fora do domínio SituacaoAgenda não entra na lista (filtro abaixo).

ClinicVisible() — o médico tem acesso a mais de uma clínica do cliente (RN-AGM-017, a). Calculada uma vez por sessão (pode ficar em cache — consulta outro banco e não precisa ser refeita a cada atualização automática):

-- Verdadeiro quando há mais de uma clínica (ClienteEmpresa) acessível ao usuário
-- no mesmo banco do cliente (ClienteBD) da sessão — "clínicas do cliente".
SELECT CASE WHEN COUNT(DISTINCT cpau.ClienteEmpresaId) > 1 THEN 1 ELSE 0 END
FROM IpSeguranca.dbo.ClientePerfilAcessoUsuario cpau
JOIN IpSeguranca.dbo.UsuarioCliente uc  ON uc.Id = cpau.UsuarioClienteId
JOIN IpSeguranca.dbo.ClienteEmpresa ce  ON ce.Id = cpau.ClienteEmpresaId
WHERE uc.UsuarioId     = @UsuarioId          -- usuário autenticado
  AND ce.ClienteBDId   = @ClienteBDId        -- banco do cliente da sessão
  AND uc.RemovidoEm   IS NULL
  AND cpau.RemovidoEm IS NULL
  AND ce.RemovidoEm   IS NULL;

Mesmo critério de “clínica acessível” do Check-in de Usuários (RN-CIU-009, Épico 1), restrito ao banco atual. Pode haver consulta do médico numa clínica a que ele perdeu o acesso (agendada antes); ela não aparece (D-CM-068) — o filtro está em “Filtros do endpoint”. O número de clínicas de {ClinicasDoMedico} é o mesmo que esta função conta, enquanto toda clínica acessível tiver SegEmpresa e Clinica.

UnitVisible(IdChClinica) — a clínica da consulta tem mais de uma unidade ativa para consultas (RN-AGM-017, b). Calculada uma vez por clínica presente no resultado, não por consulta:

SELECT CASE WHEN COUNT(*) > 1 THEN 1 ELSE 0 END
FROM UnidadeAtendimento
WHERE IdClinica  = @IdChClinica
  AND StConsulta = 'S'
  AND RemovidoEm IS NULL;     -- campo novo nesta tabela (ver "Campos novos")

Referência de tempo (RN-AGM-018)

Tudo no fuso da clínica em que o usuário entrou: serverNow, o que é “hoje”, o dia de cada consulta (filtro de date) e os horários startTime/endTime — inclusive das consultas das outras clínicas a que o médico tem acesso. O fuso vem de ClienteEmpresa.FusoHorarioOficial (IpSeguranca; identificador IANA, ex.: America/Sao_Paulo) e é devolvido em timeZone, para a tela informar qual fuso está exibindo. A conversão de DhAgendaIniUTC/DhAgendaFimUTC é feita na aplicação (o AT TIME ZONE do SQL Server não aceita nomes IANA). Como há um só fuso por requisição, os limites do dia viram uma faixa UTC exata: @inicioUtc = 00:00 de date em timeZone, convertido para UTC; @fimUtc = 00:00 do dia seguinte, convertido.

Domínios

SituacaoAgenda (Agenda.Situacao), ModoAtendimento (Agenda.Atendimento), TipoAgenda (Agenda.TipoAgenda), TipoDiagnostico e MostrarEm: definidos uma única vez em Central do Médico, Mapeamento de Banco de Dados, 4.1 (“Domínios”) — não repetidos aqui.

Status × CodEstado (IpTerminologia.DomEstadoAgendaConsulta, chave das cores e do nome traduzido): scheduled → A; waiting → D; checked → G; consultation → J; finished → M; canceled → X. A mesma tabela vale para a Central do Médico (painel de Consultas).

Domínios usados só por esta funcionalidade:

CampoValorSignificadoFonte
UnidadeAtendimento.StConsultaS / NUnidade atende (ou não) consultasInformado pelo negócio (ver Histórico de Versões); massa de teste (CargaCMZero.xlsx)
Convenio.ConvenioTConvênio “Particular”Informado pelo negócio (ver Histórico de Versões); massa de teste
Convenio.ConvenioBConvênio reservado (na massa de teste, usado junto com o paciente reservado)Massa de teste
Convenio.ConvenioNULLConvênio comumMassa de teste — [A DEFINIR] se há outros valores em produção
ProgramaApoio.FinalidadeA / DTag assistencial (atribuída no prontuário) / administrativa (atribuída no cadastro)Informado pelo negócio (ver Histórico de Versões); massa de teste
Paciente.PacienteBPaciente reservado de bloqueio: o registro de agenda é um horário bloqueado pela Recepção, não uma consulta (char(1) NOT NULL)Central do Médico, RN-CM-030; demais valores não mapeados aqui
ClienteEmpresa.FusoHorarioOficialidentificador IANAFuso da clínica (ex.: America/Sao_Paulo)Campo novo (Log de Mudanças, 07/10/2026)

Filtros do endpoint

Mesmo critério de seleção do endpoint de consultas da Central do Médico (4.1), sem o filtro de “hoje” e sem o filtro de situação:

  • Agenda.IdChRecurso = {IdChProfissional do médico logado} — mesmo critério da Central.
  • Agenda.IdChClinica IN (SELECT IdChClinica FROM {ClinicasDoMedico}) — só as clínicas a que o médico tem acesso (RN-AGM-002, D-CM-068). {ClinicasDoMedico} (colunas IdEmpresa e IdChClinica) é montada pela aplicação uma vez por sessão e definida uma só vez, no Mapeamento da Central do Médico (v5.13), Seção 4, bloco “Clínicas em que o médico atende” (D-CM-067): clínicas do cliente da sessão a que o usuário tem acesso (ClientePerfilAcessoUsuario), traduzidas para IdChClinica por SegEmpresa e Clinica. A regra vale também para blocks, que saem da mesma consulta.
  • Agenda.TipoAgenda = 'C' — agendas de consulta.
  • Paciente.Paciente (via Agenda.IdPaciente; char(1) NOT NULL) não filtra neste endpoint: = 'B' vai para blocks (RN-AGM-019), os demais para appointments. Diferente da Central, que exclui os registros 'B' (RN-CM-030) porque mostra só o que exige ação do médico.
  • Agenda.RemovidoEm IS NULL — exclusão lógica, regra de todo o sistema (a Central também a aplica).
  • Agenda.Situacao IN ('A','V','C','D','F','I','M','O','T') — todo o domínio SituacaoAgenda; consultas canceladas (inclusive falta) entram, com status = canceled (RN-AGM-009/010); bloqueios cancelados não entram (ver blocks); excluídos não entram por RemovidoEm.
  • Agenda.DhAgendaIniUTC >= @inicioUtc AND Agenda.DhAgendaIniUTC < @fimUtc (ver “Referência de tempo”).
  • Tags, foto e diagnóstico: só para appointments. Tags: filtros de MostrarEm, vigências (no dia date) e exclusão lógica (ver tags no mapa de campos).
  • Ordenação: Agenda.DhAgendaIniUTC crescente.

4.2 Endpoint: GET /api/v1/agenda/doctor/days-with-appointments

Retorna as datas, entre from e to (máximo de 62 dias), com ao menos uma consulta não cancelada do médico (marcador do calendário — RN-AGM-003). Bloqueios não contam (RN-AGM-019): por isso o filtro p.Paciente <> 'B' continua aqui e em 4.3.

-- @fromUtc = 00:00 de @from em timeZone, em UTC; @toUtc = 00:00 do dia seguinte a @to, em UTC.
-- A data local de cada consulta (no fuso timeZone) é calculada na aplicação a partir de DhAgendaIniUTC.
SELECT a.DhAgendaIniUTC
FROM Agenda a
JOIN Paciente p ON p.IdPaciente = a.IdPaciente
WHERE a.IdChRecurso = @IdChProfissional
  AND a.IdChClinica IN (SELECT IdChClinica FROM {ClinicasDoMedico})   -- clínicas a que o médico tem acesso (D-CM-068)
  AND a.TipoAgenda  = 'C'
  AND p.Paciente   <> 'B'
  AND a.RemovidoEm IS NULL
  AND a.Situacao IN ('A', 'V')          -- não cancelada (domínio SituacaoAgenda)
  AND a.DhAgendaIniUTC >= @fromUtc AND a.DhAgendaIniUTC < @toUtc;
-- Resposta: datas distintas (no fuso timeZone), em ordem crescente.

4.3 Endpoint: GET /api/v1/agenda/doctor/next-appointment-date

Retorna a data da próxima (direction = next) ou anterior (previous) consulta não cancelada do médico, a partir de from (exclusive), sem limite de horizonte (RN-AGM-003). É chamada a cada carregamento de dia e a cada atualização automática, nas duas direções — precisa ser barata.

-- next: @limiteUtc = 00:00 do dia seguinte a @from (timeZone), em UTC.
SELECT TOP 1 a.DhAgendaIniUTC
FROM Agenda a
JOIN Paciente p ON p.IdPaciente = a.IdPaciente
WHERE a.IdChRecurso = @IdChProfissional
  AND a.IdChClinica IN (SELECT IdChClinica FROM {ClinicasDoMedico})   -- D-CM-068
  AND a.TipoAgenda  = 'C'
  AND p.Paciente   <> 'B'
  AND a.RemovidoEm IS NULL
  AND a.Situacao IN ('A', 'V')
  AND a.DhAgendaIniUTC >= @limiteUtc
ORDER BY a.DhAgendaIniUTC ASC;
-- previous: @limiteUtc = 00:00 de @from, em UTC; condição DhAgendaIniUTC < @limiteUtc e ORDER BY DESC.
-- Resposta: a data local (timeZone) do resultado, ou null.

4.4 Endpoint: GET /api/v1/patients/search

Mapeamento da Central do Médico, Seção 4.10 — reutilizado sem mudança (RN-AGM-014).

Campos novos

Tabela (banco)CampoTipoObrigatoriedadeMotivoStatus
ClienteEmpresa (IpSeguranca)FusoHorarioOficialvarchar(64) (os identificadores IANA têm até ~32 caracteres)NOT NULL, depois de preencher as clínicas existentesFuso da clínica em convenção IANA (RN-AGM-018); a tabela já tem FusoOficial (smallint NOT NULL, deslocamento), que não identifica o fuso IANAMigração a criar (Log de Mudanças, 07/10/2026)
UnidadeAtendimento (GescomClienteAlfa)16 campos do padrão de auditoria do framework (CriadoEm … IpRemovido, inclusive RemovidoEm e UsuarioIdRemovido)conforme framework_pattern.md (Biblioteca de Schema)conforme o padrãoExclusão lógica no lugar de Status A/I (regra do sistema); usado por UnitVisible()Regra do sistema; migração a criar

Migração de dados: ClienteEmpresa.FusoHorarioOficial preenchido para cada clínica (o deslocamento atual não identifica o fuso IANA de forma única — ex.: −03:00 serve a vários fusos —, então o valor é informado na implantação) — tamanho, obrigatoriedade e migração aprovados em 08/10/2026. [PROPOSTA] Em UnidadeAtendimento, registros com Status = 'I' recebem RemovidoEm = data da migração.

Índices

Os campos novos da arquitetura do Gemed 2.1 precisam de índices próprios — registrado no Log de Mudanças Estruturais do Banco de Dados (07/10/2026). Em Agenda, os índices existentes (Biblioteca de Schema — DDL) que tocam o médico ou o tipo de agenda — IX_Agenda_IdChClinica_IdChRecurso_TipoAgenda_Data, IX_Agenda_IdChClinica_IdChRecurso_IdUAtendimento_Data_Situacao, IX_Agenda_IdChClinica_TipoAgenda_Situacao_Data, IX_Agenda_Situacao_TipoAgenda, IX_Agenda_TipoAgenda, FK_Agenda_IdChRecurso — usam a data legada Agenda.Data, não DhAgendaIniUTC, e os compostos começam por IdChClinica.

Para esta funcionalidade, [PROPOSTA] índice não único IX_Agenda_IdChRecurso_TipoAgenda_DhAgendaIniUTC (IdChRecurso, TipoAgenda, DhAgendaIniUTC) INCLUDE (Situacao, IdPaciente, DhAgendaFimUTC, RemovidoEm, IdChClinica) — atende a faixa de GET /day, days-with-appointments e o TOP 1 de next-appointment-date. A confirmar com o time de banco, junto com o impacto em escrita (a Agenda é muito gravada pela Recepção).

Auditoria (NGS1.07.03 / NGS1.07.04)

A leitura da agenda de um dia (GET /day ao carregar um dia; o polling do mesmo dia não gera novo evento) e a abertura do PEP a partir dela geram evento de auditoria (Especificação, Conformidade SBIS). O mecanismo e a tabela da trilha de auditoria são transversais ao sistema e não estão mapeados neste documento — ver “Pendências”, item 1.

Tabelas novas

Nenhuma proposta por esta funcionalidade. Usa IpTerminologia.DomEstadoAgendaConsulta, criada em 27/10/2026 (estrutura no Log de Mudanças Estruturais do Banco de Dados, 27/10/2026: CodEstado char(3) PK, Descricao varchar(30), CorClaroTexto, CorClaroFundo, CorEscuroTexto, CorEscuroFundo char(7)); ainda não está na Biblioteca de Schema (DDL), que precisa de nova extração. O indicador EstadoAgendaConsulta de IpTerminologia.Indicadores será descontinuado depois que a tabela estiver em uso (D-CM-081, Central do Médico).

Nota sobre registros de paciente reservado

Um registro de Agenda com o paciente reservado (Paciente.Paciente = 'B') é um bloqueio de horário criado pela Recepção. Esta funcionalidade só o lê — exibe em blocks (RN-AGM-019) e o exclui das contagens de dias com consulta (4.2, 4.3); não cria nem altera esses registros, e não tem seed para eles. A Central do Médico também os exclui (RN-CM-030), descrevendo-os como bloqueio feito pela Recepção (RN-AGM-019).

Seeds da Funcionalidade

SeedTabela(s)Por cliente ou global?StatusDetalhe completo
Traduções do domínio ModoAtendimento (Presencial, Teleatendimento, Customizado) nos idiomas pt-BR, en-US e es-419TermoTraducao (IpTerminologia)GlobalJá usado pela Central do Médico — conferir que as três línguas existem; termo sem tradução no idioma da clínica aparece como chave e gera anomalia (DT-011)4.1, campo attendanceMode.label
Nome curto de cada clínica e de cada convênio, inclusive “Particular”Chave.Descricao (GescomClienteAlfa)Por clienteJá em produção (cadastro de clínica e convênio)4.1, campos clinic e insurance
Fuso IANA de cada clínicaClienteEmpresa.FusoHorarioOficial (IpSeguranca)Por clienteCampo novo (decidido); preencher na implantação de cada clínica”Campos novos”
Cores dos seis status de consulta nos dois temasDomEstadoAgendaConsulta (IpTerminologia)GlobalTabela criada; conferir os valores contra o Design System, seção 44.1, campo status.colors
Nome dos seis status de consulta em pt-BR, en-US e es-419TermoTraducao (IpTerminologia), Origem = DomEstadoAgendaConsultaGlobalExistentes nos 3 idiomas — conferir4.1, campo status.name
Sigla, descrição e cor de cada tag exibida em agendasProgramaApoio.Sigla/Descricao/Cor (GescomClienteAlfa)Por clienteCadastro existente — conferir que as tags com MostrarEm & 32 têm os três preenchidos4.1, campo tags

Nenhum parâmetro novo (IpParametro/IpParametroChave): a tela não tem limiar configurável próprio.

Pendências

  1. Trilha de auditoria (NGS1.07.03, estágio 1) — mecanismo transversal, não mapeado aqui; precisa existir para a conformidade.
  2. [PROPOSTA] Diagnóstico com prontuário futuro: a Central não exibe o diagnóstico cujo PEP.DataInicioUTC é posterior ao fim de hoje (Central, Mapeamento 4.1). Nesta funcionalidade o critério foi herdado, mas a decisão não foi estendida à Agenda; a extensão natural é avaliar o início no dia exibido, como nas tags (RN-AGM-006). Aguarda decisão; se aprovada, muda o diagnóstico de quem tiver PEP com início depois do dia exibido (ex.: Beatriz A. Lima, PEP 1101, início em 01/10/2026).
  3. Divergência de tipo registrada: Agenda.IdAgendaClassificacao é int e não tem FK, enquanto a PK de AgendaClassificacao é smallint. O join funciona; o risco é de integridade. Registrado no Log de Mudanças Estruturais do Banco de Dados (07/10/2026).
  4. [PROPOSTA] Índice novo em Agenda (ver “Índices”) e migração de Status = 'I' para RemovidoEm em UnidadeAtendimento (ver “Campos novos”).

Histórico de Versões

  • v1.0 (07/10/2026) — Arquivo criado. Primeira versão da Seção 4, a pedido do solicitante (“podemos ir para a próxima seção”), sobre 01-Definição v1.11, 02-Especificação v1.13 e 03-Protótipo v1.11. Estrutura conferida na Biblioteca de Schema (DDL) — Agenda, Paciente, Chave, Portador, Clinica, Convenio, UnidadeAtendimento, AgendaClassificacao, AgendaSubClassificacao (GescomClienteAlfa); ClienteEmpresa, ClientePerfilAcessoUsuario, UsuarioCliente (IpSeguranca), incluindo nulabilidade, existência de RemovidoEm e índices de Agenda — e valores de exemplo na massa de teste CargaCMZero.xlsx (nomes curtos em Chave, Convenio.Convenio = T/B/NULL, UnidadeAtendimento.StConsulta, duas ClienteEmpresa no mesmo ClienteBD com fusos diferentes). Fatos dados pelo solicitante durante a Definição v1.9–v1.10 e usados aqui: nome curto da clínica e do convênio em Chave.Descricao; status também em Chave.Status; plano escrito em Agenda.Plano (não usado); acesso a mais de uma clínica por ClientePerfilAcessoUsuario; unidade ativa para consultas por UnidadeAtendimento.StConsulta = 'S'; particular com Convenio.Convenio = 'T'. Campos e regras herdados da Central do Médico referenciados ao Mapeamento dela (v4.48, Seção 4.1 e 4.10), sem repetição. Achado registrado: Clinica.IdChClinica e Convenio.IdChConvenio chegam a Chave via Portador (FKs da DDL) — é esse o caminho do nome curto.
  • v1.0 — Revisão por Dois Críticos (07/10/2026, mesma versão, antes da entrega ao solicitante) — Crítico técnico (subagente independente, DBA/back-end) sobre esta Seção 4 e o contrato da Especificação; 14 achados, cada um conferido contra a DDL antes de aplicar. Aplicados: (1) a proposta de fuso por clínica muda o contrato de GET /day (linha “AGORA”, rolagem e “Hoje” comparam serverNow com startTime) — registrado em “Referência de tempo” e na pendência 2; (2) delayMinutes positivo para canceladas — passa a exigir Situacao IN ('A','V') e sem início de atendimento, calculado em UTC; (3) SQLs de 4.2/4.3 sem a junção do fuso e sem uso de índice — reescritos com faixa UTC com folga e filtro residual, e TOP 1 em 4.3; (4) vigência das tags quando o dia exibido não é hoje — pendência 4; (5) clínica escondida quando o médico tem acesso a uma só clínica mas foi agendado em outra — pendência 6; uc.RemovidoEm e cache de ClinicVisible(); (6) exclusão lógica — conferido na DDL: Agenda, Paciente, ProgramaApoio e ProgramaApoioPaciente têm RemovidoEm; UnidadeAtendimento, Chave, Clinica, Convenio e as tabelas de classificação não têm — filtro Agenda.RemovidoEm IS NULL acrescentado; (7) tipo dos identificadores: a Especificação dava uuid, o mapeamento int — Especificação corrigida para int (v1.13); (8) Situacao fora do domínio e sobreposição de checked/finished em AppointmentStatus() — filtro pelo domínio e precedência (pendência 7); (9) índice proposto ganhou IdChClinica, DhAgendaFimUTC e RemovidoEm no INCLUDE; UnitVisible() por clínica distinta; (10) endTime com DhAgendaFimUTC NULL (a DDL permite) ou atravessando a meia-noite — regra proposta; (11) afirmações vindas só da massa de teste ou de decisão do Designer marcadas como tal (convênio B, NULL comum, valor R do modo de atendimento, clínica/convênio/classificação inativos); (12) pendências completadas: auditoria, origem do VIP e do code das tags, tradução ausente do modo; (13) remissão da Central ao “mecanismo e seed” na Seção 4 da Agenda tratada em nota própria; classification.name explicitado. Não aplicado (verificado como não procedente): risco de Paciente.Paciente NULL descartar pacientes comuns no filtro <> 'B' — a DDL define Paciente.Paciente como char(1) NOT NULL.
  • v1.1 (07/10/2026) — Respostas do solicitante às pendências da v1.0. (1) Exclusão lógica no lugar de Status: no legado, a maioria das tabelas usa Status A/I; a regra está sendo descontinuada e substituída por RemovidoEm/UsuarioIdRemovido, valendo para todo o sistema — UnitVisible() passa a usar RemovidoEm IS NULL, o que exige o padrão de auditoria em UnidadeAtendimento (que não o tem na DDL — nova subseção “Campos novos”); tags passam a filtrar RemovidoEm em ProgramaApoio e ProgramaApoioPaciente; a Central deve aplicar a regra quando descongelada; pendência do valor ativo de Status encerrada. (2) Fuso: tudo no fuso da clínica do login — a proposta de fuso por clínica da consulta foi recusada; campo novo Clinica.FusoHorarioOficial (IANA, ex.: America/Sao_Paulo), que o solicitante informou estar sendo criado para substituir Clinica.FusoHorario (deslocamento); GET /day devolve timeZone (RN-AGM-018) e a tela informa o fuso; SQLs de 4.2/4.3 simplificados para faixa UTC exata, com a conversão na aplicação. Nova pendência: ligação entre ClienteEmpresa (clínica do login) e Clinica. (3) Tags: code = sigla (ProgramaApoio.Sigla), description, color; vigências no dia exibido (confirmado); origem do VIP continua indefinida, por decisão do solicitante. (4) Clínicas do cliente = mesmo ClienteBD, confirmado. (5) Risco da clínica escondida retirado: o solicitante esclareceu que a Recepção não consegue agendar o médico numa clínica a que ele não está vinculado, porque ele só tem horários nas clínicas do seu vínculo. (6) Índices: registrado que os campos novos da arquitetura do Gemed 2.1 precisam de índices (Log de Mudanças, 07/10/2026). Acompanha 01-Definição v1.12, 02-Especificação v1.14 e 03-Protótipo v1.12.
  • v1.2 (08/10/2026) — Correção do solicitante: o fuso IANA fica em IpSeguranca.ClienteEmpresa.FusoHorarioOficial; não há esse campo em Clinica (GescomClienteAlfa). timeZone, “Tabelas envolvidas”, “Referência de tempo”, “Domínios”, “Campos novos” e “Seeds” passam a apontar para ClienteEmpresa — a mesma linha que já dá o idioma da clínica do login. Encerrada a pendência da ligação entre ClienteEmpresa e Clinica (não é mais necessária para o fuso); pendências renumeradas. Sem mudança de regra, contrato ou tela.
  • v1.3 (08/10/2026) — Decisões do solicitante. (1) Paciente reservado (bloqueio): “No caso da agenda, ela deve aparecer (ao contrário do painel da central), pois é um bloqueio de agenda gerada pela recepção” — GET /day deixa de filtrar Paciente.Paciente <> 'B' e devolve esses registros em blocks (RN-AGM-019, Definição v1.13); novo mapa de campos de blocks; motivo = Agenda.Complemento (confirmado pelo solicitante); 4.2 e 4.3 mantêm o filtro, porque dia só com bloqueio não conta como dia com consulta (decisão do solicitante); domínio Paciente.Paciente = 'B' e “Nota sobre registros de paciente reservado” reescritos. Novas pendências: como a Recepção desfaz um bloqueio [A DEFINIR]; clínica/unidade no bloqueio [PROPOSTA]. (2) Precedência de AppointmentStatus() aprovada — pendência encerrada; a correção na Central entra na pendência da Central. (3) ClienteEmpresa.FusoHorarioOficial: varchar(64), NOT NULL depois de preencher as clínicas, valor informado na implantação — aprovados; continuam como proposta só o índice novo em Agenda e a migração de UnidadeAtendimento. Pendências renumeradas. Acompanha 01-Definição v1.13, 02-Especificação v1.15 e 03-Protótipo v1.13.
  • v1.4 (08/10/2026) — Decisões do solicitante: “pode mostrar a clínica e unidade com os mesmos critérios das agendas”; “a recepção pode cancelar pela situação (quando for um cancelamento formal) e também pode fazer a exclusão lógica (quando esse bloqueio passa a não existir). Nos dois casos, deve sumir da agenda.” blocks[].clinic/unit confirmados; regra de bloqueio desfeito fechada (cancelamento pela Situacao → fora pela AppointmentStatus() = canceled; exclusão lógica → fora por RemovidoEm). Pendências 5 e 6 da v1.3 encerradas; renumeradas. Acompanha 01-Definição v1.14 e 02-Especificação v1.16.
  • v1.5 (08/10/2026) — Decisões do solicitante. (1) Tags atribuídas no prontuário: “devemos mostrar PEPProgramaApoioPaciente também na agenda”; vigência da tag em ProgramaApoio.DataInicio/DataFim; vigência da atribuição em PEP.DataInicioUTC/DataFimUTC (para PEPProgramaApoioPaciente) e na própria ProgramaApoioPaciente (DataInicio/DataFim). Campo tags reescrito como união das duas origens; PEPProgramaApoioPaciente/PEP em “Tabelas envolvidas”. Achado: PEP.DataInicioUTC/DataFimUTC não estão na Biblioteca de Schema (DDL) — nova pendência 5 e entrada no Log de Mudanças. [PROPOSTA] regra de vigência no dia para períodos com hora e tag repetida aparecendo uma vez (pendência 6). Pendência da Central ampliada (a Central também deve ler as duas origens). (2) Bloqueio sem unidade: “retirei a unidade de atendimento do bloqueio (não faz sentido ter uma unidade)” — blocks[].unit sai do contrato; nota no mapa de blocks. As duas perguntas vieram dos Cenários de Teste v1.0 (lacunas 1 e 2). Acompanha 01-Definição v1.15, 02-Especificação v1.17 e 03-Protótipo v1.14.
  • v1.7 (09/10/2026) — Acompanha a Central do Médico v5.1. Retiradas as pendências que dependiam da Central: aplicadas na Central v5.1 as tags do prontuário com vigência em PEP.DataInicioUTC/DataFimUTC, a exclusão lógica por RemovidoEm, a precedência de AppointmentStatus(), o bloqueio de horário pela Recepção em RN-CM-030 e ClienteEmpresa.FusoHorarioOficial; a Central deixa de ser tratada como congelada. Retirada também a pendência de que PEP.DataInicioUTC/DataFimUTC não estariam na Biblioteca de Schema (DDL): conferidos no catalog.json e no gescomAlfa.sql, os dois campos existem (datetimeoffset NULL) — a afirmação anterior estava errada. Nova pendência 2 ([PROPOSTA]): estender à Agenda a regra de diagnóstico com prontuário futuro decidida para a Central. Pendências renumeradas (eram 5, ficam 4). 01-Definição, 02-Especificação, 03-Protótipo e Cenários de Teste só com o cabeçalho sincronizado.
  • v1.6 (08/10/2026) — Decisões do solicitante. (1) Vigência no dia para períodos com hora (PEP.DataInicioUTC/DataFimUTC) aprovada — deixa de ser proposta. (2) Tag repetida nas duas origens: “é improvável ter a mesma tag nas 2 origens, pois as tags são separadas por ProgramaApoio.Finalidade = A (assistencial), que só é usada no prontuário, e D (administrativo), que só é usada no cadastro”; se acontecer, aparece uma vez — registrado no campo tags e em “Domínios”. (3) VIP: “desconsidere o campo Paciente.PacienteVip, por enquanto” — a tag VIP vem de ProgramaApoioPaciente, como as demais tags administrativas; pendência da origem do VIP encerrada. Pendências renumeradas (eram 7, ficam 5). Acompanha 02-Especificação v1.18; 01-Definição v1.15 e 03-Protótipo v1.14 só com o cabeçalho sincronizado.
  • v1.8 (09/10/2026) — (1) Tag VIP sem exceção: Decisão do solicitante: a exceção “VIP sempre exibida” vinha do campo Paciente.PacienteVip, que não é considerado até se confirmar o uso em produção — “pode retirar essa regra”. A VIP passa a seguir as mesmas regras das demais tags (habilitação para agendas e vigências no dia exibido). (2) Regra de vigência no dia explicitada para o dia do fim (vale como vigente), a partir da massa de teste do solicitante (VIP do paciente 3 com fim em 23/09 e tags “que vencem no dia 23 (hoje)” aparecendo hoje e não amanhã). Acompanha 01-Definição v1.16 e 02-Especificação v1.19.
  • v1.9 (21/10/2026) — Decisão transversal DT-011 (Decisões Transversais v1.3), com autorização do solicitante: “pode ajustar toda documentação”. attendanceMode.label: sai a [PROPOSTA] de usar a tradução em pt-BR quando falta a do idioma da clínica; passa a valer a regra do sistema — vai a própria chave (Agenda.Atendimento) e o back-end registra anomalia no log técnico, sem queda para outro idioma. Linha de seeds de ModoAtendimento com a mesma observação. O idioma é sempre o da clínica (DT-012), como já estava. Sem mudança de schema nem de contrato. 01-Definição, 02-Especificação, 03-Protótipo e Cenários de Teste só com o cabeçalho sincronizado.
  • v1.10 (26/10/2026) — Decisões do solicitante na Central do Médico (Registro de Decisões v1.12, D-CM-067 e D-CM-068): “sim, precisa filtrar pelas clínicas que o usuário tem acesso. Se ele perdeu acesso a uma clínica, não pode mais ver suas agendas e nem mesmo os pacientes dela.” (1) 4.1, 4.2 e 4.3: filtro explícito Agenda.IdChClinica IN (SELECT IdChClinica FROM {ClinicasDoMedico}) no lugar de “sem filtro por clínica”; a tabela {ClinicasDoMedico} é definida na Central (Mapeamento v5.13, Seção 4), não repetida aqui. (2) ClinicVisible(): sai a frase de que não há consulta numa clínica sem acesso — pode haver, e ela não aparece. (3) Índice proposto ganha IdChClinica no INCLUDE (a coluna passa a ser lida no filtro).
  • (sincronização, 26/10/2026) — sem mudança de conteúdo deste documento; apenas a linha de cabeçalho atualizada para apontar 01-Definição v1.18 (RN-AGM-002 corrigida: o médico sem acesso à clínica perde as agendas dela, não o acesso ao paciente, D-CM-070).
  • v1.11 (27/10/2026) — Acompanha 02-Especificação v1.21 e 03-Protótipo v1.15. Cores de status por tema vindas da API (DT-016; Design System de 27/10/2026, seção 4), a partir da proposta da equipe de front aprovada pelo solicitante, e respostas do solicitante de 27/10/2026: Cancelado em cinza preenchido com os textos do item riscados, exceto o chip (“vamos manter o cancelado como proposto pelo front, mas acrescentamos que o card cancelado fica com os textos riscados (hora, nome, etc), exceto o chip de estado”; avatar: “só os textos”); avatar com as iniciais em neutral-darker sobre a cor de fundo do status (“ele deve representar mais o paciente do que o estado da agenda”); cores em IpTerminologia.DomEstadoAgendaConsulta, iguais para todas as clínicas, nome por TermoTraducao com Termo = CodEstado. 4.1: status vira objeto — status.domain (AppointmentStatus()), status.name (TermoTraducao, Termo = CodEstado, Origem = DomEstadoAgendaConsulta) e status.colors (quatro colunas de cor de DomEstadoAgendaConsulta; colors só vai com as quatro preenchidas); tabela Status × CodEstado em “Domínios”; DomEstadoAgendaConsulta em “Tabelas envolvidas” e “Tabelas novas” (criada pelo solicitante, ainda fora da Biblioteca); dois seeds globais. A ligação Status × CodEstado é a informada pelo solicitante; a regra “colors só com as quatro colunas preenchidas” é do Designer (segue o contrato do Design System, seção 4).
  • v1.12 (27/10/2026) — Acompanha 02-Especificação v1.22 e 03-Protótipo v1.16. Acompanha a Central do Médico v5.16 (Registro de Decisões v1.15). (1) “Tabelas novas”: o indicador EstadoAgendaConsulta será descontinuado depois da implementação nova (D-CM-081). (2) Menções de proveniência de decisões (“solicitante”) retiradas do corpo — Mapa de campos, Funções, Domínios, Campos novos, Índices e pendências —, que passam a existir só no Histórico de Versões (D-CM-083). Nenhuma mudança de regra, de campo ou de SQL.
  • v2.0 (27/10/2026) — Abertura da versão 2.0, a pedido do solicitante: “a agenda do médico foi para desenvolvimento na versão dos documentos: 01.Definição (v1.6); 02.Especificação (v1.19); 03.Prototipo (v1.14); 04.Mapeamento de BD (v1.9); Cenários de teste (v1.6) […] Precisamos congelar a versão e iniciar a v2 para não termos confusão com as mudanças”. A Definição desenvolvida é a v1.16 (“v1.6” no pedido): é a que acompanha a Especificação v1.19, o Protótipo v1.14 e o Mapeamento v1.9 nos cabeçalhos desses arquivos. Base de desenvolvimento, congelada: 01-Definição v1.16, 02-Especificação v1.19, 03-Protótipo v1.14 (.md + .html), 04-Mapeamento de BD v1.9 e Cenários de Teste v1.6, em Histórico/, sem alteração. A série 2.x reúne o que muda depois dela, para a próxima versão de desenvolvimento. Já fazem parte da série 2.x, sem mudança de conteúdo nesta abertura: v1.10 (filtro pelas clínicas do médico, {ClinicasDoMedico}, em 4.1 a 4.3, e IdChClinica no índice proposto), v1.11 (status como objeto, com cores de IpTerminologia.DomEstadoAgendaConsulta e nome por TermoTraducao) e v1.12 (indicador EstadoAgendaConsulta a descontinuar depois da implementação nova — D-CM-081; proveniência retirada do corpo). Conteúdo igual ao da v1.12; mudam só o título, o cabeçalho e este Histórico.
  • v2.1 (28/10/2026) — Sem mudança de conteúdo deste documento; só o número da versão, para acompanhar os demais arquivos (nome “Aguardando recepção”, D-CM-084). Acompanha a Central do Médico v5.17 (Registro de Decisões v1.16, D-CM-084).
  • v3.0 (29/10/2026) — Abertura da versão 3.0, a pedido do solicitante: “Vou mandar essas mudanças para desenvolvimento e fechamos nova versão. Depois que gerar o documento, abrimos uma nova versão a partir de então.” A série 2 fecha na v2.1, que vai para desenvolvimento: 01-Definição v2.1, 02-Especificação v2.1, 03-Protótipo v2.1 (.md + .html), 04-Mapeamento de BD v2.1 e Cenários de Teste v2.1, em Histórico/, sem alteração. O que mudou da base anterior (Definição v1.16, Especificação v1.19, Protótipo v1.14, Mapeamento v1.9, Cenários v1.6) até a v2.1 está em Para Desenvolvedores/Agenda do Médico - mudanças da v2 - guia para desenvolvimento.md; o que mudar a partir daqui entra também em Para Desenvolvedores/Agenda do Médico - mudanças da v3 - guia para desenvolvimento.md. Conteúdo igual ao da v2.1; mudam só o título, o cabeçalho e este Histórico.