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

Documentos desta funcionalidade: 01 - Definição (v1.11) · 02 - Especificação (v1.13) · 03 - Protótipo (v1.11, código executável em 03 - Protótipo v1.11.html) · 04 - Mapeamento de Banco de Dados (v1.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 e nenhum campo novo: tudo o que a tela exibe já existe e é preenchido pelo Agendamento (Recepção).

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, de todas as clínicas do cliente (RN-AGM-002).

Tabelas envolvidas

TabelaBancoFunção no endpoint
AgendaGescomClienteAlfaTabela principal — uma linha por consulta
PacienteGescomClienteAlfaNome, nome social e o indicador de paciente reservado (filtro)
PacienteFotoGescomClienteAlfaFoto do paciente
PEP / PEPDiagnosticoGescomClienteAlfaDiagnósticos oncológicos do paciente
ProgramaApoio / ProgramaApoioPacienteGescomClienteAlfaTags do paciente (RN-AGM-006)
ChaveGescomClienteAlfaNome curto da clínica e do convênio (RN-AGM-017)
ClinicaGescomClienteAlfaFuso horário da clínica de cada consulta [PROPOSTA] (ver “Referência de tempo”)
UnidadeAtendimentoGescomClienteAlfaNome da unidade e contagem de unidades ativas para consultas (RN-AGM-017, b)
AgendaClassificacao / AgendaSubClassificacaoGescomClienteAlfaClassificação e subclassificação (RN-AGM-008)
TermoTraducaoIpTerminologiaRótulo traduzido do modo de atendimento
ClienteEmpresaIpSegurancaIdioma e fuso 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
serverNowdata/horarelógio do servidor, no fuso de ClienteEmpresa.FusoOficial da clínica em que o usuário entrouReferência de tempo da tela (Especificação, “Referência de tempo”)
appointments[].idintAgenda.IdAgenda
startTimehorárioAgenda.DhAgendaIniUTC (NULL possível na DDL)No fuso de “Referência de tempo”. Consulta com DhAgendaIniUTC NULL não entra na lista (não tem dia nem posição)
endTimehorárioAgenda.DhAgendaFimUTC (NULL possível na DDL)No fuso de “Referência de tempo”. [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)
statusstringcalculado — 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
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. [PROPOSTA] Sem tradução no idioma da clínica, usar a de pt-BR
delayMinutesintcalculadoMinutos entre agora e DhAgendaIniUTC, calculados em UTC (a diferença não depende de fuso). Positivo só quando date é hoje, o horário já passou, Agenda.Situacao IN ('A','V') e DhAtendimentoIniUTC IS NULL; em qualquer outro caso, 0 — inclusive canceladas, que esta tela exibe e a Central não
firstTimebooleanAgenda.PrimeiraConsulta = 'S'Domínio S/N
tagsarrayPaciente.PacienteVip + ProgramaApoioPaciente/ProgramaApoioOrigem, filtro (MostrarEm & 32) = 32, vigências e exceção VIP: Central do Médico, 4.1 (RN-CM-025). Na Agenda, “hoje” das vigências é o dia exibido (date) [PROPOSTA]. Cor, descrição e o achado em aberto sobre a origem do VIP: ver “Pendências”, item 3
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)
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 esteja inativa hoje (Chave.Status) — 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 específica esteja inativa hoje
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. [PROPOSTA] Exibido mesmo que o convênio esteja inativo hoje (Chave.Status). 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))[PROPOSTA] Exibida mesmo que a classificação esteja inativa hoje (AgendaClassificacao.Status)
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).

Funções de cálculo

AppointmentStatus() — a da Central do Médico (4.1). Precedência adotada aqui [PROPOSTA], 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 de canceled para scheduled (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 — ela 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.
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 [PROPOSTA]
  AND uc.RemovidoEm   IS NULL
  AND cpau.RemovidoEm IS NULL
  AND ce.RemovidoEm   IS NULL;

O filtro por ClienteBDId é [PROPOSTA]: “clínicas do cliente” interpretado como as ClienteEmpresa do mesmo banco de cliente — a massa de teste (CargaCMZero.xlsx) tem duas ClienteEmpresa (“Clinica A” e “Clínica B”) no mesmo ClienteBD. Mesmo critério de “clínica acessível” do Check-in de Usuários (RN-CIU-009, Épico 1), restrito ao banco atual. Ver “Pendências”, item 6, sobre o caso de consulta numa clínica a que o médico não tem acesso.

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                -- sem RemovidoEm na DDL
WHERE IdClinica  = @IdChClinica
  AND StConsulta = 'S'
  AND Status     = @StatusAtivo;       -- [A DEFINIR] valor de "ativa" em UnidadeAtendimento.Status

Referência de tempo — [PROPOSTA]

A agenda reúne clínicas que podem estar em fusos diferentes — a massa de teste tem “Clinica A” (FusoOficial = -4) e “Clínica B” (-3) no mesmo banco de cliente. A proposta:

  • serverNow e o que é “hoje”: fuso da clínica em que o usuário entrou (ClienteEmpresa.FusoOficial), como na Central do Médico.
  • Horários e dia de cada consulta: fuso da clínica da consulta, Clinica.FusoHorario (varchar(35) NOT NULL, GescomClienteAlfa) — o horário mostrado é o horário local onde o paciente será atendido. Formato do campo (nome IANA, nome de fuso do Windows ou deslocamento): [A DEFINIR] — decide se a conversão pode ser feita no banco (AT TIME ZONE do SQL Server aceita só nomes do Windows) ou precisa ser feita na aplicação.

Esta proposta muda o contrato da Especificação, que hoje define startTime/endTime como HH:MM “no fuso da clínica”, no singular, e usa serverNow para a linha “AGORA”, a rolagem inicial e o “Hoje”: com dois fusos na mesma lista, comparar serverNow com startTime deslocaria esses elementos. Se aceita, a Especificação passa a mandar também o início e o fim de cada consulta em ISO 8601 com deslocamento (para o front comparar com serverNow em UTC) e a mostrar, quando os fusos diferem, a qual fuso o horário se refere.

Alternativa, se a proposta não for aceita: tudo no fuso da clínica do login (comportamento da Central, contrato atual), aceitando que as consultas de uma clínica em outro fuso apareçam com o horário convertido para o fuso do login.

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.

Domínios usados só por esta funcionalidade:

CampoValorSignificadoFonte
UnidadeAtendimento.StConsultaS / NUnidade atende (ou não) consultasSolicitante; massa de teste (CargaCMZero.xlsx)
UnidadeAtendimento.Status[A DEFINIR]Unidade ativa / inativa—
Convenio.ConvenioTConvênio “Particular”Solicitante; 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
Paciente.PacienteBPaciente reservado, que não representa consulta (char(1) NOT NULL)Central do Médico, RN-CM-030; demais valores não mapeados aqui

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; sem filtro por clínica (RN-AGM-002).
  • Agenda.TipoAgenda = 'C' — agendas de consulta.
  • Paciente.Paciente <> 'B' (via Agenda.IdPaciente; Paciente.Paciente é NOT NULL, então o filtro não descarta pacientes comuns) — exclui registros de agenda com o paciente reservado, que não representam consulta (mesmo filtro da Central, RN-CM-030).
  • Agenda.RemovidoEm IS NULL — exclusão lógica (o campo existe em Agenda na DDL). [A DEFINIR] se a Central também deve aplicar este filtro (o Mapeamento dela não o cita).
  • Agenda.Situacao IN ('A','V','C','D','F','I','M','O','T') — todo o domínio SituacaoAgenda; canceladas (inclusive falta) entram, com status = canceled (RN-AGM-009/010).
  • Agenda.DhAgendaIniUTC IS NOT NULL e dia de DhAgendaIniUTC, no fuso de “Referência de tempo”, igual a date. Para usar índice, a consulta filtra primeiro uma faixa UTC ampla (DhAgendaIniUTC >= @dataInicioUtc - 14h AND DhAgendaIniUTC < @dataFimUtc + 14h, folga do maior deslocamento de fuso) e aplica o dia exato no fuso como filtro residual.
  • Tags: filtros de MostrarEm e de vigência da Central (4.1), avaliados no dia date.
  • 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).

Tabelas envolvidas

Agenda, Paciente (filtro), Clinica (fuso da consulta, se a proposta de “Referência de tempo” for aceita) — mesmas de 4.1.

Consulta

-- @fromUtc/@toUtc: início de @from e fim de @to, com folga de 14h para cada lado.
-- LocalDate(): data de DhAgendaIniUTC no fuso de "Referência de tempo" (4.1) —
-- no banco, se Clinica.FusoHorario for nome de fuso do Windows; senão, na aplicação.
SELECT DISTINCT LocalDate(a.DhAgendaIniUTC, c.FusoHorario) AS Data
FROM Agenda a
JOIN Paciente p ON p.IdPaciente  = a.IdPaciente
JOIN Clinica  c ON c.IdChClinica = a.IdChClinica
WHERE a.IdChRecurso = @IdChProfissional
  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
  AND LocalDate(a.DhAgendaIniUTC, c.FusoHorario) BETWEEN @from AND @to   -- filtro residual
ORDER BY Data;

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: a primeira consulta depois do fim de @from (com folga de fuso); previous: o inverso, com DESC.
SELECT TOP 1 LocalDate(a.DhAgendaIniUTC, c.FusoHorario) AS Data
FROM Agenda a
JOIN Paciente p ON p.IdPaciente  = a.IdPaciente
JOIN Clinica  c ON c.IdChClinica = a.IdChClinica
WHERE a.IdChRecurso = @IdChProfissional
  AND a.TipoAgenda  = 'C'
  AND p.Paciente   <> 'B'
  AND a.RemovidoEm IS NULL
  AND a.Situacao IN ('A', 'V')
  AND a.DhAgendaIniUTC >= @fromFimUtc - 14h                         -- faixa usa o índice
  AND LocalDate(a.DhAgendaIniUTC, c.FusoHorario) > @from             -- filtro residual
ORDER BY a.DhAgendaIniUTC ASC;

Sem a proposta de fuso por clínica, LocalDate() usa o fuso da clínica do login e o JOIN Clinica sai.

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).

Índices

Índices existentes em Agenda (Biblioteca de Schema — DDL, GescomClienteAlfa) 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 e o de FK FK_Agenda_IdChRecurso. Todos os compostos começam por IdChClinica e usam a data legada Agenda.Data, não DhAgendaIniUTC. Como esta tela não filtra por clínica (RN-AGM-002) e usa DhAgendaIniUTC, nenhum deles cobre as três consultas.

[PROPOSTA] índice não único IX_Agenda_IdChRecurso_TipoAgenda_DhAgendaIniUTC (IdChRecurso, TipoAgenda, DhAgendaIniUTC) INCLUDE (Situacao, IdPaciente, IdChClinica, DhAgendaFimUTC, RemovidoEm) — atende a faixa de GET /day, days-with-appointments e o TOP 1 de next-appointment-date; IdChClinica no INCLUDE evita ir à tabela base para achar o fuso. A confirmar com o time de banco antes de criar, 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 8.

Tabelas novas

Nenhuma.

Nota sobre registros de paciente reservado

O filtro Paciente.Paciente <> 'B' vem da Central do Médico (RN-CM-030). Esta funcionalidade não cria nem altera esses registros, e não tem seed para eles. A Central (congelada) ainda remete a “mecanismo e seed a detalhar na Seção 4” da Agenda do Médico — remissão que fica sem objeto e deve ser retirada da Central quando ela for descongelada.

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 existem4.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

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

Pendências

  1. [A DEFINIR] Valor de “ativa” em UnidadeAtendimento.Status (usado em UnitVisible()); a massa de teste não preenche o campo.
  2. [PROPOSTA] Referência de tempo com várias clínicas: horários e dia de cada consulta no fuso da clínica da consulta (Clinica.FusoHorario) — muda o contrato da Especificação (início/fim em ISO 8601 por consulta). [A DEFINIR] o formato de Clinica.FusoHorario.
  3. [PROPOSTA] Contrato de tags com cor e descrição — a Especificação define tags como lista de códigos, mas a cor vem do cadastro (ProgramaApoio.Cor/Descricao, Central 4.1). Proposta: tags: [{ "code", "label", "color", "description" }], com code = ProgramaApoio.IdProgramaApoio, label = ProgramaApoio.Nome; quando o VIP chegar pelos dois caminhos (Paciente.PacienteVip e ProgramaApoioPaciente), aparece uma vez só. Depende do achado em aberto da Central (4.1, campo tags) sobre a origem do VIP. Exige ajuste da Especificação.
  4. [PROPOSTA] Vigência das tags avaliada no dia exibido (date), não em “hoje”.
  5. [PROPOSTA] “Clínicas do cliente” = ClienteEmpresa do mesmo ClienteBD da sessão (em ClinicVisible()). Não há campo que ligue ClienteEmpresa (IpSeguranca) a Clinica (GescomClienteAlfa) — a regra não precisa dessa ligação, mas qualquer funcionalidade futura que precise saber “qual Clinica é esta ClienteEmpresa” vai precisar.
  6. Risco a decidir: se o médico tem acesso a uma única clínica, mas a Recepção o agendou também em outra, a lista mistura as duas e clinic vem vazio em todas (RN-AGM-017, a, fala em “acesso”). Alternativa: mostrar a clínica quando as consultas do dia vierem de mais de uma clínica.
  7. [PROPOSTA] Precedência de AppointmentStatus() (caso V com fim sem início = finished) — a sobreposição é herdada da Central e deve ser corrigida lá também.
  8. Trilha de auditoria (NGS1.07.03, estágio 1) — mecanismo transversal, não mapeado aqui; precisa existir para a conformidade.
  9. Divergência de tipo registrada: Agenda.IdAgendaClassificacao é int e não tem FK, enquanto a PK de AgendaClassificacao é smallint (Agenda.IdAgendaSubClassificacao, por sua vez, tem FK). O join funciona; o risco é de integridade (classificação apagada sem erro). Registrado no Log de Mudanças Estruturais do Banco de Dados como descoberta.
  10. [PROPOSTA] Índice novo em Agenda (ver “Índices”).
  11. [A DEFINIR] Filtro Agenda.RemovidoEm IS NULL na Central do Médico (aplicado aqui; não citado no Mapeamento da Central).

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.