DOCUMENTO DE ESPECIFICAÇÃO FUNCIONAL CONSOLIDADO

Central do Médico (Cockpit) — Versão 4.12

24 de agosto de 2026


1. Histórico de Revisões

VersãoDataAutorDescrição
1.021/07/2026Designer de ProtótiposVersão inicial da Definição.
1.122/07/2026Designer de ProtótiposAtualização com busca, KPIs e grid 2×2.
2.022/07/2026Designer de ProtótiposEspecificação completa com histórias e regras.
3.027/07/2026Designer de ProtótiposConsolidação narrativa e técnica; inclusão de SBIS.
3.128/07/2026Analista de SistemasAtualização de regras de busca, assinatura e status.
3.229/07/2026Designer de ProtótiposReestruturação da Seção 2 com descrição funcional detalhada por painel.
3.330/07/2026Designer de ProtótiposCorreções de busca, KPIs, prescrições, comunicação, procedimentos e validações.
3.430/07/2026Designer de ProtótiposCorreções de dependências, avatar, KPI Em Tratamento e navegação.
3.531/07/2026Designer de ProtótiposProtótipo HTML: títulos como links, sem negrito, KPIs com borda colorida, barra de progresso discreta, toggles pill, busca com hint.
3.631/07/2026Designer de ProtótiposKPI Em Tratamento: número principal agora é “em tratamento” (removido conceito de “ativos”).
3.709/08/2026Designer de ProtótiposIncorporação de Análise de Workflow com touchpoints detalhados por workflow.
3.810/08/2026Designer de ProtótiposNarrativa de prescrições, hint no rodapé do dropdown, urgentes incluem revisão, ícone de sistema, mensagens não lidas sem negrito, tabela de i18n.
3.910/08/2026Designer de ProtótiposData da agenda em prescrições, barra de progresso inline, consultas finalizadas esmaecidas em ordem, destaque visual para Recepcionado e Aguardando Recepção, renomeação para Procedimentos na Clínica.
3.1010/08/2026Designer de ProtótiposModal de revisão para assinar e revisar prescrições.
3.1110/08/2026Designer de ProtótiposRestauração completa de conteúdo truncado em 2.1, 2.2 e 2.5.
3.1210/08/2026Designer de ProtótiposMudança de conceito de assinatura e revisão de prescrições, modal para mensagens da Comunicação, Endpoints em inglês.
4.011/08/2026Marcos AraoRetirada do nome do médico do cabeçalho, api de consulta e mapeamento do BD
4.112/08/2026Marcos AraoAjustes de internacionalização
4.212/08/2026Marcos AraoAjustes em Procedimentos na clínica e api de procedimentos e seu mapeamento do BD
4.313/08/2026Marcos AraoAjustes de termos no Estado das agendas
4.413/08/2026Marcos AraoBackend da KPI Em tratamento e Alertas de Prescrição
4.524/08/2026Marcos AraoCorreção de numeração duplicada na Seção 4; renumeração sequencial da Seção 2 (2.9→2.8, 2.10→2.9, 2.11→2.10); incorporação do protótipo HTML funcional v3.12 na Seção 3
4.624/08/2026Marcos AraoCorreção conceitual: “a revisar” passa a ser gatilho automático do sistema (D-1 antes da aplicação agendada), não mais notificação manual de problema pela farmácia/enfermagem. RN-CM-011 atualizada e RN-CM-020 criada. Ajustes propagados em Personas, Workflow 3, Regras de Negócio, Fluxo Principal, Dependências, US-CM-006, KPI de Alertas, painel de Prescrições Pendentes, mensagens de sistema (SYS_PRESC_REVIEW) e dados mockados do protótipo.
4.724/08/2026Marcos AraoEndpoints de Prescrições Pendentes finalizados na Seção 2.9 (kpis/prescription-alerts, prescriptions, GET/{id}, POST sign, novo PATCH review, PUT edição). Mapeamento de BD completo na Seção 4.6-4.8, incluindo tabela nova PrescricaoRevisao para suportar RN-CM-020 (consultado EsquemaGemed21.csv — não havia tabela equivalente no schema atual).
4.824/08/2026Marcos AraoCorreção de modelagem de BD: removida a tabela PrescricaoRevisao. Revisão e assinatura passam a ser tratadas com a tabela já existente PrescricaoAssinatura (TipoAssinatura = ‘M’ assinatura do médico, ‘R’ revisão), com janela de validade de 7 dias. Esclarecido que cada versão da prescrição é um novo registro em Prescricao (apenas 1 ativo por vez, Situacao <> ‘C’) e que editar uma prescrição já assinada gera nova versão que precisa ser assinada novamente — não é mais considerada “auto-revisada”. RN-CM-020, Seções 2.9, 2.4 e 4.6-4.8 atualizadas.
4.924/08/2026Marcos AraoAdicionado toggle “Meus/Todos” ao painel de Prescrições Pendentes (2.4): afeta somente as prescrições a revisar (as a assinar já são sempre do médico logado). Default “Todos”. Novo parâmetro reviewScope no endpoint GET prescriptions (2.9) e no mapeamento de BD (4.7). Protótipo HTML atualizado com o toggle, novo item mockado (meu: false) para demonstrar o filtro, e estado do toggle preservado entre ações.
4.1024/08/2026Marcos AraoCorreção no KPI de Alertas de Prescrição (4.6): removida cláusula especulativa de permissão RBAC “revisor geral” que inflaria a contagem pessoal com prescrições sem vínculo com o médico logado; explicitado que toSignNext7Days também é restrito ao médico prescritor (faltava esse filtro na descrição). O KPI está confirmado como estritamente pessoal (prescritor ou assistente do paciente), sem afetar nem ser afetado pelo toggle “Meus/Todos” do painel.
4.1124/08/2026Marcos AraoDefault do toggle “Meus/Todos” (painel de Prescrições Pendentes) corrigido de “Todos” para “Meus” — e do parâmetro reviewScope de all para mine. Justificativa do touchpoint de workflow revisada: como as prescrições a assinar nunca são afetadas pelo toggle, o argumento anterior para default “Todos” não se sustentava. Corrigido em 2.4 (descrição funcional, critério de aceitação), 2.9, 4.7 e no protótipo HTML (botão ativo, variável de estado, chamada de inicialização).
4.1224/08/2026Marcos AraoAjustes na API de Prescrições Pendentes (GET /prescriptions): campos protocol/cycle substituídos por prescriptionCode (= Prescricao.Identificacao, já formatado); prescriberName/attendingDoctorName removidos (basta isPreferredReviewer); checagem de assinatura agora considera também o campo legado Prescricao.IdChProfissionalAssinou (compatibilidade); type=to_sign passa a filtrar por até 7 dias de antecedência; patient passa a enviar preferredName/legalName (mesmo padrão de appointments/procedures). Removidos desta doc os endpoints de ação sobre prescrição individual (GET detalhe, sign, review, edição) e a Seção 4.8 correspondente — migram para um documento de processo de Prescrições à parte.

SEÇÃO 1 — DEFINIÇÃO

Um dia na Central do Médico

Você chega à clínica para iniciar seu turno. Ao abrir o Gemed Onco, a primeira tela que surge é o seu Cockpit. No topo, quatro indicadores rápidos mostram que você tem 12 consultas hoje, 5 prescrições aguardando sua assinatura e 3 pacientes já em tratamento nas poltronas.

Ao longo da manhã, você não precisa “caçar” informações. Se um paciente chega na recepção, o painel de Consultas atualiza sozinho, mostrando quem está com status Recepcionado (fez check-in, pronto para atendimento). Se surge uma dúvida da enfermagem, uma nova mensagem pisca no painel de Comunicação. Antes de chamar o próximo paciente, você bate o olho no painel de Procedimentos na Clínica e vê, por uma barra de progresso, que a infusão da Dona Maria está correndo dentro do tempo previsto. O painel mostra todos os pacientes em tratamento na clínica, não apenas os seus, permitindo uma visão global da operação da unidade. Quando sobra um minuto entre atendimentos, você acessa o painel de Prescrições Pendentes e, com um clique, assina e revisa as prescrições do dia, garantindo que a farmácia e a enfermagem sigam o fluxo sem interrupções. É o seu dia controlado em uma única visão, sem cliques desnecessários.

Objetivo

Prover ao médico oncologista uma interface centralizada que consolide todas as informações críticas para a gestão do seu turno de trabalho em tela única. O foco é eliminar a navegação excessiva entre menus, reduzir a carga cognitiva e aumentar a segurança do paciente através de alertas visuais de atrasos e pendências críticas.

Escopo

  • Incluído: Header com busca inteligente (Nome, CPF, Prontuário); Indicadores de desempenho (KPIs); Painel de Consultas cronológico; Painel de Prescrições para assinatura rápida; Chat de comunicação interna; Monitoramento de tempo de infusão dos pacientes; Atalhos para o Prontuário Eletrônico (PEP).
  • Excluído: Digitação de evoluções clínicas (feito no PEP); Criação de novos protocolos; Gestão de horários da agenda; Comunicação externa (E-mail/WhatsApp).

Personas

PersonaPapel no SistemaNecessidade Principal
Médico OncologistaUsuário PrincipalVisão 360º do dia, agilidade na assinatura e monitoramento de segurança.
RecepcionistaStakeholder operacionalMantém as agendas atualizadas (status Agendado e Recepcionado). Recebe resultados de exames dos pacientes para encaminhar aos médicos. O status “Aguardando Recepção” pode ser definido manualmente pela recepcionista ou via integração com totem de fila.
Enfermeira e FarmacêuticaStakeholders clínicosRecebem prescrições assinadas para liberar o tratamento. A enfermagem só administra a prescrição depois que ela tiver sido revisada por um médico — revisão essa que o sistema exige automaticamente a partir de 1 dia antes da aplicação agendada (RN-CM-020).

Workflows do Profissional

A Central do Médico é um hub que toca múltiplos workflows do profissional. Cada workflow é documentado abaixo com seu resumo e os touchpoints específicos da Central.

Workflow 1 — Atendimento de Consulta

Resumo: O paciente chega à clínica, pega número na fila de espera e aguarda ser chamado pela recepcionista, que faz o check-in. O paciente aguarda na sala de espera. O médico, antes de chamar o paciente, analisa o prontuário, verifica anotações e exames anteriores. Então chama o paciente, inicia o atendimento (perguntas, constatação do estado atual, análise de exames trazidos, solicitação de novos exames, prescrições). O médico pode registrar a evolução clínica durante ou após a consulta. Ao finalizar, fecha o atendimento e foca no próximo paciente. O paciente sai do consultório e vai embora ou passa na recepção para marcar retorno.

Touchpoints da Central:

Momento do workflowNecessidade do profissionalO que a Central ofereceDecisão de design justificada
Antes de chamar o próximo pacienteSaber rapidamente quem está recepcionado e pronto para atendimentoPainel de Consultas com status “Recepcionado” em destaque (chip azul + borda lateral)Toggle default é “Pendentes” — no workflow, o médico só precisa ver quem falta atender, não quem já atendeu. Consultas finalizadas ficam esmaecidas ao alternar para “Todas”.
Antes de chamar o próximo pacienteIdentificar se o paciente está atrasado (horário passou e não iniciou)Badge vermelho pulsante “Atrasado · Xmin” no card de consultaO atraso é uma exceção do workflow que exige ação imediata — o pulsante chama atenção sem que o médico precise procurar.
Entre atendimentosAcessar o prontuário do próximo paciente sem navegar por menusClique no card de consulta abre diretamente o PEPNo workflow, o médico precisa do prontuário imediatamente antes de chamar o paciente — um clique é o menor caminho possível.
Início do turnoTer um panorama geral do dia (quantas consultas, quantas pendentes, quantas atrasadas)KPI “Consultas Hoje” com número “finalizadas/total” e subtexto “pendentes · atrasadas”No workflow, o médico precisa calibrar expectativas de carga de trabalho logo ao logar — o KPI dá isso sem abrir nenhum painel.
Durante o atendimentoNão ser interrompido por informações irrelevantesConsultas finalizadas aparecem esmaecidas na sua posição originalNo workflow, o médico em atendimento só se preocupa com o que vem a seguir — finalizadas são histórico imediato, não prioridade.

Workflow 2 — Tratamento Oncológico (Monitoramento)

Resumo: O paciente em tratamento oncológico tem um plano terapêutico com ciclos e sessões previstos. Em cada dia de tratamento, o paciente chega à clínica, faz check-in, é preparado pela enfermagem (acesso venoso, sinais vitais) e inicia a infusão do quimioterápico. A enfermagem monitora o paciente durante a infusão (checagens periódicas). O médico acompanha o progresso do tratamento, avalia resposta, ajusta protocolo quando necessário e prescreve a próxima sessão. O tratamento pode ser suspenso por intercorrências (febre neutropênica, reação alérgica). O paciente pode não aderir ao planejamento (descompasso de intervalos entre ciclos).

Touchpoints da Central:

Momento do workflowNecessidade do profissionalO que a Central ofereceDecisão de design justificada
Entre consultas / durante o turnoSaber quais pacientes estão em procedimento na clínica e em qual etapaPainel de Procedimentos na Clínica com status (Em Atendimento / Aguardando) e local na clínicaNo workflow de monitoramento, o médico precisa saber onde cada paciente está no fluxo de infusão sem sair da sua tela — o painel consolida isso em um olhar.
Durante o monitoramentoSaber se uma infusão está dentro do tempo previsto ou atrasadaBarra de progresso inline (3px) na linha do nome, com porcentagemNo workflow, o tempo de infusão é um parâmetro crítico de segurança — a barra permite monitoramento periférico sem abrir o prontuário. A barra é discreta para não competir com nome/status, mas fica vermelha se ultrapassar 100%.
Entre consultasDecidir se precisa intervir em um procedimento em andamentoClique no card abre a prescrição do procedimento; botão separado “PEP” abre o prontuárioNo workflow, o médico primeiro verifica a prescrição (o que está sendo infundido, dose, diluente) antes de decidir se precisa intervir — abrir a prescrição é a ação primária; o PEP é a ação secundária para contexto clínico completo.
Início do turnoSaber quantos pacientes estão em tratamento sob sua responsabilidade e quantos não estão aderentesKPI “Em Tratamento” com número principal (em tratamento) e subtexto “não aderentes”No workflow, o médico precisa identificar rapidamente pacientes em risco de não adesão — o subtexto traz apenas essa informação complementar, sem redundância.
Durante o turnoFiltrar apenas seus pacientes vs. ver todos os da clínicaToggle pill “Meus / Todos” (default: Meus)No workflow, o médico monitora seus próprios pacientes, mas pode precisar ver a operação global da clínica (ex: quando outro médico está em plantão) — o toggle permite alternar sem mudar de tela.

Workflow 3 — Prescrição e Dispensação

Resumo: O médico define o protocolo de tratamento e prescreve os medicamentos para cada ciclo/sessão. A prescrição fica pendente de assinatura. O médico assina (com ou sem certificado digital) na véspera ou no dia da aplicação. A farmácia recebe a prescrição assinada e manipula o medicamento. Como segunda barreira de segurança, o sistema marca automaticamente a prescrição como pendente de revisão a partir de 1 dia antes da aplicação agendada — um médico (preferencialmente o prescritor ou o médico assistente do paciente) precisa abrir a prescrição e confirmá-la como revisada antes que a enfermagem possa administrar o medicamento. A prioridade das prescrições não revisadas cresce da mesma forma que a das não assinadas, conforme a hora da aplicação se aproxima.

Touchpoints da Central:

Momento do workflowNecessidade do profissionalO que a Central ofereceDecisão de design justificada
Início do turno / entre atendimentosAssinar prescrições pendentes antes que a farmácia possa manipularPainel de Prescrições Pendentes com botão “Assinar” no card que abre a tela de assinatura com a prescrição completaNo workflow, a assinatura é um gargalo — a farmácia não pode manipular sem ela. O botão no card abre a tela de assinatura com a prescrição completa para que o médico revise e se certifique de que é a prescrição correta antes de assinar. É responsabilidade do médico saber o que está assinando — a assinatura não pode ser um clique direto sem revisão.
Início do turnoPriorizar quais prescrições assinar primeiro (as mais urgentes)Chips de urgência: vermelho (<12h) e laranja (12-24h) com tempo restanteNo workflow, a prescrição com aplicação agendada para breve tem prioridade máxima — a cor vermelha sinaliza que a janela de ação está fechando.
A partir de 1 dia antes da aplicação agendadaConfirmar que a prescrição foi revisada por um médico antes da administração ao pacienteCard de prescrição tipo “Revisar”, gerado automaticamente pelo sistema quando falta 1 dia ou menos para a aplicação e a prescrição ainda não foi revisada por nenhum médico. Botão “Revisar” abre a prescrição completa para o médico validar ou ajustar antes de confirmarNo workflow, a revisão é uma segunda barreira de segurança, independente e posterior à assinatura — garante que algum médico (idealmente o prescritor ou o assistente do paciente) validou a prescrição pouco antes da administração. Por ser automática e baseada em tempo, ganha a mesma escalada de prioridade visual (chip vermelho/laranja) das prescrições não assinadas, refletindo que o risco cresce conforme a aplicação se aproxima.
Início do turnoSaber quantas prescrições urgentes (menos de 12h) precisam de sua atençãoKPI “Alertas de Prescrição” com número principal (urgentes) em vermelho e subtexto (p/ revisar · p/ assinar próximos 7 dias)No workflow, prescrições urgentes são o item de maior risco — o número em vermelho chama atenção imediata ao logar. O subtexto dá contexto adicional sem competir com o número principal.
Ao assinar uma prescriçãoConfirmar que a assinatura foi processada e retornar à CentralToast de sucesso “Prescrição assinada com sucesso” + retorno automático à Central, focada no painel de Prescrições Pendentes + atualização do KPINo workflow, o médico precisa confirmação visual de que cumpriu a etapa — o toast + retorno à Central + decremento do KPI fecham o loop de feedback. O retorno automático evita que o médico precise navegar manualmente de volta.
Ao revisar prescriçõesFocar primeiro nas prescrições que é preferencialmente responsável por revisar (seus pacientes), mas poder ajudar a revisar as de colegas quando necessárioToggle pill “Meus / Todos” no painel de Prescrições Pendentes. “Meus” mostra somente as prescrições a revisar em que o médico logado é o prescritor ou o médico assistente do paciente. “Todos” mostra todas as prescrições a revisar (de qualquer médico, já que RN-CM-020 permite que qualquer médico revise) somadas às prescrições a assinar do próprio médico logadoNo workflow, o médico prioriza naturalmente seus próprios pacientes, mas pode ajudar a revisar as de colegas quando necessário — daí o toggle. O default é “Meus”: as prescrições a assinar nunca são afetadas pelo toggle (já são sempre do médico logado, RN-CM-012), então não há risco de escondê-las por trás de um filtro — o padrão “Meus” apenas prioriza a revisão dos próprios pacientes, consistente com o padrão do painel de Procedimentos.

Workflow 4 — Comunicação Interna

Resumo: Diferentes profissionais da clínica (recepção, farmácia, enfermagem) precisam comunicar informações ao médico durante o turno: recados, solicitações, resultados de exames, dúvidas sobre prescrições, notificações de intercorrências. O emissor pode definir uma data limite para resposta. O médico recebe essas mensagens, precisa priorizá-las, respondê-las ou resolvê-las, e arquivar as resolvidas. Algumas mensagens são urgentes (intercorrência durante infusão), outras são informativas (confirmação de manipulação).

Touchpoints da Central:

Momento do workflowNecessidade do profissionalO que a Central ofereceDecisão de design justificada
Durante todo o turnoReceber mensagens da equipe sem sair da CentralPainel de Comunicação com mensagens não resolvidasNo workflow, o médico não pode alternar entre telas para checar mensagens — o painel integra comunicação ao cockpit, permitindo resposta rápida entre atendimentos.
Ao receber uma mensagem novaIdentificar rapidamente que há mensagem não lidaMensagens não lidas com ícone colorido e borda lateral destacadaNo workflow, mensagens não lidas são pendências — o ícone colorido + borda destacada permitem identificação periférica sem ler o conteúdo. Ao ser lida, passa ao estado normal.
Ao revisar a lista de mensagensPriorizar mensagens com prazo de respostaData limite exibida no card (“Responder até 14:00”) + ordenação por data limite primeiroNo workflow, mensagens com prazo são compromissos — a ordenação coloca as mais urgentes no topo, e a data limite visível no card permite triagem sem abrir a mensagem.
Ao resolver uma solicitaçãoArquivar a mensagem com um cliqueBotão “Resolvido” no card que remove a mensagem e atualiza o contadorNo workflow, resolver é uma ação frequente e repetitiva — um clique é o menor caminho. A remoção imediata mantém a lista enxuta.
Durante todo o turnoDistinguir a origem da mensagem (farmácia, enfermagem, recepção, sistema)Ícone identificador da origem (Biblioteca Gemed 2.1 recepcionista, farmacêutica, enfermeira e bell (lucide))No workflow, a origem determina a natureza da mensagem e a urgência esperada — o ícone permite categorização visual instantânea sem ler o texto.

Regras de Negócio Consolidadas

Layout e Visualização

  • RN-CM-001 — Layout Full Viewport: A Central deve ocupar 100% da altura da tela (100vh), evitando barras de rolagem laterais na página principal. Cada painel interno possui sua própria rolagem.
  • RN-CM-002 — Grid 2×2: A interface é dividida em quatro quadrantes fixos, cada um com uma função específica:
    • Quadrante superior esquerdo — Consultas: Agenda de consultas do médico no dia, com status visual de cada paciente (Agendado, Aguardando Recepção, Recepcionado, Em Atendimento, Finalizado).
    • Quadrante superior direito — Prescrições Pendentes: Lista de prescrições que aguardam ação do médico, divididas em duas categorias: prescrições para assinar (aguardando assinatura digital) e prescrições para revisar (marcadas automaticamente pelo sistema quando a aplicação agendada está a 1 dia ou menos e a prescrição ainda não foi revisada por nenhum médico — RN-CM-020).
    • Quadrante inferior esquerdo — Comunicação: Mensagens internas da recepção, farmácia, enfermagem e sistema, com ação de resolver/arquivar.
    • Quadrante inferior direito — Procedimentos na Clínica: Monitoramento de pacientes previstos e presentes na unidade para procedimentos e tratamentos (infusões, aplicações, checagens) — não inclui consultas médicas, apenas procedimentos terapêuticos e diagnósticos.
    • Diferenciação visual: O cabeçalho de cada painel possui fundo cinza claro (color-base-dark) para diferenciar do corpo do painel (fundo branco), orientando o olhar do usuário entre a área estrutural e a área de conteúdo.
  • RN-CM-003 — Títulos como links de navegação: Os títulos dos 4 painéis são clicáveis e funcionam como links para as telas dedicadas correspondentes. No estado default, o título aparece em peso regular (sem negrito) com cor neutra. No hover, a cor muda para o azul secundário (color-secondary-dark) e uma seta (→) aparece discretamente ao lado do título, deslizando da esquerda. Esta abordagem substitui links separados (‘Ver agenda →’, ‘Ver todas →’, etc.), reduzindo ruído visual no cabeçalho. Motivador: o título é o elemento mais natural para clicar; a seta no hover garante descobribilidade sem poluir o estado default.

Busca Inteligente

  • RN-CM-004 — Lógica de Busca: A primeira busca é acionada quando o usuário digita os primeiros 2 caracteres e para de digitar por 1 segundo. A partir desse primeiro disparo, a lista vai sendo filtrada dinamicamente conforme o usuário continua digitando, sem necessidade de novo intervalo de pausa. A busca sempre retorna uma lista, pois o algoritmo busca por aproximação de termos. Se a entrada começar com dígito, o sistema busca por CPF ou Data de Nascimento. Se começar com letra, busca por Nome do Paciente ou Nome da Mãe. O placeholder do campo de busca deve ser ‘Procurar paciente…’. Ao abrir o dropdown de resultados, exibir uma mensagem de orientação no rodapé da lista: ‘Digite parte do nome, CPF, data de nascimento ou nome da mãe para filtrar’.

Consultas e Atendimento

  • RN-CM-005 — Status de Atendimento: As consultas devem refletir o status real:
    • Agendado = consulta marcada, mas sem mais interações
    • Aguardando Recepção = paciente está presente na clínica, mas ainda não fez o check-in
    • Recepcionado = paciente fez o check-in com a recepção e está pronto para ser atendido
    • Em Atendimento = paciente está em atendimento com o profissional (médico)
    • Finalizado = paciente já realizou a consulta
  • RN-CM-006 — Ordenação: A lista de consultas é sempre cronológica, priorizando o próximo atendimento.

Prescrições e Assinatura

  • RN-CM-011 — Alertas de Urgência: Prescrições com menos de 12 horas para a aplicação ganham um alerta vermelho. Entre 12h e 24h, o alerta é laranja. Esta regra vale tanto para prescrições pendentes de assinatura quanto para prescrições pendentes de revisão (RN-CM-020) — a urgência é sempre calculada em relação ao tempo restante até a aplicação agendada, independentemente do tipo de pendência.
  • RN-CM-012 — Assinatura Digital: A assinatura de prescrições pode ocorrer de 2 modos, definidos por parâmetro de configuração do cliente: (a) assinatura com certificado digital — exige que o médico possua certificado digital ativo vinculado ao seu perfil; (b) assinatura sem certificado — validada apenas pela sessão do usuário logado, sem exigência de certificado. O modo ativo é determinado pela configuração da clínica.
  • RN-CM-020 — Revisão Automática Pré-Aplicação: O sistema marca automaticamente uma prescrição já assinada como “a revisar” quando a data/hora agendada da aplicação está a 1 dia (24h) ou menos da data/hora atual E não existe assinatura do médico (original ou de revisão) com menos de 7 dias. Em outras palavras: se a assinatura original do médico tiver menos de 7 dias no momento em que a janela de D-1 se abre, ela já vale como revisão implícita — não é exigida uma confirmação separada. Se a assinatura original tiver mais de 7 dias, é necessária uma confirmação explícita de revisão dentro dos últimos 7 dias. O objetivo é garantir que um médico tenha validado a prescrição recentemente antes da administração ao paciente pela enfermagem — é uma segunda barreira de segurança, independente e desvinculada de qualquer notificação de problema pela farmácia ou enfermagem. Qualquer médico pode revisar, mas o sistema deve sinalizar preferencialmente o médico prescritor e o médico assistente do paciente como revisores ideais. Revisar não exige necessariamente editar a prescrição — o médico pode apenas confirmá-la como revisada (“Marcar como Revisada”) ou, se identificar necessidade de ajuste, editá-la, o que gera uma nova versão da prescrição (novo registro, com a versão anterior cancelada) que precisa ser assinada novamente. Prescrições “a revisar” seguem a mesma escala de urgência de RN-CM-011 conforme o tempo restante até a aplicação.

Comunicação Interna

  • RN-CM-015 — Notificações e Priorização: Mensagens não lidas devem ser destacadas visualmente através do ícone da origem na cor primary-pure e borda lateral esquerda na cor secondary-pure (sem uso de negrito no texto, conforme RN-CM-019). Ao serem lidas pela primeira vez, o ícone reverte para a cor padrão e a borda torna-se transparente. Quem emite a comunicação pode definir uma data limite para resposta ou resolução. A ordenação da lista considera a data limite (quando definida) e a ordem de chegada (LIFO) para mensagens sem data limite.

Procedimentos na Clínica (Monitoramento)

  • RN-CM-016 — Barra de Progresso: Exibe o tempo decorrido da infusão versus o tempo estimado pelo protocolo. Se ultrapassar 100%, a barra torna-se vermelha.

Atualização de Dados

  • RN-CM-017 — Atualização Frequente: A Central deve ser um espelho confiável da realidade da clínica. Os dados de todos os painéis devem ser atualizados com frequência suficiente para refletir o estado atual das operações. O mecanismo técnico de atualização (polling, websocket ou outro) será definido pelo time técnico, mas o requisito funcional é que as informações exibidas estejam sempre atualizadas dentro de uma janela de tempo curta o suficiente para ser operacionalmente útil.
  • RN-CM-019 — Hierarquia visual sem negrito: A Central não utiliza negrito (font-weight: 700) em nenhum elemento estrutural. A hierarquia visual é construída exclusivamente através de tamanho tipográfico, cor e espaçamento. Elementos estruturais (títulos de painel, labels, metadados) usam peso regular (400). Destaques importantes são feitos por contraste cromático (chips coloridos, borda lateral dos KPIs, número vermelho de alertas) e tamanho (22px nos valores de KPI, 14px nos nomes, 11px nos metadados). Motivador: o negrito deve ser economizado para destaques verdadeiramente importantes; informações estruturais devem orientar o olhar discretamente, não competindo com as informações clínicas que importam.

Fluxo Principal (O Ciclo do Dia)

  1. Início do Turno: O médico faz login e visualiza o panorama geral nos KPIs.
  2. Triagem de Pendências: Antes do primeiro paciente, o médico assina as prescrições pendentes de assinatura e confirma a revisão das prescrições marcadas automaticamente como “a revisar” (aplicação agendada em até 1 dia), priorizando as mais urgentes.
  3. Atendimento: Ao identificar um paciente “Recepcionado” no painel de Consultas, o médico clica no nome para abrir o PEP e iniciar o atendimento.
  4. Monitoramento: Entre consultas, o médico observa o painel de Procedimentos na Clínica para verificar se algum tratamento está atrasado ou finalizado.
  5. Comunicação: O médico responde dúvidas rápidas da equipe via painel de Comunicação sem sair da tela principal.

Premissas

  • A assinatura de prescrições pode exigir certificado digital ou não, dependendo da configuração do cliente. Se a clínica está configurada para assinatura com certificado digital, o médico que possuir certificado assina digitalmente; o médico que não possuir certificado deve imprimir e assinar fisicamente. Se a clínica não está configurada para certificado digital, a assinatura é validada apenas pela sessão do usuário logado.
  • A resolução mínima de tela recomendada é de 1920x1080 (Full HD).

Dependências

Sistema/MóduloDependênciaImpacto
Módulo de AgendaStatus da agendaSem isso, o painel de consultas não atualiza.
Módulo de AgendaData/hora da aplicação da prescriçãoA marcação automática de “a revisar” (RN-CM-020) depende da data/hora de aplicação agendada na prescrição — sem essa informação, o sistema não consegue calcular a janela de 1 dia e disparar o estado de revisão.
Serviço de AssinaturaIntegração com CertificadoraNecessário para a validade jurídica da assinatura (quando aplicável).
RecepcionistaAtualização de status na agendaDefine os status “Agendado” e “Recepcionado” no painel de Consultas.

Requisitos SBIS Aplicáveis

ID SBISDescrição AcessívelImplementação no Cockpit
ECF.03.11Busca multifatorial de pacientesImplementado na busca do Header (Nome, CPF, Mãe).
ECF.16.01Listagem de pendências do profissionalImplementado no Painel de Prescrições Pendentes.
ECF.17.04Registro de eventos em ordem cronológicaAplicado na ordenação de Consultas e Mensagens.

SEÇÃO 2 — ESPECIFICAÇÃO

Premissa de design: Toda decisão de design nesta especificação é justificada pelos touchpoints de workflow documentados na Seção 1. Ao escolher um componente, definir uma ordenação, priorizar uma informação visualmente ou estabelecer um comportamento de navegação, a decisão apoia o fluxo real do profissional naquele momento específico do workflow. Consulte a seção “Workflows do Profissional” na Seção 1 para o contexto completo de cada touchpoint.

2.1 Cabeçalho (Header) com Busca de Pacientes

US-CM-000 — Buscar pacientes rapidamente

Como médico, quero buscar qualquer paciente pelo nome, CPF, data de nascimento ou nome da mãe diretamente do cabeçalho, para acessar o prontuário sem precisar navegar por menus.

Descrição Funcional:

O cabeçalho é a barra superior fixa da Central do Médico e contém 3 blocos:

  1. Identificação da clínica e unidade: Nome da clínica e unidade de atendimento onde o médico está logado.
  2. Campo de busca de pacientes: Campo de texto. A busca é inteligente e contextual:
    • O placeholder do campo deve ser MSG_searchPac para deixar explícito que é uma busca por pacientes.
    • Ao abrir o dropdown de resultados, exibir uma mensagem de orientação no rodapé da lista: MSG_searchFoot.
    • A primeira busca é acionada quando o usuário digita os primeiros 2 caracteres e para de digitar por 1 segundo. A partir desse primeiro disparo, a lista vai sendo filtrada dinamicamente conforme o usuário continua digitando, sem necessidade de novo intervalo de pausa.
    • A busca sempre retorna uma lista, pois o algoritmo busca por aproximação de termos. Se o usuário digitar “ay”, o sistema busca termos em torno de “ay”: “ay” será o mais prioritário, mas se não encontrar, retornará “ai”, “aj” e assim por diante.
    • Se a entrada começar com dígito, o sistema busca por CPF ou Data de Nascimento. Se começar com letra, busca por Nome do Paciente ou Nome da Mãe.
    • Os resultados da busca devem conter minimamente: nome completo, número de prontuário, sexo, data de nascimento, nome da mãe e CPF (conforme requisito SBIS ECF.03.14).
    • Ao selecionar um paciente na lista de resultados, o sistema abre o Prontuário Eletrônico do Paciente (PEP).
  3. Identificação do médico: Avatar com foto do profissional (quando disponível) ou iniciais, dropdown para menu específico do usuário (por enquanto só com a ação se sair).

Justificativa de workflow: A busca por pacientes no cabeçalho atende ao touchpoint ‘Antes de chamar o próximo paciente’ (Workflow 1) e ao touchpoint ‘Decidir se precisa intervir em um procedimento’ (Workflow 2). Em ambos os momentos, o médico pode precisar acessar um prontuário que não está visível nos painéis — a busca global no cabeçalho é o atalho universal, disponível em qualquer momento do turno.

Critérios de Aceitação:

  • Dado que o médico digita “Ma” no campo de busca, quando ele para de digitar por 1 segundo, então o sistema deve retornar pacientes cujo nome ou nome da mãe contenham “Ma” ou termos aproximados, exibindo nome completo, número de prontuário, sexo, data de nascimento, nome da mãe e CPF.
  • Dado que o médico digita “12” no campo de busca, quando ele para de digitar por 1 segundo, então o sistema deve buscar por CPF ou data de nascimento que contenham “12”.
  • Dado que o médico digita apenas 1 caractere, então o sistema não deve disparar a busca, exibindo a mensagem MSG_searchMin no rodapé do dropdown.
  • Dado que o médico digita “ay” e não existe paciente com esse termo exato, então o sistema deve retornar pacientes com termos próximos (aproximação), como “Ayla”, “Aymoré”, ordenados por relevância.
  • Dado o médico seleciona um paciente na lista de resultados, então o sistema deve abrir o Prontuário Eletrônico do Paciente (PEP), preservando o contexto do profissional logado.
    • Dado que a busca não retorna resultados, então o sistema deve exibir MSG_searchNone

Internacionalização:

Termopt-BRen-USes-419
MSG_searchPacProcurar paciente…Search Pacient…Buscar paciente…
MSG_searchFootDigite parte do nome, CPF, data de nascimento ou nome da mãe para filtrarEnter parte of the name, ID, mother’s name or DOB to filterIngrese parte del busque por nombre, ID, nombre de la madre o fecha de nacimiento
MSG_searchMinDigite pelo menos 2 caracteres para iniciar a busca.Type at least 2 characters to start searching.Escriba al menos 2 caracteres para iniciar la búsqueda.
MSG_searchNoneNenhum paciente encontrado com os dados informados.No patient found with the provided data.Ningún paciente encontrado con los datos informados.

2.2 KPI Bar (Indicadores)

US-CM-001 — Visualizar indicadores do dia

Como médico, quero ver um resumo numérico do meu dia (consultas, tratamentos, procedimentos na clínica e alertas) em uma barra no topo, para ter um panorama rápido sem precisar analisar cada painel.

Descrição Funcional:

Layout dos cards: Cada KPI card possui uma borda lateral esquerda colorida (4px) que identifica visualmente a categoria:

  • Consultas Hoje → azul (color-secondary-pure),
  • Em Tratamento → verde (color-primary-pure),
  • Procedimentos Hoje → âmbar (color-highlight-pure),
  • Alertas de Prescrição → vermelho (color-error-pure). O ícone do KPI fica posicionado à direita do texto. Motivador: a borda colorida permite identificação rápida da categoria mesmo em uma olhada periférica, sem necessidade de leitura do título.

Justificativa de workflow: Os 4 KPIs correspondem aos 4 workflows que a Central toca: Consultas Hoje (Workflow 1), Em Tratamento (Workflow 2), Alertas de Prescrição (Workflow 3) e Procedimentos Hoje (Workflow 2). No início do turno (touchpoint comum a todos os workflows), o médico precisa calibrar expectativas de carga de trabalho — os KPIs dão isso em um olhar, sem abrir nenhum painel. Cada KPI é clicável porque, após o panorama inicial, o médico pode precisar aprofundar em um workflow específico.

A KPI Bar é uma faixa horizontal entre o cabeçalho e o grid 2×2, contendo 4 cartões de indicadores fixos. Cada cartão é clicável e navega para a tela dedicada correspondente.

  1. Consultas Hoje: Exibe “finalizadas/total” (ex: “4/6”). Subtexto: “X pendentes · Y atrasadas”.
    • Definição dos termos:
      • Pendentes: agendas que ainda não foram finalizadas
      • Atrasadas: agendas pendentes cuja hora marcada já passou
    • Ao clicar: abre a tela de Agenda de Consultas
  2. Em Tratamento: Exibe o total de pacientes em tratamento (número principal) cujo médico assistente é o médico logado. Subtexto: ‘Y não aderentes’.
    • Definição dos termos:
      • Em tratamento (número principal): pacientes que estão em tratamento cujo médico assistente é o médico logado
      • Não aderentes: pacientes em tratamento que não estão conformes com o planejamento do tratamento (plano terapêutico) — pode ser por descompasso com os intervalos entre sessões e/ou ciclos previstos
    • Ao clicar: abre a tela de Pacientes do Médico
  3. Procedimentos Hoje: Exibe o total de pacientes do médico logado com procedimentos (não consultas) previstos ou em andamento na unidade hoje. Subtexto: “X em atendimento · Y aguardando · Z previstos”.
    • Definição dos termos:
      • Em atendimento: pacientes do médico logado que já estão em procedimento (iniciaram quimioterapia, estão realizando cateterismo ou limpeza de cateter, iniciaram sessão radioterápica, iniciaram cirurgia, etc.)
      • Aguardando: pacientes do médico logado que estão na clínica (em check-in ou sendo preparados para o procedimento) mas ainda não iniciaram o procedimento
      • Previstos: pacientes do médico logado que ainda não chegaram à clínica mas têm procedimento previsto para o dia
    • Ao clicar: abre a tela de Procedimentos na Clínica
  4. Alertas de Prescrição: Exibe o total de prescrições pendentes urgentes (menos de 12h para aplicação). Subtexto: “X p/ revisar · Y p/ assinar (próx. 7 dias)”.
    • Definição dos termos:
      • Urgentes (número principal): prescrições pendentes de assinatura E pendentes de revisão com menos de 12h para a aplicação agendada
      • P/ revisar: prescrições marcadas automaticamente pelo sistema como “a revisar” (agenda de aplicação a 1 dia ou menos e ainda sem revisão de nenhum médico — ver RN-CM-020)
      • P/ assinar (próx. 7 dias): prescrições pendentes de assinatura com aplicação prevista nos próximos 7 dias
    • Quando o valor principal (urgentes) for maior que zero, o número deve aparecer em vermelho (cor error-pure, f44336).
    • Ao clicar: abre a tela de Prescrições Pendentes

Critérios de Aceitação:

  • Dado que o médico abre a Central, quando os dados são carregados, então a KPI Bar deve exibir os 4 indicadores com seus respectivos subtextos.
  • Dado que o KPI de Alertas de Prescrição tem 3 prescrições urgentes, então o número “3” deve ser exibido em vermelho (#F44336).
  • Dado que o KPI de Alertas de Prescrição tem 0 urgentes, então o número “0” deve ser exibido na cor padrão (não vermelho).
  • Dado que o médico clica no card “Consultas Hoje”, então o sistema deve navegar para a tela de Agenda de Consultas.
  • Dado que o médico clica no card “Em Tratamento”, então o sistema deve navegar para a tela de Pacientes do Médico.
  • Dado que o médico clica no card “Procedimentos Hoje”, então o sistema deve navegar para a tela de Procedimentos na Clínica.
  • Dado que o médico clica no card “Alertas de Prescrição”, então o sistema deve navegar para a tela de Prescrições Pendentes.
  • Dado que o endpoint de KPIs falha, então a KPI Bar deve exibir ”—” nos valores e os demais painéis devem continuar operando normalmente.

Internacionalização

Termo/Localizaçãopt-BRen-USes-419
Card Consultas Hoje - títuloCONSULTAS HOJETODAY’S APPOINTMENTSCONSULTAS DE HOY
Card Consultas Hoje - pendentespendentespendingpendientes
Card Consultas Hoje - atrasadasatrasadasdelayedatrasada
Card Em tratamento - títuloEM TRATAMENTOIN TREATMENTEN TRATAMIENTO
Card Em tratamento - não aderentesnão aderentesnon-adherentno adherentes
Card Procedimentos hoje - títuloPROCEDIMENTOS HOJETODAY’S PROCEDURESPROCEDIMIENTOS HOY
Card Procedimentos hoje - em atendimentoem atendimentoin progressen atención
Card Procedimentos hoje - aguardandoaguardandowaitingen espera
Card Procedimentos hoje - previstosprevistosscheduledprogramados
Card Alertas de prescrição = títuloALERTAS DE PRESCRIÇÃOPRESCRIPTION ALERTSALERTAS DE PRESCRIPCIÓN
Card Alertas de prescrição - revisarp/revisarto reviewp/revisar
Card Alertas de prescrição - assinarp/assinar (próx. 7 dias)to sign (next 7 days)p/firmar (próx. 7 dias)

2.3 Painel de Consultas (Quadrante Superior Esquerdo)

US-CM-002 — Visualizar consultas do dia

Como médico, quero ver minhas consultas do dia em ordem cronológica com informações clínicas relevantes, para organizar meu fluxo de atendimento.

US-CM-003 — Filtrar consultas pendentes

Como médico, quero alternar entre “Todas” e “Pendentes” no painel de consultas, para focar apenas nas consultas que ainda não foram realizadas.

Descrição Funcional:

O painel de Consultas exibe a agenda do médico para o dia, composta por cards de consulta. Cada card contém:

  • Hora prevista da consulta e hora prevista de término (ou tempo previsto da consulta)
  • Nome do paciente com foto (avatar com iniciais ou foto, quando disponível)
  • Diagnóstico oncológico (se houver — ex: “Ca. Mama”)
  • Tipo de consulta (Presencial / Teleatendimento)
  • Tags de atenção (se houver — ex: VIP, Quimioterapia, 1ª Consulta)
  • Status da agenda (Agendado, Aguardando Recepção, Recepcionado, Em Atendimento, Finalizado)

Ordenação: A lista deve estar ordenada pela hora agendada. Consultas finalizadas permanecem na sua posição original na ordem cronológica.

Filtro: Deve haver um toggle em estilo pill (botões com borda discreta e fundo branco) entre ‘Todas’ e ‘Pendentes’. O default é mostrar apenas as pendentes (oculta finalizadas). Ao alternar para ‘Todas’, as finalizadas aparecem na sua posição original esmaecidas. Motivador: o estilo pill é mais discreto que o bloco cinza anterior, competindo menos com o conteúdo dos cards.

Tratamento visual de finalizadas: Consultas finalizadas devem aparecer esmaecidas (cor de fundo mais clara e opacidade reduzida), mantendo a ordem cronológica da agenda. Não são movidas para o final da lista — permanecem na sua posição original, apenas com sinalização visual de que já foram concluídas.

Atraso: Quando o paciente está atrasado (horário agendado já passou e a consulta não foi iniciada nem finalizada), mostrar um sinalizador de “Atrasado” com o tempo de atraso em minutos (ex: ”🔴 15min”).

Cores de status: Agendado ffe0b3, Aguardando Recepção ffc5c1, Recepcionado b7e3ff, Em Atendimento d1df9d, Finalizado 9679e1.

Destaque visual por status: Além dos chips coloridos, cards com status “Recepcionado” recebem uma borda lateral esquerda (3px) na cor secondary-pure (azul), sinalizando que o paciente está pronto para atendimento. Cards com status “Aguardando Recepção” recebem borda lateral esquerda (3px) na cor ff8a80 (vermelho-claro), sinalizando que o paciente está presente na clínica. Outros status não recebem borda adicional. Motivador: a borda colorida é consistente com o padrão de KPI cards e permite identificação periférica dos pacientes prontos para atendimento sem necessidade de leitura do chip.

Navegação: O título do painel (‘Consultas’) é um link clicável para a tela dedicada da Agenda do Médico. No hover, o título muda de cor e uma seta (→) aparece ao lado. Ao clicar em qualquer card de consulta, o sistema abre o Prontuário Eletrônico do Paciente (PEP). Motivador: o título como link elimina a necessidade de um botão separado ‘Ver agenda →’, reduzindo ruído visual no cabeçalho do painel.

Justificativa de workflow: Este painel atende ao touchpoint ‘Antes de chamar o próximo paciente’ (Workflow 1). O toggle default ‘Pendentes’ reflete que, neste momento do workflow, o médico só precisa ver quem falta atender. O badge de atraso reflete a exceção do workflow onde o horário passou e o paciente não foi chamado. O clique no card abrindo o PEP reflete que, neste momento, o médico precisa do prontuário para se preparar antes de chamar o paciente.

Estado vazio: Quando não há consultas agendadas, exibir ícone de calendário vazio com a mensagem MSG_appointmentNone.

Critérios de Aceitação:

  • Dado que o médico abre a Central, quando o painel de Consultas carrega, então o default deve mostrar apenas consultas pendentes, ordenadas por hora agendada.
  • Dado que o médico clica no toggle “Todas”, então as consultas finalizadas devem aparecer na sua posição original esmaecidas (cor de fundo mais clara e opacidade reduzida).
  • Dado que uma consulta agendada para 09:00 não foi iniciada e são 09:15, então o sistema deve exibir o sinalizador ”🔴 Atrasado · 15min” no card da consulta.
  • Dado que o médico clica em qualquer card de consulta, então o sistema deve abrir o Prontuário Eletrônico do Paciente (PEP).
  • Dado que o médico clica no título do painel, então o sistema deve navegar para a tela dedicada da Agenda do Médico.
  • Dado que não há consultas agendadas no dia, então o painel deve exibir “Nenhuma consulta agendada para hoje”.
  • Dado que uma consulta tem status “Recepcionado”, então o card deve exibir borda lateral esquerda na cor secondary-pure (azul).
  • Dado que uma consulta tem status “Aguardando Recepção”, então o card deve exibir borda lateral esquerda na cor ff8a80.

Internacionalização

Termo/Localizaçãopt-BRen-USes-419
painel-títuloConsultasAppointmentsConsultas
toggle-todasTodasAllTodas
toggle-pendentesPendentesPendingPendientes
chip-atrasadoAtrasadoDelayedAtrasado
status-agendadoAgendadoShceduledAgendada
status-aguardandoAguardando recepçãoWaiting receptionEsperando recepción
status-recepcionadoRecepcionadoChecked-inRecepcionado
status-atendimentoEm AtendimentoIn consulationEn atención
status-finalizadoFinalizadoCompletedFinalizado
MSG_appointmentNoneNenhuma agenda para este diaNo appointments for this dayNo hay citas para este día

2.4 Painel de Prescrições Pendentes (Quadrante Superior Direito)

US-CM-004 — Visualizar prescrições pendentes

Como médico, quero ver as prescrições pendentes de assinatura ou revisão ordenadas por prioridade, para priorizar as que têm menos tempo até a aplicação agendada.

US-CM-005 — Assinar prescrição

Como médico, quero revisar e assinar prescrições pendentes diretamente no Cockpit, para que a farmácia possa liberar o medicamento a tempo.

US-CM-006 — Revisar prescrição

Como médico, quero revisar e confirmar prescrições que o sistema marcou automaticamente como pendentes de revisão perto da aplicação, para garantir que algum médico validou a prescrição antes da administração ao paciente.

Descrição Funcional:

O painel de Prescrições Pendentes lista as prescrições que aguardam ação do médico, divididas em duas categorias:

  1. Prescrições para assinar — aguardando assinatura digital do médico
  2. Prescrições para revisar — marcadas automaticamente pelo sistema quando a agenda de aplicação está a 1 dia (24h) ou menos da data/hora atual e a prescrição ainda não foi revisada por nenhum médico (RN-CM-020). Uma prescrição só entra nessa categoria depois de já assinada — é uma segunda barreira de segurança, independente e posterior à assinatura, não relacionada a notificações de farmácia ou enfermagem.

Cada card de prescrição contém:

  • Nome do paciente (nome social, se houver; caso contrário nome civil) — o endpoint envia ambos (preferredName/legalName, mesmo padrão do painel de Consultas e de Procedimentos) para o médico perceber uma eventual questão de nome social/gênero antes de abrir a prescrição
  • Código da prescrição, no formato “Protocolo CxDy” (ex: “CARBO-TAXOL C3D1”, onde C = ciclo e D = dia/sessão) — vem pronto do banco (Prescricao.Identificacao), sem montagem de protocolo e ciclo como campos separados
  • Data da agenda da aplicação agendada (ex: “22/07 18:00”) — importante principalmente para prescrições pendentes de revisão, pois a data é o próprio motivo pelo qual a prescrição está nessa lista
  • Tempo restante até a aplicação agendada (ex: “8h restantes”)
  • Tipo de ação (Assinar ou Revisar)
  • No caso de revisões: destaque visual (não texto com nomes de terceiros) quando o médico logado é revisor preferencial — prescritor ou médico assistente do paciente (RN-CM-020)

Ordenação: As prescrições devem ser ordenadas por prioridade — quanto mais próxima da data de aplicação agendada, mais prioritária é. As prescrições com menos de 12 horas restantes são classificadas como “Críticas” e marcadas com chip vermelho (fundo ffebee, texto d32f2f). Entre 12h e 24h, são “Atenção” e marcadas com chip laranja (fundo fff8e1, texto ff8f00).

Filtro “Meus / Todos”: O painel tem um toggle em estilo pill entre “Meus” e “Todos”, que afeta apenas as prescrições para revisar — as prescrições para assinar já são, por definição, sempre do médico logado (RN-CM-012: só o próprio prescritor assina) e por isso aparecem em ambos os estados do toggle, sem alternância. “Meus” mostra apenas as prescrições a revisar em que o médico logado é o prescritor ou o médico assistente do paciente (revisor preferencial, RN-CM-020). “Todos” mostra todas as prescrições a revisar de qualquer médico da clínica, somadas às prescrições a assinar do próprio médico logado. O default é “Meus” — consistente com o padrão do painel de Procedimentos — porque as prescrições a assinar nunca são escondidas pelo toggle; o filtro só decide o quanto o médico quer ver do trabalho de revisão de colegas.

Assinatura (tela de assinatura): Ao clicar em “Assinar”, o sistema abre a tela de assinatura com a prescrição completa para que o médico revise e se certifique de que é a prescrição correta. É responsabilidade do médico saber o que está assinando — a assinatura não pode ser um clique direto sem revisão. A tela exibe todos os medicamentos, doses, vias, diluentes e instruções. Após revisão, o médico clica em “Assinar” na tela, que processa a assinatura conforme o modo configurado (com ou sem certificado digital). Em caso de sucesso, o sistema exibe um toast de sucesso “Prescrição assinada com sucesso” e retorna automaticamente à Central do Médico, focada no painel de Prescrições Pendentes, com o KPI de Alertas atualizado. Em caso de erro, exibir toast de erro na tela de assinatura.

Revisão (tela de revisão): Ao clicar em “Revisar”, o sistema abre a prescrição completa (medicamentos, doses, vias, diluentes e instruções) para o médico validar. O médico tem duas opções: (a) confirmar que a prescrição está correta, clicando em “Marcar como Revisada” — o sistema registra o médico revisor e o timestamp, e a prescrição sai da lista de pendentes; ou (b) identificar necessidade de ajuste e editar a prescrição, recalculando, adicionando ou retirando medicamentos. Nesse segundo caso, o sistema cancela a prescrição atual e cria uma nova versão com os itens ajustados — como é uma prescrição nova, ela precisa ser assinada novamente pelo médico (mesmo fluxo de assinatura de uma prescrição inédita) antes de sair da lista de pendentes; a edição por si só não conta como revisão. Em ambos os casos, o sistema retorna automaticamente à Central do Médico, focada no painel de Prescrições Pendentes, com o contador atualizado.

Assinatura digital: A assinatura pode ocorrer de 2 modos, conforme configuração do cliente:

  • (a) Assinatura com certificado digital — exige certificado ativo vinculado ao perfil do médico
  • (b) Assinatura sem certificado — validada pela sessão do usuário logado

Navegação: O título do painel (‘Prescrições Pendentes’) é um link clicável para a tela dedicada. No hover, o título muda de cor e uma seta (→) aparece ao lado.

Justificativa de workflow: Este painel atende aos touchpoints ‘Assinar prescrições pendentes’ e ‘Confirmar que a prescrição foi revisada por um médico antes da administração ao paciente’ (Workflow 3). O botão ‘Assinar’ abre a tela de assinatura com a prescrição completa porque é responsabilidade do médico saber o que está assinando — a assinatura não pode ser um clique direto sem revisão. Os chips de urgência (vermelho/laranja) refletem que, no workflow, a prioridade é cronológica: quanto menos tempo até a aplicação, mais urgente — e essa lógica vale igualmente para prescrições pendentes de assinatura e de revisão (RN-CM-020), já que ambas representam risco crescente conforme a aplicação se aproxima. A prescrição completa é sempre exibida para revisão porque o médico precisa validar o que está confirmando, não apenas um resumo. O retorno automático à Central após assinar ou revisar reflete que o médico precisa voltar ao seu fluxo de trabalho sem navegação manual. O toggle “Meus/Todos” atende ao touchpoint ‘Ao revisar prescrições’: no workflow, o médico prioriza naturalmente seus próprios pacientes, mas precisa poder ajudar a revisar as de colegas ausentes — daí a possibilidade de alternar sem sair da tela.

Estado vazio: Quando não há prescrições pendentes, exibir ícone de check com a mensagem MSG_prescriptionNone.

Critérios de Aceitação:

  • Dado que uma prescrição possui 10 horas restantes para aplicação, então o sistema deve renderizar o chip de tempo com fundo vermelho claro (#FFEBEE) e texto em vermelho (#D32F2F), e o KPI de Alertas deve exibir o valor em vermelho.
  • Dado que uma prescrição possui 18 horas restantes, então o sistema deve renderizar o chip com fundo laranja claro (#FFF8E1) e texto laranja (#FF8F00).
  • Dado que o médico clica em “Assinar” em uma prescrição, então o sistema deve abrir a tela de assinatura com a prescrição completa para revisão.
  • Dado que o médico clica em “Assinar” na tela de assinatura, quando a assinatura é validada (via certificado ou sessão, conforme configuração), então o sistema deve exibir toast de sucesso, retornar automaticamente à Central do Médico focada no painel de Prescrições Pendentes, e o KPI de Alertas deve subtrair uma unidade.
  • Dado que o médico clica em “Assinar” na tela de assinatura e a assinatura falha, então o sistema deve exibir um toast de erro na tela de assinatura: “Falha na validação da assinatura. Verifique seu certificado ou tente novamente.”
  • Dado que uma prescrição assinada tem aplicação agendada para 1 dia (24h) ou menos a partir de agora e ainda não foi revisada, então o sistema deve marcá-la automaticamente como “a revisar” e exibi-la no painel com ação “Revisar” (RN-CM-020).
  • Dado que o médico clica em “Revisar”, então o sistema deve abrir a prescrição completa, permitindo confirmar a revisão (“Marcar como Revisada”) ou editar a prescrição.
  • Dado que o médico clica em “Marcar como Revisada”, então o sistema deve registrar o médico revisor e o timestamp, exibir toast de sucesso, remover a prescrição da lista de pendentes e retornar automaticamente à Central do Médico focada no painel de Prescrições Pendentes.
  • Dado que o médico edita a prescrição na tela de revisão e clica em “Gravar”, então o sistema deve cancelar a prescrição atual, criar uma nova versão com os itens ajustados e exigir que o médico assine essa nova versão (mesmo fluxo de assinatura), retornando automaticamente à Central do Médico focada no painel de Prescrições Pendentes após a assinatura.
  • Dado que o médico clica no título do painel, então o sistema deve navegar para a tela dedicada de Prescrições Pendentes.
  • Dado que não há prescrições pendentes, então o painel deve exibir “Nenhuma prescrição pendente”.
  • Dado que a prescrição tem protocolo “CARBO-TAXOL” no Ciclo 3, Dia 1, então o sistema deve exibir o código da prescrição como recebido do endpoint (prescriptionCode), ex: “CARBO-TAXOL C3D1”, sem remontar a string a partir de campos separados.
  • Dado que o card de prescrição exibe a data da agenda, então o formato deve ser “dd/MM HH:mm” (ex: “22/07 18:00”).
  • Dado que o painel é carregado, então o toggle “Meus/Todos” deve iniciar na posição “Meus”.
  • Dado que o médico ativa o toggle “Meus”, então o painel deve exibir apenas as prescrições a revisar em que o médico logado é o prescritor ou o médico assistente do paciente, mantendo visíveis todas as prescrições a assinar do médico logado (estas não são afetadas pelo toggle).
  • Dado que o médico ativa o toggle “Todos”, então o painel deve exibir todas as prescrições a revisar da clínica, somadas às prescrições a assinar do médico logado.

Internacionalização

Termo/Localizaçãopt-BRen-USes-419
painel-títuloPrescrições PendentesPending PrescriptionsPrescripciones Pendientes
botão-assinarAssinarSignFirmar
botão-revisarRevisarReviewRevisar
chip-T_restanteT RESTANTEST REMAININGT RESTANTES
MSG_prescriptionNoneSem prescrições pendentesNo pending prescriptionsSin prescripciones pendientes
toggle-meusMeusMineMíos
toggle-todosTodosAllTodos

2.5 Painel de Notificações (Quadrante Inferior Esquerdo)

US-CM-007 — Receber comunicações internas

Como médico, quero ver mensagens da recepção, farmácia e enfermagem em ordem de chegada, para responder solicitações e recados sem precisar acessar outra tela.

US-CM-008 — Arquivar mensagem resolvida

Como médico, quero marcar uma mensagem como resolvida ou descartá-la com um clique, para manter minha lista enxuta e o foco nas pendentes.

Descrição Funcional:

O painel de Notificações exibe mensagens internas não resolvidas, originadas por outros contextos (Recepção, Farmácia, Enfermagem, Sistema). Cada mensagem contém:

  • Ícone identificador da origem, utilizando biblioteca customizada do Gemed 2.1:
    • Recepção: ícone ‘Recepcionista’
    • Farmácia: ícone ‘Farmaceutica’
    • Enfermagem: ícone ‘Enfermeira’
    • Sistema: ícone bell de Lucide Icons (mensagens geradas automaticamente pelo sistema, ex: notificações de status, alertas de integridade, lembretes automáticos)
  • Texto da mensagem
  • Origem com timestamp e nome do remetente (ex: “Há 15 min · Sandra (Farm.)”)
  • Data limite (opcional): quem emite a comunicação pode definir uma data limite para resposta ou resolução. Quando definida, exibir a data limite no card (ex: ”⏰ Responder até 14:00”)

Mensagens não lidas: Mensagens não lidas são destacadas visualmente através de dois sinais discretos: (a) o ícone da origem aparece na cor de destaque (cor primary-pure) em vez da cor padrão (neutral-pure); (b) uma borda lateral esquerda na cor secondary-pure. Ao serem lidas pela primeira vez, o ícone reverte para a cor padrão e a borda lateral torna-se transparente. Não é utilizado negrito no texto da mensagem — a distinção visual vem exclusivamente do ícone colorido e da borda lateral. Motivador: mantendo o princípio de hierarquia visual sem negrito (RN-CM-019), o ícone colorido é suficiente para identificação periférica de novidade sem competir com a leitura do texto. Se houver múltiplas mensagens não lidas, a lista não fica visualmente pesada.

Ordenação: As mensagens são ordenadas considerando dois critérios:

  1. Data limite (quando definida) — mensagens com data limite mais próxima aparecem primeiro
  2. Ordem de chegada (LIFO) — para mensagens sem data limite, as mais recentes aparecem primeiro

Ação no card: Cada card exibe um botão “Resolvido” que arquiva a mensagem, removendo-a da lista. O contador do painel deve ser atualizado.

Ação ao clicar no card: Ao clicar no card de mensagem, o sistema abre um modal com a mensagem integral (texto completo, origem, timestamp, data limite). O modal contém dois botões:

  • “Resolvido” — arquiva a mensagem (mesma função do botão no card), removendo-a da lista e atualizando o contador.
  • “Descartado” — exclui a mensagem sem resolver (lixeira). A mensagem é removida da lista e o contador é atualizado. Motivador: o descarte permite ao médico remover mensagens informativas ou irrelevantes que não exigem ação, sem marcá-las como resolvidas.

Mensagens do sistema: Mensagens geradas automaticamente pelo sistema (notificações de status, alertas de integridade, lembretes automáticos) utilizam o ícone bell da biblioteca Lucide. Estas mensagens seguem as mesmas regras de ordenação, destaque de não lidas, ação de resolver e descartar. O remetente exibido é “Sistema” sem nome de profissional.

Padrão de internacionalização (i18n) para mensagens do sistema:

As mensagens geradas pelo sistema devem ser documentadas com suas versões em português (pt-BR), inglês (en-US) e espanhol (es-419), conforme tabela padrão abaixo:

Código da mensagempt-BRen-USes-419
SYS_PRESC_URGENTPrescrição urgente: menos de 12h para aplicação de {paciente}.Urgent prescription: less than 12h until application for {patient}.Prescripción urgente: menos de 12h para aplicación de {paciente}.
SYS_PRESC_REVIEWPrescrição de {paciente} pendente de revisão antes da aplicação.Prescription for {patient} pending review before application.Prescripción de {paciente} pendiente de revisión antes de la aplicación.
SYS_INFUSION_DELAYInfusão de {paciente} ultrapassou o tempo previsto.Infusion for {patient} exceeded expected time.Infusión de {paciente} superó el tiempo previsto.
SYS_PATIENT_CHECKIN{paciente} fez check-in na recepção.{patient} checked in at reception.{paciente} hizo check-in en recepción.
SYS_SESSION_REMINDERLembrete: {paciente} tem sessão prevista para {horario}.Reminder: {patient} has session scheduled for {time}.Recordatorio: {paciente} tiene sesión programada para {horario}.

Convenções da tabela:

  • Variáveis entre chaves {} são substituídas dinamicamente pelo sistema
  • O código da mensagem (SYS_*) é usado internamente para identificação e não é exibido ao usuário
  • Novas mensagens do sistema devem ser adicionadas a esta tabela como padrão de documentação
  • A tradução para o idioma do usuário é feita no backend; o frontend recebe a mensagem já traduzida

Navegação: O título do painel (‘Notificações’) é um link clicável para a tela dedicada de Mensagens. No hover, o título muda de cor e uma seta (→) aparece ao lado.

Justificativa de workflow: Este painel atende ao touchpoint ‘Receber mensagens da equipe’ (Workflow 4). O destaque de mensagens não lidas reflete que, no workflow, mensagens não lidas são pendências que competem com a atenção do médico. A ordenação por data limite reflete que mensagens com prazo são compromissos no workflow. O botão ‘Resolvido’ com um clique reflete que resolver é uma ação frequente e repetitiva no dia do médico. O botão ‘Descartado’ no modal reflete que algumas mensagens são puramente informativas e não exigem resolução — o médico precisa removê-las sem marcá-las como resolvidas.

Estado vazio: Quando não há mensagens não resolvidas, exibir ícone de balão vazio com a mensagem MSG_notificationNone.

Critérios de Aceitação:

  • Dado que chega uma nova mensagem da farmácia, quando os dados são atualizados, então a mensagem deve aparecer com o ícone na cor primary-pure e borda lateral esquerda na cor secondary-pure (sem negrito no texto) até ser lida pela primeira vez.
  • Dado que o médico visualiza uma mensagem não lida pela primeira vez, então o ícone deve reverter para a cor padrão (neutral-pure) e a borda lateral deve tornar-se transparente.
  • Dado que duas mensagens têm data limite definida, quando a lista é renderizada, então a mensagem com data limite mais próxima deve aparecer primeiro.
  • Dado que mensagens sem data limite existem, então elas devem ser ordenadas por ordem de chegada LIFO (mais recentes primeiro), após as mensagens com data limite.
  • Dado que o médico clica em “Resolvido” no card ou no modal, então a mensagem deve ser removida da lista e o contador do painel deve ser atualizado.
  • Dado que o médico clica no card de mensagem, então o sistema deve abrir um modal com a mensagem integral, contendo os botões “Resolvido” e “Descartado”.
  • Dado que o médico clica em “Descartado” no modal, então a mensagem deve ser excluída sem ser marcada como resolvida, removida da lista e o contador do painel deve ser atualizado.
  • Dado que o médico clica no título do painel, então o sistema deve navegar para a tela dedicada de Comunicação/Mensagens.
  • Dado que não há mensagens não resolvidas, então o painel deve exibir “Sem mensagens no momento”.

Internacionalização

Termo/Localizaçãopt-BRen-USes-419
painel-títuloNotificaçõesNotificationsNotificaciones
botão-resolvidoResolvidoResolvedResuelto
label-háHá TT agoHace T
MSG_notificationNoneSem notificações pendentesNo pending notificationsSin notificaciones pendientes

2.6 Painel de Procedimentos na Clínica (Quadrante Inferior Direito)

US-CM-009 — Monitorar procedimentos na clínica

Como médico, quero ver todos os pacientes presentes na unidade com seus status e localização, para planejar visitas e saber quem está disponível para atendimento.

US-CM-010 — Acompanhar tempo de atendimento

Como médico, quero ver o progresso do atendimento de pacientes em tratamento com barra de tempo, para saber quanto tempo já passou e se está dentro do previsto.

US-CM-011 — Filtrar meus pacientes na clínica

Como médico, quero filtrar a lista de pacientes na clínica para mostrar apenas os meus, para me concentrar nos pacientes sob minha responsabilidade.

Descrição Funcional:

O painel de Procedimentos na Clínica monitora pacientes previstos e presentes na unidade para procedimentos terapêuticos e diagnósticos (infusões, aplicações, checagens) — não inclui consultas médicas, apenas procedimentos.

Cada card de paciente contém:

  • Nome do paciente com avatar
  • Prescrição do procedimento (ex: “AC-T C2D14”, “Paclitaxel C1D8”)
  • Local na clínica (ex: “Consultório 4”, “Sala de Infusão 2”)
  • Status do procedimento (ex: em_atendimento, aguardando)
  • Horário de início do atendimento (quando aplicável)
  • Duração estimada do procedimento (quando aplicável)
  • Tags do paciente (se houver)

Barra de progresso: Pacientes com status ‘Em Atendimento’ exibem uma barra de progresso inline (50px de largura, 3px de altura) na mesma linha do nome do paciente, acompanhada da porcentagem em fonte reduzida (9px). A barra é extremamente discreta e não ocupa uma linha separada, evitando que pareça uma divisão entre cards. Se o tempo decorrido ultrapassar 100% da estimativa, a barra torna-se vermelha (cor error-pure, f44336). Motivador: a barra na linha do nome é percebida como parte do card, não como separador. O destaque visual fica reservado apenas para o estado de atraso (vermelho).

Filtro ‘Meus pacientes’: O toggle em estilo pill (não checkbox) alterna entre ‘Meus’ e ‘Todos’. O filtro ‘Meus’ está ativado por padrão. Motivador: o estilo pill é consistente com o toggle do painel de Consultas e mais discreto que um checkbox.

Navegação: O título do painel (‘Procedimentos na Clínica’) é um link clicável para a tela dedicada. No hover, o título muda de cor e uma seta (→) aparece ao lado. Ao clicar no card de paciente, o sistema abre a prescrição do procedimento (se houver). O card contém um botão separado ‘PEP’ para abrir o Prontuário Eletrônico. Se não houver prescrição associada, o clique no card abre diretamente o PEP.

Justificativa de workflow: Este painel atende aos touchpoints ‘Saber quais pacientes estão em procedimento’ e ‘Decidir se precisa intervir’ (Workflow 2). A barra de progresso discreta reflete que, no workflow de monitoramento, o médico faz checagem periférica entre atendimentos — não precisa de detalhe, só de saber se está dentro ou fora do tempo. O clique no card abrindo a prescrição (e não o PEP) reflete que, neste momento do workflow, o médico primeiro verifica o que está sendo infundido antes de decidir se precisa do prontuário completo. O botão ‘PEP’ separado reflete que o prontuário é a ação secundária neste momento.

Estado vazio: Quando não há pacientes na unidade, exibir ícone de prédio vazio com a mensagem MSG_proceduresNone.

Critérios de Aceitação:

  • Dado que um paciente está com status “Em Atendimento”, então o painel deve exibir uma barra de progresso inline na linha do nome representando o tempo decorrido vs. a duração estimada.
  • Dado que o tempo decorrido ultrapassa 100% da duração estimada, então a barra de progresso deve mudar para a cor vermelha (#F44336).
  • Dado que o toggle “Meus” está ativado, então o painel deve exibir apenas pacientes com vínculo direto com o médico logado.
  • Dado que o médico desativa o toggle “Meus”, então o painel deve exibir todos os pacientes presentes na unidade.
  • Dado que o médico clica no card de paciente, então o sistema deve abrir a prescrição do procedimento (se houver). Se não houver prescrição associada, abre diretamente o PEP.
  • Dado que o médico clica no botão de PEP no card, então o sistema deve abrir o Prontuário Eletrônico do Paciente (PEP).
  • Dado que não há pacientes na unidade, então o painel deve exibir MSG_proceduresNone.

Internacionalização

Termo/Localizaçãopt-BRen-USes-419
painel-títuloProcedimentos na clínicaProcedures at the clinicProcedimientos en la clínica
toggle-todosTodosAllTodos
toggle-meusMeusMineMios
botão-PEPPEPEHRHCe
MSG_proceduresNoneSem pacientes para o diaNo patients for todaySin pacientes para el día

2.7 Fluxos de Exceção e Estados (Consolidado)

PainelCondiçãoExibição
Qualquer painelFalha de endpointMSG_endpointFail
Qualquer painelQueda de conexãoManter últimos dados na tela + ícone discreto de “Offline” no canto do painel
KPI BarFalha de endpointExibir ”—” nos valores; demais painéis continuam operando

Estados de loading: Cada painel exibe skeleton loading independente quando os dados estão sendo carregados. A busca exibe um spinner dentro do campo de input durante a consulta à API.

Internacionalização

Termo/Localizaçãopt-BRen-USes-419
MSG_endpointFailDados temporariamente indisponíveis. Tente novamenteData temporarily unavailable. Try againDatos temporalmente no disponibles. Reintentar

2.8 Mapeamento de Componentes do Design System

ComponenteVarianteEstadosTokens aplicados
ButtonPrimary (Assinar)default, hover, disabled, loadingbg: color-primary-pure; text: color-base-pure; height: btn-height-sm; radius: radius-m
ButtonSecondary (Revisar)default, hover, disabledbg: transparent; border: color-primary-pure; text: color-primary-pure
ButtonTertiary (Resolvido)default, hoverbg: transparent; text: color-primary-pure
ChipActive (Crítico)defaultbg: color-error-light; text: color-error-dark
ChipActive (Atenção)defaultbg: color-highlight-light; text: color-highlight-dark
ChipStatus (consulta)defaultVer cores por status na RN-CM-005
BadgeError (KPI Alertas)defaultbg: color-error-pure; text: color-base-pure
BadgePrimary (contadores)defaultbg: color-primary-pure; text: color-base-pure
InputBordered (busca)default, focus, disabledborder: color-neutral-light → focus: color-neutral-dark (2px); height: input-height
AvatarSM/MD (paciente)defaultbg: color-primary-light; text: color-primary-dark
ProgressBar (atendimento)default, criticalbg track: color-neutral-lighter; bg bar: color-primary-pure → critical: color-error-pure
ToastSuccess/ErrordefaultVer Design System para tokens de toast
TooltipDefaulthoverbg: color-neutral-dark; text: color-base-pure
KPI CardBorda colorida lateraldefault, hoverborder-left: 4px solid; cores: secondary-pure (consultas), primary-pure (tratamento), highlight-pure (procedimentos), error-pure (alertas)
Panel Title LinkLink com seta no hoverdefault, hoverfont-weight: 400; color: neutral-darker → hover: secondary-dark; arrow: opacity 0 → hover: opacity 1
Toggle PillFiltro de painelactive, inactiveborder: 1px solid neutral-lighter; active: bg secondary-light, text secondary-dark; inactive: bg transparent, text neutral-pure
Progress Bar InlineBarra na linha do nomedefault, dangerwidth: 50px; height: 3px; bg track: neutral-lighter; bg fill: primary-pure → danger: error-pure; pct font: 9px
Card Highlight (Consulta)Borda colorida por statusrecepcionado, aguardando, defaultrecepcionado: border-left 3px solid secondary-pure; aguardando: border-left 3px solid ff8a80; default: sem borda
Message Icon (Lucide)Origem da mensagemunread, readunread: color primary-pure; read: color neutral-pure. Origens: concierge-bell, pill, syringe, bell

2.9 Integração com Backend

Decisão arquitetural: 1 endpoint por painel + 1 endpoint por KPI card, em vez de um único endpoint consolidado. Justificativa: paralelismo (frontend dispara chamadas simultâneas), resiliência (falha em um endpoint não bloqueia os demais — especialmente importante para os KPIs, onde um problema em um indicador não trava os outros três), granularidade de atualização.

Endpoints de KPI (1 por card):

  • [GET] /api/v1/cockpit/doctor/kpis/appointments-today
    • Função: Retornar o indicador de Consultas Hoje
    • Response 200: { "total": 6, "finished": 4, "pending": 2, "delayed": 1 }
  • [GET] /api/v1/cockpit/doctor/kpis/in-treatment
    • Função: Retornar o indicador de Em Tratamento
    • Response 200: { "inTreatment": 43, "nonAdherent": 2 }
  • [GET] /api/v1/cockpit/doctor/kpis/procedures-today
    • Função: Retornar o indicador de Procedimentos Hoje
    • Response 200: { "total": 8, "inProgress": 2, "waiting": 4, "scheduled": 2 }
  • [GET] /api/v1/cockpit/doctor/kpis/prescription-alerts
    • Função: Retornar o indicador de Alertas de Prescrição
    • Response 200: { "urgent": 3, "toReview": 1, "toSignNext7Days": 5 }
    • Detalhamento dos campos: urgent = total de prescrições pendentes de assinatura OU pendentes de revisão (RN-CM-020) com hoursRemaining < 12h (RN-CM-011). toReview = total de prescrições atualmente marcadas como “a revisar”, independente da urgência. toSignNext7Days = total de prescrições pendentes de assinatura com aplicação agendada nos próximos 7 dias. Mapeamento de BD: Seção 4.6.

Endpoints de leitura (painéis):

  • [GET] /api/v1/cockpit/doctor/appointments
    • Response 200: { "appointments": [ { "id": "uuid", "patient": { "id": "uuid", "preferredName": "", "legalName: "Maria da Silva", "photo": "url|null", "diagnosis": "Ca. Mama" }, "startTime": "08:00", "endTime": "08:30", "status": "finished", "type": "in_person", "delayMinutes": 0 } ] }
  • [GET] /api/v1/cockpit/doctor/prescriptions
    • Query params: type (opcional: to_sign | to_review) — usado pela tela dedicada de Prescrições Pendentes para filtrar por categoria. O painel do Cockpit não envia o parâmetro e recebe as duas categorias combinadas, já ordenadas por hoursRemaining crescente (RN-CM-011). reviewScope (opcional: mine | all, default mine) — controla o toggle “Meus/Todos”: afeta somente as prescrições to_review; as to_sign nunca são filtradas por este parâmetro, pois já são sempre do médico logado (RN-CM-012).
    • Response 200: { "prescriptions": [ { "id": "uuid", "patient": { "id": "uuid", "preferredName": "", "legalName": "Roberto Oliveira" }, "prescriptionCode": "CARBO-TAXOL C3D1", "scheduleDate": "2026-07-22T18:00:00Z", "hoursRemaining": 8, "type": "to_sign" }, { "id": "uuid", "patient": { "id": "uuid", "preferredName": "", "legalName": "Carlos Mendes" }, "prescriptionCode": "FOLFOX C1D1", "scheduleDate": "2026-07-22T14:00:00Z", "hoursRemaining": 18, "type": "to_review", "isPreferredReviewer": true } ] }
    • patient.preferredName/patient.legalName: mesmo padrão de appointments e procedures — o front decide qual exibir como nome principal (nome social se houver), mas ambos são enviados para o médico perceber questões de gênero/identidade antes do atendimento.
    • prescriptionCode: substitui os antigos campos protocol/cycle por um único campo já formatado (protocolo + ciclo/sessão, ex: “CARBO-TAXOL C3D1”), espelhando Prescricao.Identificacao diretamente — sem necessidade de montar a string no backend.
    • Campo exclusivo do tipo to_review (RN-CM-020): isPreferredReviewer = true quando o médico logado é o prescritor OU o médico assistente do paciente — usado pelo front para destacar visualmente que este médico é revisor preferencial, sem bloquear a ação para os demais (qualquer médico pode revisar). Os campos prescriberName/attendingDoctorName cogitados numa versão anterior foram removidos — o booleano já é suficiente para o front filtrar/destacar, sem expor nomes de terceiros nesta lista.
    • type = to_sign só retorna prescrições com aplicação agendada nos próximos 7 dias — evita inflar a lista com prescrições distantes no tempo, sem relevância imediata.
    • Mapeamento de BD: Seção 4.7.
  • (em revisão)[GET] /api/v1/cockpit/doctor/messages
    • Response 200: { "messages": [ { "id": "uuid", "sourceType": "pharmacy", "text": "Medicamento Carboplatina em falta.", "sender": "Sandra (Farm.)", "read": false, "deadline": "2026-07-22T14:00:00Z" } ] }
  • (em revisão)[GET] /api/v1/cockpit/doctor/procedures
    • Response 200: { "procedures": [ { "id": "uuid", "prescriptionId": "AC-T C1D21", "patient": { "id": "uuid", "legalName": "Roberto Oliveira", "preferredName: "", "photo": "url|null" }, "location": "Sala de Infusão 2", "status": "in_progress", "startTime": "2026-07-22T09:30:00Z", "progress": 65, "mine": true } ] }
  • [GET] /api/v1/patients/search
    • Query params: q (string, mínimo 2 caracteres)
    • Response 200: { "patients": [ { "id": "uuid", "name": "Maria da Silva", "medicalRecordNumber": "0012345", "gender": "F", "birthDate": "1972-08-15", "motherName": "Joana da Silva", "cpf": "12345678901" } ] }

Endpoints de ação:

Nota: os endpoints de ação sobre uma prescrição individual (abrir prescrição completa, assinar, marcar como revisada, editar/gravar nova versão) saíram do escopo deste documento. Eles pertencem à tela de detalhe da prescrição, que é chamada a partir deste Cockpit mas faz parte de um processo mais amplo de Prescrições (fora do domínio “Central do Médico”) e deve ser especificada em documento próprio. RN-CM-020 continua aqui porque define a regra de negócio usada no cálculo do KPI e do painel (Seções 4.6/4.7), mesmo que a execução da ação em si esteja documentada em outro lugar.

  • (em revisão)[PATCH] /api/v1/messages/{id}/resolve — Arquiva a mensagem como resolvida
  • (em revisão)[DELETE] /api/v1/messages/{id} — Exclui a mensagem sem resolver (descartar)

2.10 Conformidade SBIS (Detalhamento)

RequisitoComo a Central do Médico atende
ECF.03.11O campo de busca no header permite pesquisar pacientes por nome, CPF, data de nascimento e nome da mãe. A busca inteligente (RN-CM-004) interpreta automaticamente o tipo de entrada.
ECF.03.14O endpoint GET /api/v1/pacientes/busca retorna os campos obrigatórios: nome completo, número de prontuário, sexo, data de nascimento, nome da mãe e CPF em cada resultado.
ECF.16.01(e)Após o login, o painel de Prescrições Pendentes exibe as prescrições em aberto de responsabilidade do médico, permitindo acesso direto para assinatura ou revisão.
ECF.17.01Todos os cards de paciente identificam univocamente o paciente (nome + ID). As mensagens identificam o remetente (origem + nome do profissional). As prescrições identificam o paciente e o médico prescritor.
ECF.17.02As mensagens internas exibem timestamp de criação (criadaEm). As ações de assinatura e resolução registram data/hora automaticamente no backend.
ECF.17.04As consultas são ordenadas cronologicamente pelo horário agendado. As mensagens seguem ordenação por data limite e LIFO. As prescrições são ordenadas por urgência cronológica (tempo restante).
ECF.17.18Toda a interface, incluindo rótulos, mensagens, títulos de tela e descritivos, está em português do Brasil.
ECF.17.19Mensagens de erro e feedback ao usuário (toasts, alerts) são em linguagem não técnica. Erros técnicos do backend são tratados e traduzidos para mensagens amigáveis.

SEÇÃO 3 — PROTÓTIPO HTML

Estado: Protótipo funcional v3.12, com HTML semântico, CSS (Flexbox/Grid, tokens do Design System) e JavaScript de interação (render dinâmico dos 4 painéis, busca com debounce, modal de mensagens, toasts de feedback, filtros por toggle). Dados mockados em memória para demonstração.

Cobertura de touchpoints: O protótipo permite percorrer os touchpoints de workflow de ponta a ponta:

  • Workflow 1: ver consultas pendentes → identificar atraso (badge pulsante) → clicar no card → abrir PEP
  • Workflow 2: ver pacientes em procedimento → monitorar barra de progresso inline → clicar no card → abrir prescrição → clicar em PEP
  • Workflow 3: ver prescrições urgentes → clicar em Assinar → tela de assinatura (simulada via toast) → assinar → retorno automático à Central com contador atualizado. Clicar em Revisar → tela de edição (simulada via toast)
  • Workflow 4: ver mensagens não lidas (borda lateral colorida) → identificar data limite → clicar no card → modal com mensagem integral → Resolvido ou Descartado → contador atualizado

Pendências identificadas no protótipo em relação à Seção 2 (ver lista completa no Checklist de acompanhamento):

  • Ações de Assinar/Revisar/Resolver/Descartar estão simuladas com showToast() e manipulação do array em memória — ainda não chamam os endpoints reais (todos marcados “em revisão” na 2.9).
  • Ícones dos KPI cards e de origem das mensagens ainda são placeholders (texto/emoji), pendente substituição pela biblioteca Lucide (ver Metadados Finais, itens 4 e 5).
  • Nome do médico ainda aparece no header (Dr. Fernando Alves) — a v4.0 do documento retirou o nome do médico do cabeçalho (ver Histórico de Revisões); o protótipo precisa ser atualizado para refletir essa decisão.

Código-fonte completo:

<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gemed Onco v3.12 - Central do Médico</title>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<style>
:root {
  --font-family: 'Roboto', sans-serif;
  --color-primary-pure: #00E676;
  --color-primary-dark: #00B01C;
  --color-primary-light: #E8F5E9;
  --color-secondary-pure: #40C4FF;
  --color-secondary-dark: #0091EA;
  --color-secondary-light: #E1F5FE;
  --color-error-pure: #F44336;
  --color-error-dark: #D32F2F;
  --color-error-light: #FFEBEE;
  --color-highlight-pure: #FFC400;
  --color-highlight-dark: #FF8F00;
  --color-highlight-light: #FFF8E1;
  --color-base-pure: #FFFFFF;
  --color-base-dark: #F5F6FA;
  --color-neutral-darker: #01013B;
  --color-neutral-dark: #012856;
  --color-neutral-pure: #6B85AC;
  --color-neutral-medium: #94A7C4;
  --color-neutral-light: #BECADC;
  --color-neutral-lighter: #E5EAF0;
  --spacing-xs: 8px;
  --spacing-sm: 12px;
  --spacing-m: 16px;
  --spacing-lg: 20px;
  --spacing-xl: 24px;
  --radius-s: 4px;
  --radius-m: 8px;
  --radius-l: 12px;
  --radius-pill: 999px;
  --shadow-light: 0px 1px 4px rgba(0,0,0,0.08);
  --shadow-medium: 0px 2px 8px rgba(0,0,0,0.12);
}
* { box-sizing: border-box; margin: 0; padding: 0; font-weight: 400; }
h1, h2, h3, h4, h5, h6, strong, b { font-weight: 400; }
body {
  font-family: var(--font-family);
  background-color: var(--color-base-dark);
  color: var(--color-neutral-darker);
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.header {
  height: 64px;
  background-color: var(--color-base-pure);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--spacing-xl);
  box-shadow: var(--shadow-light);
  z-index: 100;
  flex-shrink: 0;
}
.header-left { display: flex; align-items: center; gap: var(--spacing-m); }
.logo-circle {
  width: 36px; height: 36px;
  background-color: var(--color-primary-pure);
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: white; font-size: 18px;
}
.clinic-info h1 { font-size: 14px; }
.clinic-info p { font-size: 11px; color: var(--color-neutral-pure); }
.header-center { flex: 0 1 450px; position: relative; }
.search-container { position: relative; }
.search-input {
  width: 100%; height: 40px;
  background-color: var(--color-base-dark);
  border: 1px solid var(--color-neutral-lighter);
  border-radius: var(--radius-m);
  padding: 0 12px 0 40px;
  font-size: 14px; outline: none;
  transition: border-color 0.2s;
}
.search-input:focus { border-color: var(--color-secondary-pure); }
.search-icon {
  position: absolute; left: 12px; top: 10px;
  color: var(--color-neutral-pure); font-size: 16px;
}
.search-dropdown {
  position: absolute; top: 46px; left: 0; right: 0;
  background: white; border-radius: var(--radius-m);
  box-shadow: var(--shadow-medium);
  display: none; max-height: 320px; overflow-y: auto; z-index: 200;
}
.search-hint {
  padding: var(--spacing-sm) var(--spacing-m);
  font-size: 11px; color: var(--color-neutral-medium);
  border-top: 1px solid var(--color-base-dark);
  background: #fafafa; font-style: italic;
}
.search-item {
  padding: var(--spacing-sm);
  border-bottom: 1px solid var(--color-base-dark);
  cursor: pointer;
}
.search-item:hover { background-color: var(--color-secondary-light); }
.search-item h4 { font-size: 14px; margin-bottom: 4px; }
.search-item p { font-size: 11px; color: var(--color-neutral-pure); }
.header-right { display: flex; align-items: center; gap: var(--spacing-m); }
.doctor-avatar {
  width: 40px; height: 40px;
  background-color: var(--color-neutral-dark);
  color: white; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.doctor-info { text-align: right; }
.doctor-info h3 { font-size: 14px; }
.doctor-info p { font-size: 11px; color: var(--color-neutral-pure); }
.kpi-bar {
  min-height: 96px;
  display: flex; gap: var(--spacing-m);
  padding: var(--spacing-sm) var(--spacing-xl);
  flex-shrink: 0;
}
.kpi-card {
  flex: 1; background: white;
  border-radius: var(--radius-m);
  padding: 10px var(--spacing-m);
  box-shadow: var(--shadow-light);
  cursor: pointer;
  transition: transform 0.2s, box-shadow 0.2s;
  display: flex; align-items: center; gap: var(--spacing-sm);
  overflow: hidden;
  border-left: 4px solid var(--color-neutral-light);
}
.kpi-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-medium); }
.kpi-card.kpi-consultas { border-left-color: var(--color-secondary-pure); }
.kpi-card.kpi-tratamento { border-left-color: var(--color-primary-pure); }
.kpi-card.kpi-procedimentos { border-left-color: var(--color-highlight-pure); }
.kpi-card.kpi-alertas { border-left-color: var(--color-error-pure); }
.kpi-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.kpi-title { font-size: 11px; text-transform: uppercase; color: var(--color-neutral-pure); letter-spacing: 0.5px; }
.kpi-value { font-size: 22px; line-height: 1.2; }
.kpi-value.alert { color: var(--color-error-pure); }
.kpi-subtext { font-size: 11px; color: var(--color-neutral-medium); line-height: 1.3; }
.kpi-icon-placeholder {
  width: 36px; height: 36px;
  border-radius: var(--radius-m);
  background: var(--color-base-dark);
  border: 1px dashed var(--color-neutral-light);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; font-size: 10px; color: var(--color-neutral-light);
}
.dashboard-grid {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: var(--spacing-m);
  padding: 0 var(--spacing-xl) var(--spacing-xl);
  overflow: hidden;
  min-height: 0;
}
.panel {
  background: white; border-radius: var(--radius-m);
  display: flex; flex-direction: column;
  overflow: hidden; box-shadow: var(--shadow-light);
  min-height: 0;
}
.panel-header {
  padding: var(--spacing-sm) var(--spacing-m);
  background-color: var(--color-base-dark);
  border-bottom: 1px solid var(--color-neutral-lighter);
  display: flex; align-items: center; justify-content: space-between;
  flex-shrink: 0;
}
.panel-title-group { display: flex; align-items: center; gap: var(--spacing-xs); }
.panel-title-link {
  font-size: 15px;
  color: var(--color-neutral-darker);
  text-decoration: none; cursor: pointer;
  display: flex; align-items: center; gap: 4px;
  transition: color 0.2s;
}
.panel-title-link:hover { color: var(--color-secondary-dark); }
.panel-title-arrow {
  font-size: 14px; opacity: 0;
  transition: opacity 0.2s, transform 0.2s;
  transform: translateX(-4px);
}
.panel-title-link:hover .panel-title-arrow { opacity: 1; transform: translateX(0); }
.badge-count {
  background: var(--color-neutral-lighter);
  padding: 2px 8px; border-radius: var(--radius-pill);
  font-size: 12px;
}
.panel-actions { display: flex; align-items: center; gap: var(--spacing-sm); }
.toggle-group {
  display: flex; background: white;
  padding: 2px; border-radius: var(--radius-pill);
  border: 1px solid var(--color-neutral-lighter);
}
.toggle-btn {
  padding: 3px 10px; font-size: 11px;
  border: none; background: transparent;
  cursor: pointer; border-radius: var(--radius-pill);
  color: var(--color-neutral-pure);
  transition: all 0.2s;
}
.toggle-btn.active { background: var(--color-secondary-light); color: var(--color-secondary-dark); }
.panel-body { flex: 1; overflow-y: auto; padding: var(--spacing-sm); min-height: 0; }
.card-item {
  border: 1px solid var(--color-base-dark);
  border-radius: var(--radius-m);
  padding: var(--spacing-sm);
  margin-bottom: var(--spacing-xs);
  display: flex; align-items: flex-start; gap: var(--spacing-sm);
  transition: background 0.2s; cursor: pointer;
  position: relative;
}
.card-item:hover { background-color: var(--color-base-dark); }
.card-item.finalized { opacity: 0.55; background-color: #fafafa; }
.card-item.highlight-recepcionado { border-left: 3px solid var(--color-secondary-pure); }
.card-item.highlight-aguardando { border-left: 3px solid #FF8A80; }
.avatar-circle {
  width: 36px; height: 36px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: white; font-size: 13px; flex-shrink: 0;
}
.card-content { flex: 1; min-width: 0; }
.card-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
.card-name { font-size: 14px; }
.card-time { font-size: 12px; color: var(--color-neutral-pure); }
.card-meta { font-size: 12px; color: var(--color-neutral-medium); display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.chip {
  padding: 2px 8px; border-radius: var(--radius-pill);
  font-size: 10px; text-transform: uppercase; white-space: nowrap;
}
.chip-agendado { background: #FFE0B3; color: #855D00; }
.chip-recepcionado { background: #B7E3FF; color: #004D7A; }
.chip-aguardandorecepcao { background: #FFC5C1; color: #8B0000; }
.chip-ematendimento { background: #D1DF9D; color: #3E4D00; }
.chip-finalizado { background: #E5EAF0; color: #6B85AC; }
.chip-urgente { background: var(--color-error-light); color: var(--color-error-dark); }
.chip-atencao { background: var(--color-highlight-light); color: var(--color-highlight-dark); }
.chip-vip { background: var(--color-secondary-light); color: var(--color-secondary-dark); }
.chip-1aconsulta { background: #EDE7F6; color: #4527A0; }
.badge-atraso {
  background: var(--color-error-pure); color: white;
  font-size: 10px; padding: 2px 6px; border-radius: var(--radius-s);
  animation: pulse 2s infinite; white-space: nowrap;
}
@keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } }
.progress-name-inline {
  display: flex; align-items: center; gap: 4px;
  flex: 0 0 auto;
}
.progress-bar-mini {
  width: 50px; height: 3px;
  background: var(--color-neutral-lighter);
  border-radius: 2px; overflow: hidden;
}
.progress-fill { height: 100%; background: var(--color-primary-pure); border-radius: 2px; transition: width 0.5s; }
.progress-fill.danger { background: var(--color-error-pure); }
.progress-pct { font-size: 9px; color: var(--color-neutral-medium); white-space: nowrap; }
.btn {
  padding: 6px 12px; border-radius: var(--radius-s);
  font-size: 12px; cursor: pointer;
  border: none; transition: filter 0.2s; white-space: nowrap;
}
.btn-primary { background: var(--color-primary-pure); color: white; }
.btn-secondary { background: var(--color-secondary-light); color: var(--color-secondary-dark); }
.btn-tertiary { background: transparent; color: var(--color-neutral-pure); border: 1px solid var(--color-neutral-lighter); }
.btn-danger { background: transparent; color: var(--color-error-dark); border: 1px solid var(--color-error-light); }
.btn:hover { filter: brightness(0.9); }
.msg-item { border-left: 4px solid transparent; }
.msg-unread { border-left-color: var(--color-secondary-pure); }
.msg-icon { font-size: 20px; flex-shrink: 0; color: var(--color-neutral-pure); }
.msg-unread .msg-icon { color: var(--color-primary-pure); }
#toast-container { position: fixed; bottom: 24px; right: 24px; z-index: 1000; }
.toast {
  background: var(--color-neutral-darker); color: white;
  padding: 12px 24px; border-radius: var(--radius-m);
  margin-top: 8px; font-size: 14px;
  box-shadow: var(--shadow-medium);
  animation: slideIn 0.3s ease-out;
}
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
.empty-state {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  height: 100%; color: var(--color-neutral-medium); text-align: center;
}
.empty-icon { font-size: 48px; margin-bottom: 16px; opacity: 0.3; }
.panel-body::-webkit-scrollbar { width: 6px; }
.panel-body::-webkit-scrollbar-track { background: transparent; }
.panel-body::-webkit-scrollbar-thumb { background: var(--color-neutral-light); border-radius: 3px; }
.modal-overlay {
  position: fixed; top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(0,0,0,0.4);
  display: none; align-items: center; justify-content: center;
  z-index: 500;
}
.modal-overlay.show { display: flex; }
.modal-box {
  background: white; border-radius: var(--radius-l);
  padding: var(--spacing-xl);
  max-width: 500px; width: 90%;
  box-shadow: var(--shadow-medium);
  display: flex; flex-direction: column; gap: var(--spacing-m);
}
.modal-title { font-size: 16px; color: var(--color-neutral-darker); }
.modal-body { font-size: 14px; color: var(--color-neutral-dark); line-height: 1.5; }
.modal-meta { font-size: 12px; color: var(--color-neutral-pure); }
.modal-actions { display: flex; gap: var(--spacing-sm); justify-content: flex-end; }
@media (max-width: 1024px) {
  .dashboard-grid { grid-template-columns: 1fr; overflow-y: auto; }
  body { overflow-y: auto; }
}
</style>
</head>
<body>
 
<header class="header">
  <div class="header-left">
    <div class="logo-circle">G</div>
    <div class="clinic-info">
      <h1>Hospital São Lucas</h1>
      <p>Unidade Paraíso · Consultórios</p>
    </div>
  </div>
  <div class="header-center">
    <div class="search-container">
      <span class="search-icon">🔍</span>
      <input type="text" class="search-input" id="main-search" placeholder="Procurar paciente…">
      <div class="search-dropdown" id="search-results"></div>
    </div>
  </div>
  <div class="header-right">
    <div class="doctor-info">
      <h3>Dr. Fernando Alves</h3>
      <p>CRM 123456-SP · Oncologia</p>
    </div>
    <div class="doctor-avatar">FA</div>
  </div>
</header>
 
<div class="kpi-bar">
  <div class="kpi-card kpi-consultas" onclick="showToast('Navegando para Agenda de Consultas…')">
    <div class="kpi-text">
      <span class="kpi-title">Consultas Hoje</span>
      <span class="kpi-value">4/6</span>
      <span class="kpi-subtext">2 pendentes · 1 atrasada</span>
    </div>
    <div class="kpi-icon-placeholder">ícone</div>
  </div>
  <div class="kpi-card kpi-tratamento" onclick="showToast('Navegando para Pacientes do Médico…')">
    <div class="kpi-text">
      <span class="kpi-title">Em Tratamento</span>
      <span class="kpi-value">43</span>
      <span class="kpi-subtext">2 não aderentes</span>
    </div>
    <div class="kpi-icon-placeholder">ícone</div>
  </div>
  <div class="kpi-card kpi-procedimentos" onclick="showToast('Navegando para Procedimentos na Clínica…')">
    <div class="kpi-text">
      <span class="kpi-title">Procedimentos Hoje</span>
      <span class="kpi-value">8</span>
      <span class="kpi-subtext">2 em atendimento · 4 aguardando · 2 previstos</span>
    </div>
    <div class="kpi-icon-placeholder">ícone</div>
  </div>
  <div class="kpi-card kpi-alertas" onclick="showToast('Navegando para Prescrições Pendentes…')">
    <div class="kpi-text">
      <span class="kpi-title">Alertas de Prescrição</span>
      <span class="kpi-value alert" id="kpi-alert-count">3</span>
      <span class="kpi-subtext">1 p/ revisar · 5 p/ assinar (próx. 7 dias)</span>
    </div>
    <div class="kpi-icon-placeholder">ícone</div>
  </div>
</div>
 
<main class="dashboard-grid">
 
  <section class="panel">
    <div class="panel-header">
      <div class="panel-title-group">
        <a class="panel-title-link" onclick="showToast('Abrindo Agenda do Médico…')">Consultas <span class="panel-title-arrow">→</span></a>
        <span class="badge-count" id="count-consultas">6</span>
      </div>
      <div class="panel-actions">
        <div class="toggle-group">
          <button class="toggle-btn" onclick="filterConsultas('all', this)">Todas</button>
          <button class="toggle-btn active" onclick="filterConsultas('pending', this)">Pendentes</button>
        </div>
      </div>
    </div>
    <div class="panel-body" id="list-consultas"></div>
  </section>
 
  <section class="panel">
    <div class="panel-header">
      <div class="panel-title-group">
        <a class="panel-title-link" onclick="showToast('Abrindo Prescrições Pendentes…')">Prescrições Pendentes <span class="panel-title-arrow">→</span></a>
        <span class="badge-count" id="count-prescricoes">3</span>
      </div>
      <div class="panel-actions">
        <div class="toggle-group">
          <button class="toggle-btn active" onclick="filterPrescricoes('mine', this)">Meus</button>
          <button class="toggle-btn" onclick="filterPrescricoes('all', this)">Todos</button>
        </div>
      </div>
    </div>
    <div class="panel-body" id="list-prescricoes"></div>
  </section>
 
  <section class="panel">
    <div class="panel-header">
      <div class="panel-title-group">
        <a class="panel-title-link" onclick="showToast('Abrindo Mensagens…')">Comunicação <span class="panel-title-arrow">→</span></a>
        <span class="badge-count" id="count-mensagens">4</span>
      </div>
    </div>
    <div class="panel-body" id="list-mensagens"></div>
  </section>
 
  <section class="panel">
    <div class="panel-header">
      <div class="panel-title-group">
        <a class="panel-title-link" onclick="showToast('Abrindo Procedimentos na Clínica…')">Procedimentos na Clínica <span class="panel-title-arrow">→</span></a>
        <span class="badge-count" id="count-clinica">4</span>
      </div>
      <div class="panel-actions">
        <div class="toggle-group">
          <button class="toggle-btn active" onclick="toggleMeusPacientes(true, this)">Meus</button>
          <button class="toggle-btn" onclick="toggleMeusPacientes(false, this)">Todos</button>
        </div>
      </div>
    </div>
    <div class="panel-body" id="list-clinica"></div>
  </section>
 
</main>
 
<div id="toast-container"></div>
 
<div class="modal-overlay" id="msg-modal-overlay">
  <div class="modal-box">
    <div class="modal-title" id="msg-modal-title"></div>
    <div class="modal-meta" id="msg-modal-meta"></div>
    <div class="modal-body" id="msg-modal-body"></div>
    <div class="modal-meta" id="msg-modal-deadline"></div>
    <div class="modal-actions">
      <button class="btn btn-danger" onclick="discardMessage()">Descartado</button>
      <button class="btn btn-primary" onclick="resolveMessageFromModal()">Resolvido</button>
    </div>
  </div>
</div>
 
<script>
var pacientesMock = [
  { id: 1, nome: "Maria da Silva", prontuario: "12345", cpf: "123.456.789-00", mae: "Josefa Silva", nasc: "12/05/1965", sexo: "F" },
  { id: 2, nome: "Roberto Oliveira", prontuario: "67890", cpf: "987.654.321-11", mae: "Maria Oliveira", nasc: "20/10/1970", sexo: "M" },
  { id: 3, nome: "Ana Paula Costa", prontuario: "11223", cpf: "444.555.666-77", mae: "Lucia Costa", nasc: "05/01/1985", sexo: "F" },
  { id: 4, nome: "Carlos Mendes", prontuario: "44556", cpf: "888.999.000-11", mae: "Beatriz Mendes", nasc: "15/08/1958", sexo: "M" },
  { id: 5, nome: "Aymore Lima", prontuario: "77889", cpf: "222.333.444-55", mae: "Helena Lima", nasc: "03/03/1972", sexo: "M" }
];
 
var consultas = [
  { id: 1, hora: "08:00 - 08:30", nome: "Maria da Silva", diag: "Ca. Mama", tipo: "Presencial", tags: ["vip"], status: "Finalizado", color: "#9679E1" },
  { id: 2, hora: "08:30 - 09:00", nome: "Roberto Oliveira", diag: "Ca. Prostata", tipo: "Presencial", tags: [], status: "Recepcionado", color: "#40C4FF" },
  { id: 3, hora: "09:00 - 09:30", nome: "Ana Paula Costa", diag: "Ca. Mama", tipo: "Teleatendimento", tags: ["1aconsulta"], status: "Agendado", atraso: "15min", color: "#FFC400" },
  { id: 4, hora: "09:30 - 10:00", nome: "Carlos Mendes", diag: "Ca. Colon", tipo: "Presencial", tags: [], status: "Aguardando Recepcao", color: "#FF8A80" },
  { id: 5, hora: "10:00 - 10:30", nome: "Joana Ferreira", diag: "Ca. Pulmao", tipo: "Presencial", tags: [], status: "Agendado", color: "#FFC400" },
  { id: 6, hora: "10:30 - 11:00", nome: "Pedro Santos", diag: "", tipo: "Presencial", tags: ["1aconsulta"], status: "Em Atendimento", color: "#00E676" }
];
 
var prescricoes = [
  { id: 1, paciente: "Roberto Oliveira", prescricaoCodigo: "CARBO-TAXOL C3D1", dataAgenda: "22/07 18:00", tempo: "8h restantes", urgencia: "urgente", acao: "Assinar" },
  { id: 2, paciente: "Maria da Silva", prescricaoCodigo: "AC-T C2D1", dataAgenda: "23/07 09:00", tempo: "18h restantes", urgencia: "atencao", acao: "Assinar" },
  { id: 3, paciente: "Carlos Mendes", prescricaoCodigo: "FOLFOX C1D1", dataAgenda: "22/07 14:00", tempo: "18h restantes", urgencia: "atencao", acao: "Revisar", meu: true, obs: "Revisao automatica: aplicacao em menos de 24h. Voce e revisor preferencial." },
  { id: 4, paciente: "Aymore Lima", prescricaoCodigo: "FOLFIRI C4D1", dataAgenda: "23/07 07:00", tempo: "23h restantes", urgencia: "atencao", acao: "Revisar", meu: false, obs: "Revisao automatica: aplicacao em menos de 24h." }
];
 
var mensagens = [
  { id: 1, origem: "sistema", texto: "Prescricao urgente: menos de 12h para aplicacao de Roberto Oliveira.", meta: "Ha 10 min - Sistema", limite: "14:00", unread: true },
  { id: 2, origem: "farmacia", texto: "Medicamento Carboplatina em falta para o ciclo de amanha.", meta: "Ha 15 min - Sandra (Farm.)", limite: "14:00", unread: true },
  { id: 3, origem: "enfermagem", texto: "Paciente Roberto Oliveira relatou nausea durante a infusao.", meta: "Ha 32 min - Carla (Enf.)", unread: true },
  { id: 4, origem: "recepcao", texto: "Resultado de exame de imagem recebido para Ana Paula Costa.", meta: "Ha 1h - Recepcao", unread: false }
];
 
var clinica = [
  { id: 1, nome: "Roberto Oliveira", local: "Sala de Infusao 2", status: "Em Atendimento", inicio: "09:30", progresso: 65, tags: ["Quimioterapia"], meu: true },
  { id: 2, nome: "Maria da Silva", local: "Sala de Infusao 1", status: "Em Atendimento", inicio: "09:00", progresso: 110, tags: ["vip"], meu: true },
  { id: 3, nome: "Ana Paula Costa", local: "Consultorio 3", status: "Aguardando", inicio: "-", progresso: 0, tags: [], meu: true },
  { id: 4, nome: "Pedro Santos", local: "Consultorio 4", status: "Em Atendimento", inicio: "10:30", progresso: 30, tags: [], meu: true },
  { id: 5, nome: "Joao Silva", local: "Sala de Infusao 3", status: "Em Atendimento", inicio: "08:00", progresso: 80, tags: [], meu: false },
  { id: 6, nome: "Fernanda Lima", local: "Sala de Repouso 1", status: "Aguardando", inicio: "-", progresso: 0, tags: [], meu: false },
  { id: 7, nome: "Jose Pereira", local: "Consultorio 2", status: "Em Atendimento", inicio: "09:45", progresso: 50, tags: [], meu: false },
  { id: 8, nome: "Lucia Santos", local: "Sala de Infusao 4", status: "Em Atendimento", inicio: "10:00", progresso: 95, tags: [], meu: false }
];
 
var currentMsgId = null;
 
function renderConsultas(filter) {
  var container = document.getElementById('list-consultas');
  var countEl = document.getElementById('count-consultas');
  var filtered = filter === 'pending' ? consultas.filter(function(c) { return c.status !== 'Finalizado'; }) : consultas;
  countEl.innerText = filtered.length;
  container.innerHTML = filtered.map(function(c) {
    var initials = c.nome.split(' ').map(function(n) { return n[0]; }).join('').substring(0, 2);
    var tagsHtml = c.tags.map(function(t) {
      var label = t === '1aconsulta' ? '1a Consulta' : t.toUpperCase();
      return '<span class="chip chip-' + t + '">' + label + '</span>';
    }).join('');
    var statusClass = c.status.toLowerCase().replace(/\s/g, '').replace(/[^a-z]/g, '');
    var highlightClass = '';
    if (c.status === 'Recepcionado') highlightClass = 'highlight-recepcionado';
    else if (c.status === 'Aguardando Recepcao') highlightClass = 'highlight-aguardando';
    return '<div class="card-item ' + (c.status === 'Finalizado' ? 'finalized' : '') + ' ' + highlightClass + '" onclick="showToast(\'Abrindo PEP: ' + c.nome + '\')">' +
      '<div class="avatar-circle" style="background-color: ' + c.color + '">' + initials + '</div>' +
      '<div class="card-content">' +
        '<div class="card-row"><span class="card-name">' + c.nome + '</span><span class="card-time">' + c.hora + '</span></div>' +
        '<div class="card-row">' +
          '<div class="card-meta">' +
            (c.diag ? '<span>' + c.diag + '</span><span>-</span>' : '') +
            '<span>' + c.tipo + '</span>' + tagsHtml +
          '</div>' +
          '<div style="display: flex; gap: 6px; align-items: center;">' +
            (c.atraso ? '<span class="badge-atraso">Atrasado ' + c.atraso + '</span>' : '') +
            '<span class="chip chip-' + statusClass + '">' + c.status + '</span>' +
          '</div>' +
        '</div>' +
      '</div>' +
    '</div>';
  }).join('');
}
 
var currentPrescricaoScope = 'mine';
 
function renderPrescricoes(scope) {
  currentPrescricaoScope = scope || currentPrescricaoScope;
  scope = currentPrescricaoScope;
  var container = document.getElementById('list-prescricoes');
  var countEl = document.getElementById('count-prescricoes');
  var kpiEl = document.getElementById('kpi-alert-count');
  var urgentCount = prescricoes.filter(function(p) { return p.urgencia === 'urgente'; }).length;
  kpiEl.innerText = urgentCount;
  kpiEl.className = urgentCount > 0 ? 'kpi-value alert' : 'kpi-value';
  // Toggle Meus/Todos afeta somente os itens "Revisar" — os itens "Assinar" ja sao sempre do medico logado (RN-CM-012)
  var filtered = prescricoes.filter(function(p) {
    if (p.acao === 'Assinar') return true;
    return scope === 'all' ? true : p.meu === true;
  });
  countEl.innerText = filtered.length;
  if (filtered.length === 0) {
    container.innerHTML = '<div class="empty-state"><div class="empty-icon">✅</div><p>Nenhuma prescricao pendente</p></div>';
    return;
  }
  container.innerHTML = filtered.map(function(p) {
    return '<div class="card-item">' +
      '<div class="card-content">' +
        '<div class="card-row"><span class="card-name">' + p.paciente + '</span><span class="chip chip-' + p.urgencia + '">' + p.tempo + '</span></div>' +
        '<div class="card-row">' +
          '<div class="card-meta"><span>' + p.prescricaoCodigo + '</span><span>-</span><span>Agenda: ' + p.dataAgenda + '</span></div>' +
          '<button class="btn ' + (p.acao === 'Assinar' ? 'btn-primary' : 'btn-secondary') + '" onclick="handlePrescricao(' + p.id + ', \'' + p.acao + '\', event)">' + p.acao + '</button>' +
        '</div>' +
        (p.obs ? '<p style="font-size: 11px; font-style: italic; color: var(--color-neutral-pure); margin-top: 6px;">' + p.obs + '</p>' : '') +
      '</div>' +
    '</div>';
  }).join('');
}
 
function filterPrescricoes(scope, btn) {
  document.querySelectorAll('.panel:nth-child(2) .toggle-btn').forEach(function(b) { b.classList.remove('active'); });
  btn.classList.add('active');
  renderPrescricoes(scope);
}
 
function renderMensagens() {
  var container = document.getElementById('list-mensagens');
  var countEl = document.getElementById('count-mensagens');
  countEl.innerText = mensagens.length;
  var icons = { farmacia: '💊', enfermagem: '💉', recepcao: '🔔', sistema: '🔔' };
  var sorted = mensagens.slice().sort(function(a, b) {
    if (a.limite && !b.limite) return -1;
    if (!a.limite && b.limite) return 1;
    return b.id - a.id;
  });
  container.innerHTML = sorted.map(function(m) {
    return '<div class="card-item msg-item ' + (m.unread ? 'msg-unread' : '') + '" onclick="openMsgModal(' + m.id + ')">' +
      '<div class="msg-icon">' + (icons[m.origem] || '📨') + '</div>' +
      '<div class="card-content">' +
        '<p style="font-size: 13px; margin-bottom: 4px;">' + m.texto + '</p>' +
        '<div class="card-row">' +
          '<span class="card-meta">' + m.meta + '</span>' +
          (m.limite ? '<span style="font-size: 11px; color: var(--color-highlight-dark);">⏰ ' + m.limite + '</span>' : '') +
          '<button class="btn btn-tertiary" onclick="resolveMsg(' + m.id + ', event)">Resolvido</button>' +
        '</div>' +
      '</div>' +
    '</div>';
  }).join('');
}
 
function renderClinica(onlyMe) {
  var container = document.getElementById('list-clinica');
  var countEl = document.getElementById('count-clinica');
  var filtered = onlyMe ? clinica.filter(function(c) { return c.meu; }) : clinica;
  countEl.innerText = filtered.length;
  container.innerHTML = filtered.map(function(c) {
    var initials = c.nome.split(' ').map(function(n) { return n[0]; }).join('').substring(0, 2);
    var progressHtml = '';
    if (c.progresso > 0) {
      progressHtml = '<div class="progress-name-inline">' +
        '<div class="progress-bar-mini">' +
          '<div class="progress-fill ' + (c.progresso > 100 ? 'danger' : '') + '" style="width: ' + Math.min(c.progresso, 100) + '%"></div>' +
        '</div>' +
        '<span class="progress-pct">' + c.progresso + '%</span>' +
      '</div>';
    }
    return '<div class="card-item" onclick="showToast(\'Abrindo prescricao: ' + c.nome + '\')">' +
      '<div class="avatar-circle" style="background-color: var(--color-neutral-light); color: var(--color-neutral-dark);">' + initials + '</div>' +
      '<div class="card-content">' +
        '<div class="card-row">' +
          '<span class="card-name">' + c.nome + '</span>' +
          progressHtml +
          '<button class="btn btn-secondary" style="height: 24px; padding: 0 8px; font-size: 11px;" onclick="showToast(\'Abrindo PEP: ' + c.nome + '\'); event.stopPropagation();">PEP</button>' +
        '</div>' +
        '<div class="card-meta">' +
          '<span>' + c.local + '</span><span>-</span>' +
          '<span>' + c.status + (c.inicio !== '-' ? ' (' + c.inicio + ')' : '') + '</span>' +
        '</div>' +
      '</div>' +
    '</div>';
  }).join('');
}
 
function filterConsultas(type, btn) {
  document.querySelectorAll('.panel:nth-child(1) .toggle-btn').forEach(function(b) { b.classList.remove('active'); });
  btn.classList.add('active');
  renderConsultas(type);
}
 
function toggleMeusPacientes(onlyMe, btn) {
  document.querySelectorAll('.panel:nth-child(4) .toggle-btn').forEach(function(b) { b.classList.remove('active'); });
  btn.classList.add('active');
  renderClinica(onlyMe);
}
 
function handlePrescricao(id, acao, e) {
  e.stopPropagation();
  if (acao === 'Assinar') {
    showToast('Abrindo tela de assinatura...');
    setTimeout(function() {
      prescricoes = prescricoes.filter(function(p) { return p.id !== id; });
      showToast('Prescricao assinada com sucesso. Retornando a Central...');
      renderPrescricoes();
    }, 2000);
  } else {
    showToast('Abrindo tela de edicao para revisao...');
  }
}
 
function resolveMsg(id, e) {
  e.stopPropagation();
  mensagens = mensagens.filter(function(m) { return m.id !== id; });
  renderMensagens();
  showToast('Mensagem arquivada');
}
 
function openMsgModal(id) {
  var msg = mensagens.find(function(m) { return m.id === id; });
  if (!msg) return;
  currentMsgId = id;
  if (msg.unread) {
    msg.unread = false;
    renderMensagens();
  }
  var icons = { farmacia: 'Farmacia', enfermagem: 'Enfermagem', recepcao: 'Recepcao', sistema: 'Sistema' };
  document.getElementById('msg-modal-title').innerText = icons[msg.origem] || 'Mensagem';
  document.getElementById('msg-modal-meta').innerText = msg.meta;
  document.getElementById('msg-modal-body').innerText = msg.texto;
  document.getElementById('msg-modal-deadline').innerText = msg.limite ? '⏰ Responder ate ' + msg.limite : '';
  document.getElementById('msg-modal-overlay').classList.add('show');
}
 
function resolveMessageFromModal() {
  mensagens = mensagens.filter(function(m) { return m.id !== currentMsgId; });
  renderMensagens();
  document.getElementById('msg-modal-overlay').classList.remove('show');
  showToast('Mensagem arquivada');
}
 
function discardMessage() {
  mensagens = mensagens.filter(function(m) { return m.id !== currentMsgId; });
  renderMensagens();
  document.getElementById('msg-modal-overlay').classList.remove('show');
  showToast('Mensagem descartada');
}
 
function initSearch() {
  var input = document.getElementById('main-search');
  var dropdown = document.getElementById('search-results');
  var timeout = null;
  input.addEventListener('input', function(e) {
    var val = e.target.value;
    clearTimeout(timeout);
    if (val.length === 0) {
      dropdown.style.display = 'none';
      return;
    }
    if (val.length === 1) {
      dropdown.innerHTML = '<div class="search-hint">Digite pelo menos 2 caracteres para iniciar a busca.</div>';
      dropdown.style.display = 'block';
      return;
    }
    timeout = setTimeout(function() {
      var valLower = val.toLowerCase();
      var results = pacientesMock.filter(function(p) {
        return p.nome.toLowerCase().indexOf(valLower) !== -1 ||
               p.cpf.indexOf(val) !== -1 ||
               p.prontuario.indexOf(val) !== -1 ||
               p.mae.toLowerCase().indexOf(valLower) !== -1;
      });
      var hint = '<div class="search-hint">Digite parte do nome, CPF, data de nascimento ou nome da mae para filtrar</div>';
      if (results.length > 0) {
        dropdown.innerHTML = results.map(function(p) {
          return '<div class="search-item" onclick="showToast(\'Abrindo PEP: ' + p.nome + '\'); document.getElementById(\'search-results\').style.display=\'none\';">' +
            '<h4>' + p.nome + '</h4>' +
            '<p>Prontuario: ' + p.prontuario + ' - Sexo: ' + p.sexo + ' - Nasc: ' + p.nasc + ' - Mae: ' + p.mae + ' - CPF: ' + p.cpf + '</p>' +
          '</div>';
        }).join('') + hint;
      } else {
        dropdown.innerHTML = '<div class="search-item"><p>Nenhum paciente encontrado com os dados informados.</p></div>' + hint;
      }
      dropdown.style.display = 'block';
    }, 1000);
  });
  document.addEventListener('click', function(e) {
    if (!e.target.closest('.search-container')) {
      dropdown.style.display = 'none';
    }
  });
  document.getElementById('msg-modal-overlay').addEventListener('click', function(e) {
    if (e.target === this) {
      this.classList.remove('show');
    }
  });
}
 
function showToast(msg) {
  var container = document.getElementById('toast-container');
  var toast = document.createElement('div');
  toast.className = 'toast';
  toast.innerText = msg;
  container.appendChild(toast);
  setTimeout(function() { toast.remove(); }, 3000);
}
 
window.onload = function() {
  renderConsultas('pending');
  renderPrescricoes('mine');
  renderMensagens();
  renderClinica(true);
  initSearch();
};
</script>
</body>
</html>

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
delayMinutesintAgenda.DhAgendaIniUTC(no fuso da clínica)-Now(no fuso da clínica)Se o valor for negativo, retorna 0
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.diagnosisstringPEPDiagnostico.Diagnostico para Tipo = ‘O’ e PEP.IdPacientepode haver mais de um

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, Agenda.DhAgendaIniUTC(no fuso da clínica)-Now(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": "Roberto Oliveira",
              "legalName: "Alberto Roberto" 
            }, 
        "location": "Sala de Infusão 2", 
        "status": "in_progress", 
        "startTime": "2026-07-22T09:30:00Z", 
        "progress": 65, 
        "mine": true 
      } 
    ]
}`

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

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()=preparation OR administering))
waitingintcount(ProcedureStatus()=waiting OR checked)
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 que estão em descompasso com o planejado

  • refere-se aos pacientes que tem plano terapêutico (PEPProjetoTerapeutico)
  • quem não tem, não é adicionado na contagem
  • em cada PEPProjetoTerapeuticoProtocolo do plano terapêutico, calcular:
    • Se tem IdPrescricao,
      • verificar se a data de C1D1 está mais do que 5 dias diferente da prevista
      • verificar se a prescricao passada não foi realizada (Prescricao.Situacao = P, G, A, C)
      • verificar se os intervalos entre as sessões das prescrições estão de acordo com o programado (Prescricao.Sessao = Prescricao.Data - Prescricao.Data_da_prescrição_anterior)

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 = 'M' é 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:

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 = 'M')
        OR p.IdChProfissionalAssinou IS NOT NULL                 -- compatibilidade com legado
      )                                                          -- já assinada, por um dos dois caminhos
  AND a.DhAgendaIniUTC <= DATEADD(HOUR, 24, SYSDATETIMEOFFSET())  -- a 1 dia ou menos da aplicação
  AND NOT EXISTS (
        SELECT 1 FROM PrescricaoAssinatura pa2
        WHERE pa2.IdPrescricao = p.IdPrescricao
          AND pa2.TipoAssinatura IN ('M','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.

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 = 'M' 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 = 'M' 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
MAssinatura 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 = 'M' 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 M/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 = 'M' 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 D-1, 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

Seção 4.8 removida (v4.12): o mapeamento de BD dos endpoints de ação (GET /prescriptions/{id}, POST /sign, PATCH /review, PUT /prescriptions/{id}) saiu deste documento junto com os endpoints correspondentes na Seção 2.9 — pertence ao processo de Prescrições, documentado à parte. Fica registrado aqui, para quem for escrever aquele documento, que o esquema atual já suporta assinatura e revisão via PrescricaoAssinatura.TipoAssinatura (M/R, ver domínio na Seção 4.7) e versionamento via PrescricaoVersao + novo registro em Prescricao — não é necessária nenhuma tabela nova para isso.

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 (concierge-bell, pill, syringe, bell).
    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).

Documento elaborado em 11 de agosto de 2026. As informações contidas são de responsabilidade do solicitante.