Central do Médico (Cockpit) — Mapeamento de Banco de Dados (v4.28)

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


SEÇÃO 4 — MAPEAMENTO DE BANCO DE DADOS

4.1 Endpoint: GET /api/v1/cockpit/doctor/appointments

Retorna a lista de consultas do médico logado para o dia atual.

Tabelas envolvidas

TabelaBancoFunção no endpoint
AgendaGescomClienteAlfaTabela principal — dados da agenda
PacienteGescomClienteAlfaDados do paciente (nome, nome social)
PacienteFotoGescomClienteAlfaFoto do paciente
PEPDiagnosticoGescomClienteAlfaDiagnóstico oncológico do paciente
TermoTraducaoIpTerminologiaTradução do modo de atendimento
ClienteEmpresaIpSegurancaIdioma e fuso horário da clínica

Mapa de campos

CampoTipoBancoObservação
idintAgenda.IdAgenda
startTimehorárioAgenda.DhAgendaIniUTCsó horário, convertido para o fuso e idioma da clínica
endTimehorárioAgenda.DhAgendaFimUTCsó horário, convertido para o fuso e idioma da clínica
statusstringcalculadovide AppointmentStatus()
typestringAgenda.Atendimento -> TermoTraducao.TermoValorTermo = Agenda.Atendimento, Origem=“Indicadores
firstTimecharAgenda.PrimeiraConsultadomínio = ‘S’=sim, ‘N’=não
delayMinutesintNow(no fuso da clínica)-Agenda.DhAgendaIniUTC(no fuso da clínica)Se o valor for negativo (horário previsto ainda não chegou), retorna 0 — só é positivo quando o horário previsto já passou e a consulta não foi iniciada
patient.idintAgenda.IdPaciente
patient.prefferedNamestringPaciente.NomeSocialse existir, usar este como nome principal
patient.legalNamestringPaciente.Nomese NomeSocial não existir, usar este como nome
patient.photourlPacienteFoto.NomeArquivo, busca IdPaciente e Padrao = ‘S’, se multiplos, retorna o mais recenteurl gerada pelo MinIO
patient.diagnosisarray de stringPEPDiagnostico.Diagnostico para Tipo = ‘O’ e PEP.IdPacienteretorna TODOS os diagnósticos oncológicos ativos do paciente (não só um) — o card exibe a lista completa
tagsarray de stringPaciente.PacienteVip (bit=1 → tag vip) UNION ProgramaApoioPaciente filtrado por IdPaciente (ativo quando DataInicio <= hoje e DataFim IS NULL ou DataFim >= hoje) join ProgramaApoio (Nome/Sigla/Cor)Cor de cada tag vem de ProgramaApoio.Cor (exceto vip, que usa o token de destaque do Design System, Seção 2.8). Consultado no EsquemaGemed21.csv: ProgramaApoioPaciente/ProgramaApoio existem; PEPProgramaApoioPaciente (vínculo por PEP, em vez de por paciente) existe mas não é usado aqui — as tags do Cockpit são no nível do paciente, não do atendimento.

Funções de cálculo

AppointmentStatus() — calcula o status da consulta a partir dos campos da Agenda:

Status retornadoCondição
scheduled (Agendado)Agenda.Situacao = ‘A’ AND DhChegadaUTC IS NULL
waiting (Aguardando recepção)Agenda.Situacao = ‘A’ AND DhChegadaUTC IS NOT NULL
checked (Recepcionado)Agenda.Situacao = ‘V’ AND DhAtendimentoIniUTC IS NULL
consultation (Em atendimento)Agenda.Situacao = ‘V’ AND DhAtendimentoIniUTC IS NOT NULL AND DhAtendimentoFimUTC IS NULL
`finished’ (Finalizado)Agenda.Situacao = ‘V’ AND DhAtendimentoFimUTC IS NOT NULL
’canceled’ (Cancelado)Agenda.Situacao IN (‘C’,‘D’,‘F’,‘I’,‘M’,‘O’,‘T’)

Domínios

TipoAgenda (domínio de Agenda.TipoAgenda) na tabela Indicadores:

ValorSignificado
CConsulta
QQuimioterapia
RRadioterapia
SReserva de sala para assuntos não assistenciais

ModoAtendimento (domínio de Agenda.Atendimento) na tabela Indicadores:

ValorSignificado
PPadrão (Presencial)
TTeleatendimento
CCustomizado
RReservado

SituacaoAgenda (domínio de Agenda.Situacao) na tabela Indicadores:

ValorSignificado
AAberta
VConfirmada (check-in realizado)
CCancelada pelo usuário
DCancelada pelo paciente
MCancelada pelo médico
FFalta
ICancelado por internação
OCancelada por óbito
TTransferido (cancelado)

TipoDiagnostico (domínio de Diagnostico.Tipo):

ValorSignificado
CComorbidade
ODoença oncológica

Infraestrutura de apoio

MinIO (Storage de fotos):

  • Bucket global: gemed
  • Bucket por ambiente do cliente: nome = banco de dados do cliente
  • 1 bucket por banco de dados (cliente pode ter múltiplos bancos)
  • Pasta de fotos: FotosPacientes/ dentro do bucket do cliente
  • Seleção da foto: PacienteFoto.Padrao = 'S'; se múltiplas, selecionar a mais recente (futuro: vamos usar o campo CriadoEm da infraestrutura)

Internacionalização (i18n):

  • Idioma da clínica: ClienteEmpresa.IdiomaOficial (IpSeguranca), o termo segue padrão BCP 47
  • Fuso horário da clínica: ClienteEmpresa.FusoOficial (IpSeguranca)
  • Traduções: tabela TermoTraducao (IpTerminologia) usa chave composta por (Termo, Origem, Idioma)
    • Origem: nome da tabela de origem ou Indicadores|<NomeIndicador> quando o domínio está na tabela Indicadores
    • Idioma: Idioma do cliente
    • Termo: o termo usado como chave na tabela de origem

Filtros do endpoint

  • Agenda.IdChRecurso = {IdChProfissional do médico logado} — apenas consultas do médico
  • Agenda.TipoAgenda = 'C' - Agendas de consulta
  • Agenda.DhAgendaIniUTC(no fuso da clínica) = Hoje(no fuso da clinica) — apenas consultas do dia atual
  • Toggle “Pendentes”: Agenda.Situacao IN ('A','V')ANDDhAtendimentoFimUTC IS NULL — exclui canceladas e finalizadas
  • Toggle “Todas”: inclui finalizadas (canceladas não aparecem no painel — apenas finalizadas esmaecidas)

4.2 Endpoint: GET /api/v1/cockpit/doctor/kpis/appointments-today

Retornar o indicador de Consultas Hoje

Tabelas envolvidas

TabelaBancoFunção no endpoint
AgendaGescomClienteAlfaTabela principal — dados da agenda

Mapa de campos

CampoTipoBanco
totalintcount(Agenda.Situacao IN (‘A’, ‘V’))
finishedintcount(Agenda.Situacao=‘V’, Agenda.DhAtendimentoFimUTC<>NULL)
pendingintcount(Agenda.Situacao IN (‘A’, ‘V’), Agenda.DhAtendimentoFimUTC=NULL)
delayedintcount(Agenda.Situacao IN (‘A’, ‘V’), Agenda.DhAtendimentoFimUTC=NULL, Now(no fuso da clínica)-Agenda.DhAgendaIniUTC(no fuso da clinica)>0)

Domínios

** os mesmos do endpoint acima

Filtros do endpoint

  • Agenda.IdChRecurso = {IdChProfissional do médico logado} — apenas consultas do médico
  • Agenda.TipoAgenda = 'C' - agendas de consulta
  • Agenda.DhAgendaIniUTC(no fuso da clínica) = Hoje(no fuso da clinica) — apenas consultas do dia atual

4.3 Endpoint: [GET] /api/v1/cockpit/doctor/procedures

`{ "procedures":
    [ { "id": "uuid",
        "patient":
            { "id": "uuid",
              "preferredName": "",
              "legalName": "Roberto Oliveira"
            },
        "location": "Sala de Infusão 2",
        "status": "administering",
        "startTime": "2026-07-22T09:30:00Z",
        "progress": 65,
        "mine": true,
        "tags": ["quimioterapia"]
      }
    ]
}`

Retorna a lista de pacientes em procedimentos no dia atual.

Tabelas envolvidas

TabelaBancoFunção no endpoint
AgendaGescomClienteAlfaTabela principal — dados da agenda
PacienteGescomClienteAlfaDados do paciente (nome, nome social)
PacienteFotoGescomClienteAlfaFoto do paciente
PrescricaoGescomClienteAlfaDiagnóstico oncológico do paciente
TermoTraducaoIpTerminologiaTradução do modo de atendimento
ClienteEmpresaIpSegurancaIdioma e fuso horário da clínica

Mapa de campos

CampoTipoBancoObservação
idintPrescricao.IdPrescricao
prescriptionCodestringPrescricao.Identificacao
locationstringPrescricao.IdAgenda->Agenda.IdUAtendimento->UnidadeAtendimento.Descricao + Agenda.IdChRecurso->Chave.DescricaoIdUAtendimento pode ser NULL
startTimehoráriose Situacao=‘V’, Agenda.DhAtendimentoIniUTC(no fuso da clíncia) senão Agenda.DhAgendaIniUTC(no fuso da clínica)só horário, convertido para o fuso e idioma da clínica
statusstringcalculadovide ProcedureStatus()
progressint(Now()-Agenda.DhAtendimentoIniUTC(no fuso do servidor))/Agenda.Tempo*100
minebooleanPrescricao.IdChProfissionalMed={IdChProfissional do médico logado}
patient.idintPrescricao.IdPaciente
patient.prefferedNamestringPaciente.NomeSocialse existir, usar este como nome principal
patient.legalNamestringPaciente.Nomese NomeSocial não existir, usar este como nome
patient.photourlPacienteFoto.NomeArquivo, busca IdPaciente e Padrao = ‘S’, se multiplos, retorna o mais recenteurl gerada pelo MinIO
tagsarray de stringmesma origem de appointments.tags, ver Seção 4.1 (Paciente.PacienteVip + ProgramaApoioPaciente/ProgramaApoio)

Funções de cálculo

ProcedureStatus() — calcula o status do procedimento a partir dos campos da Agenda:

Status retornadoCondição
scheduled (Agendado)Agenda.Situacao = ‘A’ AND DhChegadaUTC IS NULL
waiting (Aguardando recepção)Agenda.Situacao = ‘A’ AND DhChegadaUTC IS NOT NULL
checked (Recepcionado)Agenda.Situacao = ‘V’ AND DhAtendimentoIniUTC IS NULL
preparation (Preparo)Agenda.Situacao = ‘V’ AND DhAtendimentoIniUTC IS NOT NULL AND DhInfusaoIniUTC IS NULL
administering (Em administração)Agenda.Situacao = ‘V’ AND DhInfusaoIniUTC IS NOT NULL AND DhInfusaoFimUTC IS NULL
administered (Completo)Agenda.Situacao = ‘V’ AND DhInfusaoFimUTC IS NOT NULL AND DhAtendimentoFim IS NULL
finished (Finalizado)Agenda.Situacao = ‘V’ AND DhAtendimentoFimUTC IS NOT NULL
canceled (Cancelado)Agenda.Situacao IN (‘C’,‘D’,‘F’,‘I’,‘M’,‘O’,‘T’)

Domínios

TipoAgenda (domínio de Agenda.TipoAgenda) na tabela Indicadores:

ValorSignificado
CConsulta
QQuimioterapia
RRadioterapia
SReserva de sala para assuntos não assistenciais

SituacaoAgenda (domínio de Agenda.Situacao) na tabela Indicadores:

ValorSignificado
AAberta
VConfirmada (check-in realizado)
CCancelada pelo usuário
DCancelada pelo paciente
MCancelada pelo médico
FFalta
ICancelado por internação
OCancelada por óbito
TTransferido (cancelado)

Infraestrutura de apoio

MinIO (Storage de fotos):

  • Bucket global: gemed
  • Bucket por ambiente do cliente: nome = banco de dados do cliente
  • 1 bucket por banco de dados (cliente pode ter múltiplos bancos)
  • Pasta de fotos: FotosPacientes/ dentro do bucket do cliente
  • Seleção da foto: PacienteFoto.Padrao = 'S'; se múltiplas, selecionar a mais recente (futuro: vamos usar o campo CriadoEm da infraestrutura)

Internacionalização (i18n):

  • Idioma da clínica: ClienteEmpresa.IdiomaOficial (IpSeguranca), o termo segue padrão BCP 47
  • Fuso horário da clínica: ClienteEmpresa.FusoOficial (IpSeguranca)
  • Traduções: tabela TermoTraducao (IpTerminologia) usa chave composta por (Termo, Origem, Idioma)
    • Origem: nome da tabela de origem ou Indicadores|<NomeIndicador> quando o domínio está na tabela Indicadores
    • Idioma: Idioma do cliente
    • Termo: o termo usado como chave na tabela de origem

Filtros do endpoint

  • Prescricao.IdAgenda <> NULL
  • Agenda.TipoAgenda IN 'Q', 'R' - Agendas de quimio, radio
  • Agenda.DhAgendaIniUTC(no fuso da clínica) = Hoje(no fuso da clinica) — apenas procedimentos do dia atual
  • Toggle “Meus”: Prescricao.IdChProfissionalMed={IdChProfissional do médico logado}
  • Toggle “Todos”: sem restrições

4.4 Endpoint GET /api/v1/cockpit/doctor/kpis/procedures-today

GET] /api/v1/cockpit/doctor/kpis/procedures-today { "total": 8, "inProgress": 2, "waiting": 4, "scheduled": 2 } Função: Retornar o indicador de Procedimentos Hoje

Tabelas envolvidas

TabelaBancoFunção no endpoint
AgendaGescomClienteAlfaTabela principal — dados da agenda
PacienteGescomClienteAlfaDados do paciente (nome, nome social)
PacienteFotoGescomClienteAlfaFoto do paciente
PrescricaoGescomClienteAlfaDiagnóstico oncológico do paciente
TermoTraducaoIpTerminologiaTradução do modo de atendimento
ClienteEmpresaIpSegurancaIdioma e fuso horário da clínica

Mapa de campos

CampoTipoBanco
totalintcount(Agenda.Situacao IN (‘A’, ‘V’))
inProgressintcount(ProcedureStatus()=administering)
waitingintcount(ProcedureStatus()=waiting OR checked OR preparation)
scheduledintcount(ProcedureStatus()=scheduled)

Funções de cálculo

ProcedureStatus() — calcula o status do procedimento a partir dos campos da Agenda:

Status retornadoCondição
scheduled (Agendado)Agenda.Situacao = ‘A’ AND DhChegadaUTC IS NULL
waiting (Aguardando recepção)Agenda.Situacao = ‘A’ AND DhChegadaUTC IS NOT NULL
checked (Recepcionado)Agenda.Situacao = ‘V’ AND DhAtendimentoIniUTC IS NULL
preparation (Preparo)Agenda.Situacao = ‘V’ AND DhAtendimentoIniUTC IS NOT NULL AND DhInfusaoIniUTC IS NULL
administering (Em administração)Agenda.Situacao = ‘V’ AND DhInfusaoIniUTC IS NOT NULL AND DhInfusaoFimUTC IS NULL
administered (Completo)Agenda.Situacao = ‘V’ AND DhInfusaoFimUTC IS NOT NULL AND DhAtendimentoFim IS NULL
completed (Finalizado)Agenda.Situacao = ‘V’ AND DhAtendimentoFimUTC IS NOT NULL
canceled (Cancelado)Agenda.Situacao IN (‘C’,‘D’,‘F’,‘I’,‘M’,‘O’,‘T’)

Domínios

TipoAgenda (domínio de Agenda.TipoAgenda) na tabela Indicadores:

ValorSignificado
CConsulta
QQuimioterapia
RRadioterapia
SReserva de sala para assuntos não assistenciais

SituacaoAgenda (domínio de Agenda.Situacao) na tabela Indicadores:

ValorSignificado
AAberta
VConfirmada (check-in realizado)
CCancelada pelo usuário
DCancelada pelo paciente
MCancelada pelo médico
FFalta
ICancelado por internação
OCancelada por óbito
TTransferido (cancelado)

Infraestrutura de apoio

Internacionalização (i18n):

  • Idioma da clínica: ClienteEmpresa.IdiomaOficial (IpSeguranca), o termo segue padrão BCP 47
  • Fuso horário da clínica: ClienteEmpresa.FusoOficial (IpSeguranca)
  • Traduções: tabela TermoTraducao (IpTerminologia) usa chave composta por (Termo, Origem, Idioma)
    • Origem: nome da tabela de origem ou Indicadores|<NomeIndicador> quando o domínio está na tabela Indicadores
    • Idioma: Idioma do cliente
    • Termo: o termo usado como chave na tabela de origem

Filtros do endpoint

  • Agenda.TipoAgenda IN 'Q', 'R' - Agendas de quimio, radio
  • Agenda.DhAgendaIniUTC(no fuso da clínica) = Hoje(no fuso da clinica) — apenas procedimentos do dia atual
  • `Prescricao.IdChProfissionalMed={IdChProfissional do médico logado} - só os meus pacientes

4.5 Endpoint [GET] /api/v1/cockpit/doctor/kpis/in-treatment

/api/v1/cockpit/doctor/kpis/in-treatment
`{  "inTreatment": 43, 
    "nonAdherent": 2 }`

Função: Retornar o indicador de Em Tratamento

Tabelas envolvidas

TabelaBancoFunção no endpoint
AgendaGescomClienteAlfaTabela principal — dados da agenda
PacienteGescomClienteAlfaDados do paciente (nome, nome social)
PrescricaoGescomClienteAlfaDiagnóstico oncológico do paciente
TermoTraducaoIpTerminologiaTradução do modo de atendimento

Mapa de campos

CampoTipoBanco
inTreatmentintPatientInTreatmentCount()
nonAdherentintTreatmentPlanAdherenceCount()

Funções de cálculo

PatientInTreatmentCount() — calcula a quantidade de pacientes em tratamento do médico

  • refere-se aos pacientes com agenda realizada há menos de 6 meses e/ou com prescrições realizadas há menos de 6 meses)
  • esses 6 meses referem-se a um parâmetro da clínica que diz qual o tempo máximo de inatividade para considerar o paciente inativo:
    • quanto às agendas: IpParametro.TempoPacienteAtivoAgenda -> IpParametroChave.Valor
    • quanto às prescrições: IpParametroTempoPacienteAtivoPrescricao -> IpParametroChave.Valor
  • Nas agendas obter as agendas com:
    • Situação ‘V’
    • DhAgendaIniUTC > Hoje()-IpParametroChave.Valor (onde IpParametro=TempoPacienteAtivoAgenda)
  • Nas prescrições obter as prescrições com:
    • Situação <> ‘C’ (canceladas)
    • Data > Hoje()-IpParametroChave.Valor (onde IpParametro=TempoPacienteAtivoPrescricao)
  • A query fica mais ou menos assim: SELECT DISTINCT p.IdChProfissional, p.IdPaciente FROM paciente p INNER JOIN agenda a ON a.IdPaciente = p.IdPaciente AND a.IdChRecurso = p.IdChProfissional WHERE a.Situacao = 'V' AND a.DhAgendaIniUTC > dateadd(day,-180, getdate()) -- há 6 meses UNION SELECT DISTINCT p.IdChProfissional , p.IdPaciente FROM Paciente p INNER JOIN Prescricao p2 on p2.IdPaciente = p.IdPaciente AND p.IdChProfissional = p2.IdChProfissionalMed WHERE p2.Situacao <> 'C' AND p2.[Data] > dateadd(day,-180, getdate()) -- há 6 meses Então conta a quantidade de pacientes do profissional logado.

TreatmentPlanAdherenceCount() — calcula os pacientes com plano terapêutico (PEPProjetoTerapeutico) que estão em descompasso com o planejado; quem não tem plano terapêutico não entra na contagem. Um paciente conta como não aderente quando QUALQUER UMA das três condições abaixo é verdadeira (lógica OU — confirmado com o solicitante: basta uma delas estar fora do parametrizado) para algum PEPProjetoTerapeuticoProtocolo do seu plano que tenha IdPrescricao:

  • A data do C1D1 realizado difere da data prevista em mais de Protocolo.ToleranciaDiasAdesao dias [PROPOSTA]
  • A prescrição passada não foi realizada (Prescricao.Situacao IN (‘P’,‘G’,‘A’,‘C’))
  • O intervalo entre sessões da prescrição diverge do intervalo programado no protocolo (Prescricao.Sessao = Prescricao.Data - Prescricao.Data_da_prescrição_anterior, comparado a Protocolo.IntervaloCiclosEmDias — já existe no schema — com a mesma tolerância Protocolo.ToleranciaDiasAdesao acima)

[PROPOSTA] Coluna nova em Protocolo (GescomClienteAlfa): ToleranciaDiasAdesao (int, dias de tolerância para desvio de datas previstas — reaproveitada tanto para o C1D1 quanto para o intervalo entre sessões). Não existe hoje no EsquemaGemed21.csv — confirmado com o solicitante que os valores de tolerância são parâmetros do protocolo, ainda não modelados na tabela Protocolo; a criar antes da implementação deste KPI.

Filtros do endpoint

  • Paciente.IdChProfissional={IdChProfissional do médico logado} - Pacientes em que o médico é o médico assistente

4.6 Endpoint: GET /api/v1/cockpit/doctor/kpis/prescription-alerts

Retorna o indicador de Alertas de Prescrição (urgentes, a revisar, a assinar nos próximos 7 dias).

Tabelas envolvidas

TabelaBancoFunção no endpoint
PrescricaoGescomClienteAlfaTabela principal — versão ativa (Situacao <> 'C'), médico prescritor
PrescricaoAssinaturaGescomClienteAlfaHistórico de assinaturas/revisões — usada para determinar se a prescrição está revisada
AgendaGescomClienteAlfaData/hora agendada da aplicação (via Prescricao.IdAgenda)

Mapa de campos

CampoTipoBancoObservação
urgentintPrescriptionUrgentCount()
toReviewintPrescriptionToReviewCount()
toSignNext7DaysintPrescriptionToSignNext7DaysCount()

Funções de cálculo

PrescriptionToReviewCount() — conta as prescrições “a revisar” do médico logado (RN-CM-020), restritas a prescrições em que o médico logado é o prescritor ou o médico assistente do paciente. Reaproveita PrescricaoAssinatura: um registro com TipoAssinatura = 'A' é a assinatura original do médico; um registro com TipoAssinatura = 'R' é uma confirmação de revisão. Qualquer um dos dois, se teve Data dentro dos últimos 7 dias, satisfaz o requisito — não é necessária uma tabela nova. Para “está assinada”, verifica tanto PrescricaoAssinatura quanto o campo legado Prescricao.IdChProfissionalAssinou, por compatibilidade com prescrições gravadas antes da adoção da tabela de assinaturas.

A janela que dispara “a revisar” (RN-CM-020) — descrita na Seção 1 como “1 dia (24h) antes da aplicação” — não é um valor fixo no código: é um parâmetro configurável por clínica, mesmo padrão já usado em 4.5 (TempoPacienteAtivoAgenda/TempoPacienteAtivoPrescricao): IpParametro.PrescricaoTempoRevisaoIpParametroChave.Valor (horas). Ver “Parâmetro de configuração — PrescricaoTempoRevisao” logo abaixo para a definição completa das duas linhas de banco necessárias.

SELECT COUNT(*)
FROM Prescricao p
INNER JOIN Agenda a ON a.IdAgenda = p.IdAgenda
WHERE p.Situacao <> 'C'                                          -- apenas a versão ativa
  AND (
        EXISTS (SELECT 1 FROM PrescricaoAssinatura pa
                WHERE pa.IdPrescricao = p.IdPrescricao AND pa.TipoAssinatura = 'A')
        OR p.IdChProfissionalAssinou IS NOT NULL                 -- compatibilidade com legado
      )                                                          -- já assinada, por um dos dois caminhos
  AND a.DhAgendaIniUTC <= DATEADD(HOUR,
        COALESCE(
          (SELECT ipc.Valor FROM IpParametroChave ipc
           WHERE ipc.IdParametro = 'PrescricaoTempoRevisao' AND ipc.IdChave = {IdClinica}),
          24),                                                   -- default 24h se IpParametro/IpParametroChave não existir (confirmado pelo solicitante)
        SYSDATETIMEOFFSET())                                     -- a X horas ou menos da aplicação, X = parâmetro da clínica
  AND NOT EXISTS (
        SELECT 1 FROM PrescricaoAssinatura pa2
        WHERE pa2.IdPrescricao = p.IdPrescricao
          AND pa2.TipoAssinatura IN ('A','R')
          AND pa2.Data > DATEADD(DAY, -7, SYSDATETIMEOFFSET())    -- assinatura/revisão válida por 7 dias
      )
  AND (p.IdChProfissionalMed = {IdChProfissional do médico logado}
       OR EXISTS (SELECT 1 FROM Paciente pac WHERE pac.IdPaciente = p.IdPaciente
                  AND pac.IdChProfissional = {IdChProfissional do médico logado}))

Nota: a cláusula de escopo acima é fechada (só prescritor OU assistente) — o KPI é uma contagem pessoal de “quanto precisa da sua atenção”, diferente do toggle “Todos” do painel (Seção 4.7), que deliberadamente amplia para qualquer médico da clínica porque ali o médico está decidindo ajudar a revisar colegas. Não existe (nem deveria existir) uma permissão RBAC de “revisor geral” que amplie o KPI — isso inflaria a contagem pessoal com prescrições de pacientes sem nenhum vínculo com o médico logado.

Parâmetro de configuração — PrescricaoTempoRevisao

[PROPOSTA — pedido pelo solicitante nesta versão] A janela de disparo de “a revisar” precisa existir como parâmetro real de banco, não só como texto de regra de negócio. Não é uma tabela nova — IpParametro/IpParametroChave já existem e já hospedam parâmetros do mesmo tipo (ver 4.5). São 2 linhas novas de dado (seed), não uma mudança de schema:

IpParametro (linha nova):

CampoValor
IdParametroPrescricaoTempoRevisao
DescricaoDefine o tempo em horas antes da aplicação para uma prescrição ficar em estado de "pendente de revisão"
DominioNULL
UsuarioControlaS
TipoN

IpParametroChave (linha nova, valor por clínica — exemplo com o padrão-sugerido de 24h, correspondente à regra “1 dia” da Seção 1):

CampoValor
IdParametroPrescricaoTempoRevisao
IdChave{Id da Clínica}
Valor24
IdChave2NULL

Comportamento se o parâmetro não existir: se a linha em IpParametro ou em IpParametroChave não existir para a clínica, o sistema assume 24h como default (confirmado pelo solicitante) — ver COALESCE na query acima. O seed abaixo (Seção “Seeds da Funcionalidade”) deve ainda assim ser aplicado em todo cliente, para que o valor fique explícito e configurável desde o início, em vez de depender do default implícito do código.

Atenção Dev/DevOps: este parâmetro é um dado novo de configuração, não uma migration de schema — precisa ser adicionado à documentação de deploy/seed de cada cliente (mesma lista onde já constam TempoPacienteAtivoAgenda/TempoPacienteAtivoPrescricao). Ver a subseção “Seeds da Funcionalidade”, ao final desta Seção 4, para a lista consolidada de todos os seeds necessários para este documento.

PrescriptionUrgentCount() — soma duas contagens, ambas restritas ao médico logado (prescritor ou assistente) e filtradas por hoursRemaining < 12 (RN-CM-011): (a) PrescriptionToReviewCount() restrita a hoursRemaining < 12; (b) prescrições pendentes de assinatura do médico logado (Prescricao.IdChProfissionalMed = {médico logado}, sem PrescricaoAssinatura.TipoAssinatura = 'A' E Prescricao.IdChProfissionalAssinou IS NULL) com hoursRemaining < 12. hoursRemaining = DATEDIFF(MINUTE, SYSDATETIMEOFFSET(), a.DhAgendaIniUTC) / 60.0.

PrescriptionToSignNext7DaysCount() — prescrições com Prescricao.Situacao <> 'C', Prescricao.IdChProfissionalMed = {IdChProfissional do médico logado} (só o próprio prescritor assina, RN-CM-012 — não há equivalente de “assistente” aqui), sem PrescricaoAssinatura.TipoAssinatura = 'A' E sem Prescricao.IdChProfissionalAssinou preenchido (compatibilidade com legado), e Agenda.DhAgendaIniUTC entre agora e +7 dias.

Filtros do endpoint

  • Escopo do médico logado, fechado nas 3 métricas: prescritor (Prescricao.IdChProfissionalMed) OU médico assistente do paciente (Paciente.IdChProfissional) para toReview e a parcela de revisão de urgent; apenas prescritor para toSignNext7Days e a parcela de assinatura de urgent. O KPI nunca inclui prescrições de outros médicos sem esse vínculo — ver nota acima sobre a diferença em relação ao toggle “Todos” do painel (Seção 4.7).

4.7 Endpoint: GET /api/v1/cockpit/doctor/prescriptions

Retorna a lista de prescrições pendentes (assinatura e revisão) do médico logado, para o painel e para a tela dedicada.

Tabelas envolvidas

TabelaBancoFunção no endpoint
PrescricaoGescomClienteAlfaTabela principal — versão ativa (Situacao <> 'C'); Identificacao já traz protocolo + ciclo/sessão formatados
PrescricaoAssinaturaGescomClienteAlfaDetermina se a prescrição está assinada e/ou revisada (ver 4.6)
PacienteGescomClienteAlfaNome social/civil do paciente e médico assistente
AgendaGescomClienteAlfaData/hora agendada da aplicação

Domínio — PrescricaoAssinatura.TipoAssinatura

ValorSignificado
AAssinatura do médico (assinatura original da prescrição ou de uma nova versão gerada por edição)
RConfirmação de revisão sem alteração da prescrição (“Marcar como Revisada”, RN-CM-020)

Nota: o esquema também sugere os tipos F (farmácia) e outros, usados por outras funcionalidades fora do escopo do Cockpit — não detalhados aqui.

Mapa de campos

CampoTipoBancoObservação
iduuidPrescricao.IdPrescricaoidentifica diretamente a versão ativa — não há campo de número de versão a considerar à parte
patient.iduuidPrescricao.IdPaciente
patient.preferredNamestringPaciente.NomeSocialmesmo padrão de appointments (4.1) e procedures (4.3) — enviado sempre, mesmo vazio, para o front sinalizar nome social ao médico
patient.legalNamestringPaciente.Nomeenviado sempre, junto com preferredName
prescriptionCodestringPrescricao.Identificacaosubstitui os antigos protocol/cycle — já vem formatado do banco (ex: “CARBO-TAXOL C3D1”), sem necessidade de montar a string a partir de Protocolo/PrescricaoProtocolo
scheduleDatedatetimeAgenda.DhAgendaIniUTC, via Prescricao.IdAgendaconvertida para o fuso da clínica na exibição
hoursRemainingintcalculado: Agenda.DhAgendaIniUTC - Now() em horas
typestringcalculadoto_sign se não existe PrescricaoAssinatura.TipoAssinatura = 'A' E Prescricao.IdChProfissionalAssinou IS NULL (checagem dupla por compatibilidade com legado, ver 4.6); to_review se assinada por qualquer um dos dois caminhos, mas nenhum registro A/R com Data nos últimos 7 dias (ver PrescriptionToReviewCount, 4.6)
isPreferredReviewerboolcalculadotrue se médico logado = Prescricao.IdChProfissionalMed OU = Paciente.IdChProfissional; presente somente quando type = to_review. Os campos prescriberName/attendingDoctorName cogitados antes foram removidos — o booleano basta para o front

Filtros do endpoint

  • type = to_sign: (não existe PrescricaoAssinatura.TipoAssinatura = 'A' E Prescricao.IdChProfissionalAssinou IS NULL) AND Prescricao.IdChProfissionalMed = médico logado AND Agenda.DhAgendaIniUTC até 7 dias a partir de agora — nunca afetado por reviewScope. O corte de 7 dias evita inflar a lista com prescrições distantes no tempo, sem relevância imediata para o médico.
  • type = to_review: condição temporal e de assinatura de PrescriptionToReviewCount() (Seção 4.6) — i.e., Situacao <> 'C', assinada (por qualquer um dos dois caminhos), dentro da janela de IpParametro.PrescricaoTempoRevisao (parâmetro por clínica, ver 4.6 — não mais um “D-1” fixo), sem assinatura/revisão válida nos últimos 7 dias — mas com a condição de escopo de médico da 4.6 substituída pelo reviewScope abaixo (a 4.6 é sempre “mine” porque é uma contagem pessoal do KPI; o painel de prescrições permite alternar):
    • reviewScope = mine (default): adiciona (Prescricao.IdChProfissionalMed = {médico logado} OR Paciente.IdChProfissional = {médico logado})
    • reviewScope = all: sem restrição adicional de médico — todas as prescrições a revisar da clínica
  • Sem parâmetro type: união das duas categorias, ordenada por hoursRemaining ascendente (RN-CM-011); reviewScope aplicado apenas à parte to_review da união, conforme acima
  • Prescricao.Situacao <> 'C' em ambos os casos — como há no máximo 1 prescrição ativa por cadeia de versões, este filtro já garante que apenas a versão vigente apareça na lista, sem risco de duplicidade

Nota: os endpoints de ação de prescrições (GET /prescriptions/{id}, POST /sign, PATCH /review, PUT /prescriptions/{id}) pertencem a um documento de processo de Prescrições à parte, fora do escopo deste documento. RN-CM-020 continua na Seção 2 porque alimenta o KPI/painel deste Cockpit (Seções 4.6/4.7). O esquema já suporta assinatura/revisão via PrescricaoAssinatura.TipoAssinatura (A/R) e versionamento via PrescricaoVersao, sem necessidade de tabela nova.

4.8 Endpoint: GET /api/v1/cockpit/doctor/conversations

Retorna as conversas não finalizadas do médico logado — lidas e não lidas (painel compacto do Cockpit — ver escopo em RN-CM-015 e Seção 2.5), com base no modelo de Conversas e Alertas (IP.Mensageria). O schema desse domínio (GescomClienteAlfa.mensageria) passou a ter DDL real na Biblioteca de Schema (DDL) do projeto (GescomMensageria.sql) a partir de 28/08/2026 — antes disso, o mapeamento abaixo era baseado só na descrição do documento externo “Conversas-e-Alertas”, sem o DDL para conferir nomes e tipos de campo exatos. Esta versão corrige os campos que o DDL real revelou estarem descritos incorretamente (ver “Resolução do nome do autor” abaixo e o changelog desta versão). Diferente das demais tabelas mapeadas neste documento, as tabelas de mensageria abaixo pertencem ao mesmo banco operacional do cliente (GescomClienteAlfa), mas são de um schema separado (mensageria), não do schema dbo assistencial.

Tabelas envolvidas

TabelaBancoFunção no endpoint
ConversaGescomClienteAlfaTabela principal — thread, status, prazo, origem, paciente relacionado
ConversaDestinatarioGescomClienteAlfaSnapshot de quem recebeu a conversa — usada para filtrar pelo médico logado
ConversaLeituraGescomClienteAlfaDetermina se a conversa está lida para o médico logado
MensagemGescomClienteAlfaConteúdo e autor da última mensagem da thread (preview do card)
EquipeGescomClienteAlfaNome de exibição da equipe (Nome) — usado no sufixo “(Equipe)” do autor quando aplicável (ver “Resolução do nome da equipe” abaixo)
EquipeMembroGescomClienteAlfaDetermina se o autor da mensagem é membro da equipe destino da conversa (Conversa.EquipeId) — decide se o sufixo de equipe aparece
SegUsuarioGescomClienteAlfaPonte legada entre o identificador local (int) e o GUID do IPSeguranca (ver resolução de nome abaixo)
PacienteGescomClienteAlfaNome social/civil do paciente relacionado, quando Conversa.PacienteId existe

Resolução do nome do autor (corrigida nesta versão — DDL real de mensageria disponibilizado em 28/08/2026): Mensagem.IdUsuarioAutor, Conversa.IdUsuarioRemetente, Conversa.IdUsuarioDestino, ConversaDestinatario.IdUsuario e EquipeMembro.IdUsuario são todos int, não GUID — o mesmo tipo de identificador legado local já usado em Profissional.IdUsuario/Prescricao.IdUsuarioAssinatura. Versões anteriores deste documento (v4.14 a v4.23) assumiam, sem o DDL real da mensageria disponível, que esses campos já armazenavam o GUID de IPSeguranca.dbo.Usuario.Id — suposição que o DDL real desmente. A triangulação correta é: IdUsuarioAutor (int) = SegUsuario.IdUsuario (smallint, PK — join dentro do próprio GescomClienteAlfa) → SegUsuario.SegurancaUsuarioId (GUID; nome de campo conforme “Log de Mudanças Estruturais do Banco de Dados”, que prevalece sobre a Biblioteca de Schema (DDL) para este campo específico) → nome de exibição em IPSeguranca.dbo.Usuario.Apelido (mesmo GUID). A mesma triangulação vale para IdUsuarioRemetente, IdUsuarioDestino e ConversaDestinatario.IdUsuario.

Resolução do nome da equipe (nova nesta versão): o autor de uma mensagem ganha o sufixo da equipe quando Conversa.DestinoTipo = 'Team' E existe uma linha em EquipeMembro com EquipeId = Conversa.EquipeId e IdUsuario igual ao SegUsuario.IdUsuario do autor resolvido acima. Quando as duas condições são verdadeiras, o nome de exibição final é Usuario.Apelido + ” (” + Equipe.Nome + ”)” (ex.: “Sandra (Farmácia)”); caso contrário, é só Usuario.Apelido. [PROPOSTA — a confirmar com o solicitante]: esta verificação usa o vínculo atual de EquipeMembro (RemovidoEmUtc IS NULL) no momento em que o card/thread é exibido, não o vínculo no momento em que a mensagem foi enviada — EquipeMembro não guarda um snapshot por mensagem, então alguém que já saiu da equipe deixaria de ter o sufixo em mensagens antigas dele. Alternativa não implementada aqui: checar AdicionadoEmUtc <= Mensagem.CriadoEmUtc AND (RemovidoEmUtc IS NULL OR RemovidoEmUtc > Mensagem.CriadoEmUtc) para refletir o vínculo histórico da época do envio. A escolha entre as duas abordagens fica pendente de confirmação.

O ícone continua binário: bell (Lucide) para OrigemTipo = 'System', ícone genérico de pessoa para OrigemTipo = 'User', sem variação por equipe (recepção/farmácia/enfermagem) — a identificação da equipe, quando aplicável, é resolvida como texto (acima), não como ícone. Diferente do que versões anteriores deste documento afirmavam, a tabela Equipe (e EquipeMembro) é necessária neste endpoint — não apenas no backend de roteamento — porque a exibição do sufixo “(Equipe)” no authorName depende dela (ver “Resolução do nome da equipe” acima).

Mapa de campos

CampoTipoBancoObservação
iduuidConversa.Id
sourceTypestringcalculado a partir de Conversa.OrigemTiposystem se sistema; person se usuario
authorNamestringIPSeguranca.dbo.Usuario.Apelido do autor da mensagem de maior Sequencia, via SegUsuario (ver “Resolução do nome do autor” acima); com sufixo " (" + Equipe.Nome + ")" quando Conversa.DestinoTipo = 'Team' e o autor é membro dessa Equipe (ver “Resolução do nome da equipe” acima); ou “Sistema” quando sourceType = system
lastMessagestringMensagem.Conteudo (maior Sequencia da Conversa)
lastMessageAtdatetimeMensagem.CriadoEmUtc (mesma linha)
deadlinedatetimeConversa.PrazoEmUtcpode ser nulo
statusstringConversa.Statusmapeado para sent/read/replied (ver 2.9)
unreadboolcalculado: Conversa.UltimaSequencia > ConversaLeitura.UltimaSequenciaLida (ou sem ConversaLeitura)usado para destaque visual e camada de prioridade (RN-CM-015); não filtra o resultado
patientobjectnullPaciente, via Conversa.PacienteId

Filtros do endpoint

  • ConversaDestinatario.IdUsuario = {médico logado} — recebida diretamente ou via snapshot de equipe (EquipeOrigemId)
  • Conversa.IdEmpresa = {filial da sessão validada} — nunca escolhido livremente pelo cliente da API (conforme fronteira de responsabilidade do IPSeguranca)
  • Conversa.Status IN ('Sent', 'Read', 'Responded') — exclui 'Resolved' e 'Dismissed'
  • Conversa.UltimaSequencia > ConversaLeitura.UltimaSequenciaLida, OU não existe ConversaLeitura para o médico logado — calcula o campo unread, usado como critério de ordenação (não filtra o WHERE).
  • Ordenação: unread descendente (não lidas primeiro), depois Conversa.PrazoEmUtc ascendente (nulos por último), depois lastMessageAt descendente — RN-CM-015

4.9 Endpoints de ação: GET /conversations/{id}, POST /read, POST /reply, PATCH /resolve, PATCH /discard

Tabelas envolvidas

TabelaBancoFunção no endpoint
ConversaGescomClienteAlfaStatus atual, UltimaSequencia
MensagemGescomClienteAlfaThread completa (GET detalhe); nova linha inserida em POST /reply
ConversaLeituraGescomClienteAlfaAtualizada em POST /read
ConversaAcaoGescomClienteAlfaHistórico append-only — nova linha em toda ação (leitura, resposta, resolução, descarte)
OutboxEventoGescomClienteAlfaEvento assíncrono gravado na mesma transação de qualquer mudança de estado (fora do escopo deste front, mencionado por completude)

Efeitos em BD por endpoint de ação

  • GET /conversations/{id}: somente leitura — retorna todas as Mensagem da conversa ordenadas por Sequencia, mais os dados de Conversa (status, prazo, paciente). Para cada mensagem, resolve o sufixo de equipe do autor do mesmo jeito que o endpoint de lista (Seção 4.8, “Resolução do nome da equipe”) — a thread completa também mostra “Sandra (Farmácia)” quando aplicável, não só o card compacto.
  • POST /read: insere ou atualiza ConversaLeitura (chave ConversaId + IdUsuario) com UltimaSequenciaLida = Conversa.UltimaSequencia; insere uma linha em ConversaAcao (Tipo = Read); se Conversa.Status = 'Sent', atualiza para 'Read' — nunca regride um status já mais avançado ('Responded' permanece 'Responded').
  • POST /reply: insere uma nova linha em Mensagem (Sequencia = Conversa.UltimaSequencia + 1, IdUsuarioAutor = médico logado, Conteudo do request, Tipo = 'Response'); atualiza Conversa.UltimaSequencia; atualiza Conversa.Status para 'Responded'; insere uma linha em ConversaAcao (Tipo = 'Response'; MensagemId da nova mensagem); grava OutboxEvento (TipoEvento=ConversaRespondida). O valor 'Reply', antes um segundo valor válido para Mensagem.Tipo/ConversaAcao.Tipo no mesmo CHECK, foi abolido pelo solicitante — 'Response' é o único valor usado para a ação de responder, resolvendo a pendência [A DEFINIR] da v4.24 (ver Log de Mudanças Estruturais do Banco de Dados).
  • PATCH /resolve: atualiza Conversa.Status para 'Resolved'; insere uma linha em ConversaAcao (Tipo = 'Resolve'); grava OutboxEvento (TipoEvento=ConversaResolvida). Não altera nem exclui Mensagem.
  • PATCH /discard: atualiza Conversa.Status para 'Dismissed'; insere uma linha em ConversaAcao (Tipo = 'Dismiss'); grava OutboxEvento (TipoEvento=ConversaDescartada). Mesma observação — nada é excluído fisicamente.

Fora do escopo deste documento

A criação de conversas (envio inicial por um usuário) e a publicação de alertas automáticos (AlertaPublicacao, com chave de idempotência) partem de outros módulos ou telas — o Cockpit é consumidor/participante das conversas, não o ponto de origem. O cadastro e a gestão de equipes (criar/renomear/desativar uma Equipe, adicionar ou remover membros em EquipeMembro) também partem de outro módulo — o Cockpit só Equipe/EquipeMembro para resolver o sufixo do nome do autor (Seção 4.8), nunca escreve nelas. O processamento assíncrono via OutboxEvento pertence ao domínio do IP.Mensageria e também não é especificado aqui.


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

Retorna pacientes que casam com o termo digitado no campo de busca do cabeçalho (RN-CM-004). A correspondência aproximada (pesos de proximidade fonológica e semântica) usa um mecanismo já existente no sistema, fora do escopo desta especificação — este mapeamento cobre apenas os campos de busca direta e de resposta que esse motor já existente consome/retorna.

Tabelas envolvidas

TabelaBancoFunção no endpoint
PacienteGescomClienteAlfaTabela única consultada — todos os campos de busca e resposta vêm dela

Mapa de campos

CampoTipoBancoObservação
idintPaciente.IdPaciente
namestringPaciente.Nomesegue o mesmo padrão de preferredName/legalName dos demais endpoints quando Paciente.NomeSocial existir
medicalRecordNumberstringPaciente.NumProntuario
gendercharPaciente.Sexodomínio ‘M’/‘F’
birthDatedataPaciente.Nascimentocampo de busca quando a entrada começa com dígito (RN-CM-004)
motherNamestringPaciente.NomeMaecampo de busca quando a entrada começa com letra (RN-CM-004)
cpfstringPaciente.CPFcampo de busca quando a entrada começa com dígito (RN-CM-004)

Filtros do endpoint

  • Sem filtro por médico logado — diferente dos demais painéis do Cockpit, a busca do cabeçalho não é restrita aos pacientes do médico, pois ele pode precisar localizar qualquer paciente da clínica.
  • Mínimo de 2 caracteres (RN-CM-004) antes de disparar a busca.

Nota sobre o motor de correspondência aproximada

O EsquemaGemed21.csv não tem uma coluna dedicada de correspondência fonética/semântica em Paciente — o motor de busca aproximada citado em RN-CM-004 já existe e está em produção fora deste documento; presume-se que ele consulta os mesmos campos mapeados acima, mas o algoritmo em si (ranking, tolerância, índice usado) não é redefinido aqui.


Seeds da Funcionalidade

Lista consolidada de todo dado (seed) que precisa existir em produção — não schema novo, mas linhas de dado que este documento pressupõe — para que a funcionalidade se comporte como especificado. Pensada como checklist de deploy para Dev/DevOps: cada linha aponta para a seção com a definição completa dos campos, não a repete (evita duplicar a mesma informação em dois lugares — Lição #10 da Skill Designer).

SeedTabela(s)Por cliente ou global?StatusDetalhe completo
PrescricaoTempoRevisao — janela (em horas) antes da aplicação em que uma prescrição assinada vira “a revisar” (RN-CM-020)IpParametro (1 linha) + IpParametroChave (1 linha por clínica)Por cliente (IpParametroChave); a linha de IpParametro é única, compartilhada entre clientes[PROPOSTA] — pedido pelo solicitante nesta versão, ainda não aplicado em produção. Default de 24h no código se a linha de IpParametroChave (ou a de IpParametro) não existir para a clínica — confirmado pelo solicitante — mas o seed deve ser aplicado mesmo assim, para que o valor fique explícitoSeção 4.6, “Parâmetro de configuração — PrescricaoTempoRevisao”

Nenhum outro seed novo é necessário por este documento — os demais parâmetros citados (TempoPacienteAtivoAgenda, TempoPacienteAtivoPrescricao, Seção 4.5) já existem em produção, não são propostos aqui.


METADADOS FINAIS

  • Prioridade: Alta (Core do Sistema)
  • Complexidade: Média/Alta (Devido às integrações em tempo real)
  • Próximos Passos:
    1. Homologação do serviço de atualização automática.
    2. Teste de carga para múltiplos médicos acessando simultaneamente.
    3. Validação da assinatura digital em ambiente de sandbox.
    4. Definir ícones definitivos para os KPI cards (biblioteca Lucide Icons).
    5. Substituir ícones placeholder de comunicação por SVGs da biblioteca Lucide — apenas 2 ícones (bell para alertas de sistema, ícone de pessoa genérico para conversas com usuário; não há ícone por equipe/farmácia/enfermagem/recepção).
    6. Validar acessibilidade (WCAG, navegação por teclado) dos títulos como links e toggles pill.
    7. Testar usabilidade do título como link com seta no hover com médicos.
    8. Validar touchpoints de workflow com médicos em ambiente real (shadowing).
    9. Mapear touchpoints de workflows ainda não documentados (ex: workflow de alta, workflow de intercorrência).
    10. Especificar os demais itens do menu do usuário: autocadastro/edição de perfil, dados de faturamento e pagamento (conta bancária, PIX) e dados de especialidade (CRM, RQE) — hoje o menu só tem “Sair”.

Histórico de Versões

  • v4.25 (29/08/2026) — Arquivo criado pela divisão do documento único CM_CockPit_do_medico_v4_25.md em 4 arquivos por seção (ver Skill Designer, “Organização Física: Pasta por Funcionalidade”, Lição #18). Conteúdo desta seção sem alteração de substância em relação à v4.25 do documento original — apenas reorganização física. O histórico de revisões anterior a esta divisão (v4.0 a v4.25, incluindo o racional de cada mudança) está preservado integralmente no documento original, arquivado em Histórico/CM_CockPit_do_medico_v4_25 (documento único, antes da divisão em 4 arquivos).md.
  • v4.26 (30/08/2026) — Pedido do solicitante: a janela de “1 dia (24h)” que dispara o estado “a revisar” de uma prescrição (RN-CM-020) precisa existir como parâmetro real de banco, não só como texto de regra de negócio — mesmo padrão já usado para outros parâmetros por clínica neste documento (TempoPacienteAtivoAgenda/TempoPacienteAtivoPrescricao, Seção 4.5). Adicionado, na Seção 4.6: (1) referência ao parâmetro IpParametro.PrescricaoTempoRevisaoIpParametroChave.Valor na query de PrescriptionToReviewCount(), substituindo o DATEADD(HOUR, 24, ...) fixo; (2) nova subseção “Parâmetro de configuração — PrescricaoTempoRevisao” [PROPOSTA], com a definição completa das 2 linhas de dado necessárias (IpParametro: IdParametro='PrescricaoTempoRevisao', Descricao, Dominio=NULL, UsuarioControla='S', Tipo='N'; IpParametroChave: IdParametro='PrescricaoTempoRevisao', IdChave={Id da Clínica}, Valor=24, IdChave2=NULL) e um alerta explícito para Dev/DevOps sobre a necessidade de incluir esse seed na documentação de deploy de cada cliente. Não é uma tabela nova — IpParametro/IpParametroChave já existem. Filtro type = to_review do endpoint 4.7 atualizado para referenciar o mesmo parâmetro em vez de “D-1” fixo.
  • v4.27 (30/08/2026) — Pedido do solicitante, resolvendo o [A DEFINIR] da v4.26: (1) comportamento definido para quando IpParametro/IpParametroChave de PrescricaoTempoRevisao não existir para a clínica — default de 24h, confirmado pelo solicitante — implementado na query de PrescriptionToReviewCount() (Seção 4.6) via COALESCE(..., 24) em vez do SELECT direto; parágrafo “Atenção Dev/DevOps” reescrito para descrever esse comportamento e remover a pendência; (2) nova subseção “Seeds da Funcionalidade” ao final da Seção 4, consolidando em uma tabela todo dado (não schema) que precisa existir em produção para a funcionalidade funcionar como especificado — pedido explícito do solicitante (“seria bom termos uma subseção com os seeds da funcionalidade”). Por ora contém 1 linha (PrescricaoTempoRevisao, [PROPOSTA]), apontando para a Seção 4.6 em vez de repetir a definição (Lição #10).
  • v4.28 (11/09/2026) — Correção pontual do solicitante: o valor de PrescricaoAssinatura.TipoAssinatura para a assinatura do médico está errado em todo o documento — era 'M', o correto é 'A'. Corrigido em todas as ocorrências da Seção 4.6 (prosa e SQL de PrescriptionToReviewCount(), PrescriptionUrgentCount(), PrescriptionToSignNext7DaysCount()) e da Seção 4.7 (tabela de domínio, mapa de campos, filtros do endpoint, nota final). Não é o mesmo valor de PrescricaoAssinaturaEnfermagem.TipoAssinatura = 'E' (tabela distinta, confirmada na Biblioteca de Schema/DDL) — apenas o 'M''A' de PrescricaoAssinatura estava incorreto. Nenhuma outra seção deste conjunto de documentos (01, 02, 03) referenciava esse campo — correção isolada à Seção 4.