## 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ão | Data       | Autor                  | Descrição                                                                                                                                                                                               |
| ------ | ---------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1.0    | 21/07/2026 | Designer de Protótipos | Versão inicial da Definição.                                                                                                                                                                            |
| 1.1    | 22/07/2026 | Designer de Protótipos | Atualização com busca, KPIs e grid 2×2.                                                                                                                                                                 |
| 2.0    | 22/07/2026 | Designer de Protótipos | Especificação completa com histórias e regras.                                                                                                                                                          |
| 3.0    | 27/07/2026 | Designer de Protótipos | Consolidação narrativa e técnica; inclusão de SBIS.                                                                                                                                                     |
| 3.1    | 28/07/2026 | Analista de Sistemas   | Atualização de regras de busca, assinatura e status.                                                                                                                                                    |
| 3.2    | 29/07/2026 | Designer de Protótipos | Reestruturação da Seção 2 com descrição funcional detalhada por painel.                                                                                                                                 |
| 3.3    | 30/07/2026 | Designer de Protótipos | Correções de busca, KPIs, prescrições, comunicação, procedimentos e validações.                                                                                                                         |
| 3.4    | 30/07/2026 | Designer de Protótipos | Correções de dependências, avatar, KPI Em Tratamento e navegação.                                                                                                                                       |
| 3.5    | 31/07/2026 | Designer de Protótipos | Protótipo HTML: títulos como links, sem negrito, KPIs com borda colorida, barra de progresso discreta, toggles pill, busca com hint.                                                                    |
| 3.6    | 31/07/2026 | Designer de Protótipos | KPI Em Tratamento: número principal agora é "em tratamento" (removido conceito de "ativos").                                                                                                            |
| 3.7    | 09/08/2026 | Designer de Protótipos | Incorporação de Análise de Workflow com touchpoints detalhados por workflow.                                                                                                                            |
| 3.8    | 10/08/2026 | Designer de Protótipos | Narrativa 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.9    | 10/08/2026 | Designer de Protótipos | Data 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.10   | 10/08/2026 | Designer de Protótipos | Modal de revisão para assinar e revisar prescrições.                                                                                                                                                    |
| 3.11   | 10/08/2026 | Designer de Protótipos | Restauração completa de conteúdo truncado em 2.1, 2.2 e 2.5.                                                                                                                                            |
| 3.12   | 10/08/2026 | Designer de Protótipos | Mudança de conceito de assinatura e revisão de prescrições, modal para mensagens da Comunicação, Endpoints em inglês.                                                                                   |
| 4.0    | 11/08/2026 | Marcos Arao            | Retirada do nome do médico do cabeçalho, api de consulta e mapeamento do BD                                                                                                                             |
| 4.1    | 12/08/2026 | Marcos Arao            | Ajustes de internacionalização                                                                                                                                                                          |
| 4.2    | 12/08/2026 | Marcos Arao            | Ajustes em Procedimentos na clínica e api de procedimentos e seu mapeamento do BD                                                                                                                       |
| 4.3    | 13/08/2026 | Marcos Arao            | Ajustes de termos no Estado das agendas                                                                                                                                                                 |
| 4.4    | 13/08/2026 | Marcos Arao            | Backend da KPI Em tratamento e Alertas de Prescrição                                                                                                                                                    |
| 4.5    | 24/08/2026 | Marcos Arao            | Correçã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.6    | 24/08/2026 | Marcos Arao            | Correçã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.7    | 24/08/2026 | Marcos Arao            | Endpoints 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.8    | 24/08/2026 | Marcos Arao            | Correçã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.9    | 24/08/2026 | Marcos Arao            | Adicionado 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.10   | 24/08/2026 | Marcos Arao            | Correçã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.11   | 24/08/2026 | Marcos Arao            | Default 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.12   | 24/08/2026 | Marcos Arao            | Ajustes 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

|Persona|Papel no Sistema|Necessidade Principal|
|---|---|---|
|Médico Oncologista|Usuário Principal|Visão 360º do dia, agilidade na assinatura e monitoramento de segurança.|
|Recepcionista|Stakeholder operacional|Manté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êutica|Stakeholders clínicos|Recebem 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 workflow|Necessidade do profissional|O que a Central oferece|Decisão de design justificada|
|---|---|---|---|
|Antes de chamar o próximo paciente|Saber rapidamente quem está recepcionado e pronto para atendimento|Painel 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 paciente|Identificar se o paciente está atrasado (horário passou e não iniciou)|Badge vermelho pulsante "Atrasado · Xmin" no card de consulta|O atraso é uma exceção do workflow que exige ação imediata — o pulsante chama atenção sem que o médico precise procurar.|
|Entre atendimentos|Acessar o prontuário do próximo paciente sem navegar por menus|Clique no card de consulta abre diretamente o PEP|No workflow, o médico precisa do prontuário imediatamente antes de chamar o paciente — um clique é o menor caminho possível.|
|Início do turno|Ter 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 atendimento|Não ser interrompido por informações irrelevantes|Consultas finalizadas aparecem esmaecidas na sua posição original|No 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 workflow|Necessidade do profissional|O que a Central oferece|Decisão de design justificada|
|---|---|---|---|
|Entre consultas / durante o turno|Saber quais pacientes estão em procedimento na clínica e em qual etapa|Painel de Procedimentos na Clínica com status (Em Atendimento / Aguardando) e local na clínica|No 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 monitoramento|Saber se uma infusão está dentro do tempo previsto ou atrasada|Barra de progresso inline (3px) na linha do nome, com porcentagem|No 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 consultas|Decidir se precisa intervir em um procedimento em andamento|Clique no card abre a prescrição do procedimento; botão separado "PEP" abre o prontuário|No 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 turno|Saber quantos pacientes estão em tratamento sob sua responsabilidade e quantos não estão aderentes|KPI "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 turno|Filtrar apenas seus pacientes vs. ver todos os da clínica|Toggle 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 workflow                  | Necessidade do profissional                                               | O que a Central oferece                                                                                                                                              | Decisão de design justificada                                                                                                                                                                                                                                                                                                                                  |
| ------------------------------------ | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Início do turno / entre atendimentos | Assinar prescrições pendentes antes que a farmácia possa manipular        | Painel de Prescrições Pendentes com botão "Assinar" no card que abre a tela de assinatura com a prescrição completa                                                  | No 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 turno                      | Priorizar quais prescrições assinar primeiro (as mais urgentes)           | Chips de urgência: vermelho (<12h) e laranja (12-24h) com tempo restante                                                                                             | No 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 agendada | Confirmar que a prescrição foi revisada por um médico antes da administração ao paciente | Card 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 confirmar | No 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 turno                      | Saber quantas prescrições urgentes (menos de 12h) precisam de sua atenção | KPI "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ção            | Confirmar que a assinatura foi processada e retornar à Central            | Toast de sucesso "Prescrição assinada com sucesso" + retorno automático à Central, focada no painel de Prescrições Pendentes + atualização do KPI                    | No 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ções                | Focar primeiro nas prescrições que é preferencialmente responsável por revisar (seus pacientes), mas poder ajudar a revisar as de colegas quando necessário | Toggle 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 logado | No 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 workflow             | Necessidade do profissional                                               | O que a Central oferece                                                                                      | Decisão de design justificada                                                                                                                                                   |
| ------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Durante todo o turno            | Receber mensagens da equipe sem sair da Central                           | Painel de Comunicação com mensagens não resolvidas                                                           | No 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 nova    | Identificar rapidamente que há mensagem não lida                          | Mensagens não lidas com ícone colorido e borda lateral destacada                                             | No 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 mensagens | Priorizar mensagens com prazo de resposta                                 | Data limite exibida no card ("Responder até 14:00") + ordenação por data limite primeiro                     | No 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ção     | Arquivar a mensagem com um clique                                         | Botão "Resolvido" no card que remove a mensagem e atualiza o contador                                        | No 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 turno            | Distinguir 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ódulo        | Dependência                     | Impacto                                                                                                                                                            |
| --------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Módulo de Agenda      | Status da agenda                | Sem isso, o painel de consultas não atualiza.                                                                                                                      |
| Módulo de Agenda      | Data/hora da aplicação da prescrição | A 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 Assinatura | Integração com Certificadora    | Necessário para a validade jurídica da assinatura (quando aplicável).                                                                                              |
| Recepcionista         | Atualização de status na agenda | Define os status "Agendado" e "Recepcionado" no painel de Consultas.                                                                                               |

### Requisitos SBIS Aplicáveis

|ID SBIS|Descrição Acessível|Implementação no Cockpit|
|---|---|---|
|ECF.03.11|Busca multifatorial de pacientes|Implementado na busca do Header (Nome, CPF, Mãe).|
|ECF.16.01|Listagem de pendências do profissional|Implementado no Painel de Prescrições Pendentes.|
|ECF.17.04|Registro de eventos em ordem cronológica|Aplicado 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:

| Termo          | pt-BR                                                                     | en-US                                                       | es-419                                                                            |     |
| -------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------- | --- |
| MSG_searchPac  | Procurar paciente...                                                      | Search Pacient...                                           | Buscar paciente...                                                                |     |
| MSG_searchFoot | Digite parte do nome, CPF, data de nascimento ou nome da mãe para filtrar | Enter parte of the name, ID, mother's name or DOB to filter | Ingrese parte del busque por nombre, ID, nombre de la madre o fecha de nacimiento |     |
| MSG_searchMin  | Digite 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_searchNone | Nenhum 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ção | pt-BR | en-US | es-419 |
|-------|-------|--------|----|
|Card Consultas Hoje - título|CONSULTAS HOJE|TODAY'S APPOINTMENTS|CONSULTAS DE HOY|
|Card Consultas Hoje - pendentes|pendentes|pending|pendientes|
|Card Consultas Hoje - atrasadas|atrasadas|delayed|atrasada|
|Card Em tratamento - título|EM TRATAMENTO|IN TREATMENT|EN TRATAMIENTO|
|Card Em tratamento - não aderentes|não aderentes|non-adherent|no adherentes|
|Card Procedimentos hoje - título|PROCEDIMENTOS HOJE|TODAY'S PROCEDURES|PROCEDIMIENTOS HOY|
|Card Procedimentos hoje - em atendimento|em atendimento|in progress|en atención|
|Card Procedimentos hoje - aguardando|aguardando|waiting|en espera|
|Card Procedimentos hoje - previstos|previstos|scheduled|programados|
|Card Alertas de prescrição = título|ALERTAS DE PRESCRIÇÃO|PRESCRIPTION ALERTS|ALERTAS DE PRESCRIPCIÓN|
|Card Alertas de prescrição - revisar|p/revisar|to review|p/revisar|
|Card Alertas de prescrição - assinar|p/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ção   | pt-BR                        | en-US                        | es-419                     |
| ------------------- | ---------------------------- | ---------------------------- | -------------------------- |
| painel-título       | Consultas                    | Appointments                 | Consultas                  |
| toggle-todas        | Todas                        | All                          | Todas                      |
| toggle-pendentes    | Pendentes                    | Pending                      | Pendientes                 |
| chip-atrasado       | Atrasado                     | Delayed                      | Atrasado                   |
| status-agendado     | Agendado                     | Shceduled                    | Agendada                   |
| status-aguardando   | Aguardando recepção          | Waiting reception            | Esperando recepción        |
| status-recepcionado | Recepcionado                 | Checked-in                   | Recepcionado               |
| status-atendimento  | Em Atendimento               | In consulation               | En atención                |
| status-finalizado   | Finalizado                   | Completed                    | Finalizado                 |
| MSG_appointmentNone | Nenhuma agenda para este dia | No appointments for this day | No 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ção    | pt-BR                     | en-US                    | es-419                        |
| -------------------- | ------------------------- | ------------------------ | ----------------------------- |
| painel-título        | Prescrições Pendentes     | Pending Prescriptions    | Prescripciones Pendientes     |
| botão-assinar        | Assinar                   | Sign                     | Firmar                        |
| botão-revisar        | Revisar                   | Review                   | Revisar                       |
| chip-T_restante      | T RESTANTES               | T REMAINING              | T RESTANTES                   |
| MSG_prescriptionNone | Sem prescrições pendentes | No pending prescriptions | Sin prescripciones pendientes |
| toggle-meus          | Meus                      | Mine                     | Míos                          |
| toggle-todos         | Todos                     | All                      | Todos                         |

---

### 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 mensagem   | pt-BR                                                          | en-US                                                               | es-419                                                            |
| -------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------- |
| SYS_PRESC_URGENT     | Prescriçã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_REVIEW     | Prescriçã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_DELAY   | Infusã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_REMINDER | Lembrete: {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ção    | pt-BR                      | en-US                    | es-419                        |
| -------------------- | -------------------------- | ------------------------ | ----------------------------- |
| painel-título        | Notificações               | Notifications            | Notificaciones                |
| botão-resolvido      | Resolvido                  | Resolved                 | Resuelto                      |
| label-há             | Há T                       | T ago                    | Hace T                        |
| MSG_notificationNone | Sem notificações pendentes | No pending notifications | Sin 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ção  | pt-BR                    | en-US                    | es-419                       |
| ------------------ | ------------------------ | ------------------------ | ---------------------------- |
| painel-título      | Procedimentos na clínica | Procedures at the clinic | Procedimientos en la clínica |
| toggle-todos       | Todos                    | All                      | Todos                        |
| toggle-meus        | Meus                     | Mine                     | Mios                         |
| botão-PEP          | PEP                      | EHR                      | HCe                          |
| MSG_proceduresNone | Sem pacientes para o dia | No patients for today    | Sin pacientes para el día    |

---

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

| Painel          | Condição          | Exibição                                                                      |
| --------------- | ----------------- | ----------------------------------------------------------------------------- |
| Qualquer painel | Falha de endpoint | MSG_endpointFail                                                              |
| Qualquer painel | Queda de conexão  | Manter últimos dados na tela + ícone discreto de "Offline" no canto do painel |
| KPI Bar         | Falha de endpoint | Exibir "—" 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ção | pt-BR                                                | en-US                                   | es-419                                         |
| ----------------- | ---------------------------------------------------- | --------------------------------------- | ---------------------------------------------- |
| MSG_endpointFail  | Dados temporariamente indisponíveis. Tente novamente | Data temporarily unavailable. Try again | Datos temporalmente no disponibles. Reintentar |

---

### 2.8 Mapeamento de Componentes do Design System

| Componente                | Variante                  | Estados                           | Tokens aplicados                                                                                                                           |
| ------------------------- | ------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Button                    | Primary (Assinar)         | default, hover, disabled, loading | bg: color-primary-pure; text: color-base-pure; height: btn-height-sm; radius: radius-m                                                     |
| Button                    | Secondary (Revisar)       | default, hover, disabled          | bg: transparent; border: color-primary-pure; text: color-primary-pure                                                                      |
| Button                    | Tertiary (Resolvido)      | default, hover                    | bg: transparent; text: color-primary-pure                                                                                                  |
| Chip                      | Active (Crítico)          | default                           | bg: color-error-light; text: color-error-dark                                                                                              |
| Chip                      | Active (Atenção)          | default                           | bg: color-highlight-light; text: color-highlight-dark                                                                                      |
| Chip                      | Status (consulta)         | default                           | Ver cores por status na RN-CM-005                                                                                                          |
| Badge                     | Error (KPI Alertas)       | default                           | bg: color-error-pure; text: color-base-pure                                                                                                |
| Badge                     | Primary (contadores)      | default                           | bg: color-primary-pure; text: color-base-pure                                                                                              |
| Input                     | Bordered (busca)          | default, focus, disabled          | border: color-neutral-light → focus: color-neutral-dark (2px); height: input-height                                                        |
| Avatar                    | SM/MD (paciente)          | default                           | bg: color-primary-light; text: color-primary-dark                                                                                          |
| Progress                  | Bar (atendimento)         | default, critical                 | bg track: color-neutral-lighter; bg bar: color-primary-pure → critical: color-error-pure                                                   |
| Toast                     | Success/Error             | default                           | Ver Design System para tokens de toast                                                                                                     |
| Tooltip                   | Default                   | hover                             | bg: color-neutral-dark; text: color-base-pure                                                                                              |
| KPI Card                  | Borda colorida lateral    | default, hover                    | border-left: 4px solid; cores: secondary-pure (consultas), primary-pure (tratamento), highlight-pure (procedimentos), error-pure (alertas) |
| Panel Title Link          | Link com seta no hover    | default, hover                    | font-weight: 400; color: neutral-darker → hover: secondary-dark; arrow: opacity 0 → hover: opacity 1                                       |
| Toggle Pill               | Filtro de painel          | active, inactive                  | border: 1px solid neutral-lighter; active: bg secondary-light, text secondary-dark; inactive: bg transparent, text neutral-pure            |
| Progress Bar Inline       | Barra na linha do nome    | default, danger                   | width: 50px; height: 3px; bg track: neutral-lighter; bg fill: primary-pure → danger: error-pure; pct font: 9px                             |
| Card Highlight (Consulta) | Borda colorida por status | recepcionado, aguardando, default | recepcionado: border-left 3px solid secondary-pure; aguardando: border-left 3px solid #FF8A80; default: sem borda                          |
| Message Icon (Lucide)     | Origem da mensagem        | unread, read                      | unread: 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)

|Requisito|Como a Central do Médico atende|
|---|---|
|ECF.03.11|O 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.14|O 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.01|Todos 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.02|As mensagens internas exibem timestamp de criação (criadaEm). As ações de assinatura e resolução registram data/hora automaticamente no backend.|
|ECF.17.04|As 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.18|Toda a interface, incluindo rótulos, mensagens, títulos de tela e descritivos, está em português do Brasil.|
|ECF.17.19|Mensagens 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:

```html
<!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

| Tabela         | Banco             | Função no endpoint                    |
| -------------- | ----------------- | ------------------------------------- |
| Agenda         | GescomClienteAlfa | Tabela principal — dados da agenda    |
| Paciente       | GescomClienteAlfa | Dados do paciente (nome, nome social) |
| PacienteFoto   | GescomClienteAlfa | Foto do paciente                      |
| PEPDiagnostico | GescomClienteAlfa | Diagnóstico oncológico do paciente    |
| TermoTraducao  | IpTerminologia    | Tradução do modo de atendimento       |
| ClienteEmpresa | IpSeguranca       | Idioma e fuso horário da clínica      |

#### Mapa de campos

| Campo                   | Tipo    | Banco | Observação | 
| :---------------------- | :------ | :---- | :--------- | 
| `id`                    | int     | Agenda.IdAgenda | |
| `startTime`             | horário | Agenda.DhAgendaIniUTC | só horário, convertido para o fuso e idioma da clínica | 
| `endTime`               | horário | Agenda.DhAgendaFimUTC | só horário, convertido para o fuso e idioma da clínica |
| `status`                | string  | calculado | vide AppointmentStatus() |
| `type`                  | string  | Agenda.Atendimento -> TermoTraducao.TermoValor | Termo = Agenda.Atendimento, Origem="Indicadores|ModoAtendimento", Idioma=ClienteEmpresa.IdiomaOficial |
| `firstTime`             | char    | Agenda.PrimeiraConsulta | domínio = 'S'=sim, 'N'=não |
| `delayMinutes`          | int     | Agenda.DhAgendaIniUTC(no fuso da clínica)-Now(no fuso da clínica) | Se o valor for negativo, retorna 0 |
| `patient.id`            | int     | Agenda.IdPaciente | |
| `patient.prefferedName` | string  | Paciente.NomeSocial | se existir, usar este como nome principal |
| `patient.legalName`     | string  | Paciente.Nome | se NomeSocial não existir, usar este como nome |
| `patient.photo`         | url     | PacienteFoto.NomeArquivo, busca IdPaciente e Padrao = 'S', se multiplos, retorna o mais recente | url gerada pelo MinIO | 
| `patient.diagnosis`     | string  | PEPDiagnostico.Diagnostico para Tipo = 'O' e PEP.IdPaciente | pode haver mais de um |

#### Funções de cálculo

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

| Status retornado                | Condiçã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:

| Valor | Significado         |
| ----- | ------------------- |
| C     | Consulta |
| Q     | Quimioterapia |
| R     | Radioterapia |
| S     | Reserva de sala para assuntos não assistenciais |

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

| Valor | Significado         |
| ----- | ------------------- |
| P     | Padrão (Presencial) |
| T     | Teleatendimento     |
| C     | Customizado         |
| R     | Reservado           |

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

| Valor | Significado                     |
| ----- | ------------------------------- |
| A     | Aberta                          |
| V     | Confirmada (check-in realizado) |
| C     | Cancelada pelo usuário          |
| D     | Cancelada pelo paciente         |
| M     | Cancelada pelo médico           |
| F     | Falta                           |
| I     | Cancelado por internação        |
| O     | Cancelada por óbito             |
| T     | Transferido (cancelado)         |

TipoDiagnostico (domínio de Diagnostico.Tipo):

| Valor | Significado                     |
| ----- | ------------------------------- |
| C     | Comorbidade                     |
| O     | Doenç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')`AND`DhAtendimentoFimUTC 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

| Tabela         | Banco             | Função no endpoint                    |
| -------------- | ----------------- | ------------------------------------- |
| Agenda         | GescomClienteAlfa | Tabela principal — dados da agenda    |

#### Mapa de campos

| Campo      | Tipo | Banco | 
| :--------- | :--- | :---- | 
| `total`    | int  | count(Agenda.Situacao IN ('A', 'V')) |
| `finished` | int  | count(Agenda.Situacao='V', Agenda.DhAtendimentoFimUTC<>NULL) |
| `pending`  | int  | count(Agenda.Situacao IN ('A', 'V'), Agenda.DhAtendimentoFimUTC=NULL) |
| `delayed`  | int  | count(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

| Tabela         | Banco             | Função no endpoint                    |
| -------------- | ----------------- | ------------------------------------- |
| Agenda         | GescomClienteAlfa | Tabela principal — dados da agenda    |
| Paciente       | GescomClienteAlfa | Dados do paciente (nome, nome social) |
| PacienteFoto   | GescomClienteAlfa | Foto do paciente                      |
| Prescricao     | GescomClienteAlfa | Diagnóstico oncológico do paciente    |
| TermoTraducao  | IpTerminologia    | Tradução do modo de atendimento       |
| ClienteEmpresa | IpSeguranca       | Idioma e fuso horário da clínica      |

#### Mapa de campos

| Campo                   | Tipo    | Banco                                                                                                           | Observação                                             |     |
| :---------------------- | :------ | :-------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------- | --- |
| `id`                    | int     | Prescricao.IdPrescricao                                                                                         |                                                        |     |
| `prescriptionCode`      | string  | Prescricao.Identificacao                                                                                        |                                                        |     |
| `location`              | string  | Prescricao.IdAgenda->Agenda.IdUAtendimento->UnidadeAtendimento.Descricao + Agenda.IdChRecurso->Chave.Descricao  | IdUAtendimento pode ser NULL                           |     |
| `startTime`             | horário | se 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 |     |
| `status`                | string  | calculado                                                                                                       | vide ProcedureStatus()                                 |     |
| `progress`              | int     | (Now()-Agenda.DhAtendimentoIniUTC(no fuso do servidor))/Agenda.Tempo*100                                        |                                                        |     |
| `mine`                  | boolean | Prescricao.IdChProfissionalMed={IdChProfissional do médico logado}                                              |                                                        |     |
| `patient.id`            | int     | Prescricao.IdPaciente                                                                                           |                                                        |     |
| `patient.prefferedName` | string  | Paciente.NomeSocial                                                                                             | se existir, usar este como nome principal              |     |
| `patient.legalName`     | string  | Paciente.Nome                                                                                                   | se NomeSocial não existir, usar este como nome         |     |
| `patient.photo`         | url     | PacienteFoto.NomeArquivo, busca IdPaciente e Padrao = 'S', se multiplos, retorna o mais recente                 | url gerada pelo MinIO                                  |     |

#### Funções de cálculo

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

| Status retornado                   | Condiçã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:

| Valor | Significado         |
| ----- | ------------------- |
| C     | Consulta |
| Q     | Quimioterapia |
| R     | Radioterapia |
| S     | Reserva de sala para assuntos não assistenciais |

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

| Valor | Significado                     |
| ----- | ------------------------------- |
| A     | Aberta                          |
| V     | Confirmada (check-in realizado) |
| C     | Cancelada pelo usuário          |
| D     | Cancelada pelo paciente         |
| M     | Cancelada pelo médico           |
| F     | Falta                           |
| I     | Cancelado por internação        |
| O     | Cancelada por óbito             |
| T     | Transferido (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

| Tabela         | Banco             | Função no endpoint                    |
| -------------- | ----------------- | ------------------------------------- |
| Agenda         | GescomClienteAlfa | Tabela principal — dados da agenda    |
| Paciente       | GescomClienteAlfa | Dados do paciente (nome, nome social) |
| PacienteFoto   | GescomClienteAlfa | Foto do paciente                      |
| Prescricao     | GescomClienteAlfa | Diagnóstico oncológico do paciente    |
| TermoTraducao  | IpTerminologia    | Tradução do modo de atendimento       |
| ClienteEmpresa | IpSeguranca       | Idioma e fuso horário da clínica      |

#### Mapa de campos

| Campo        | Tipo | Banco                                                      |
| :----------- | :--- | :--------------------------------------------------------- |
| `total`      | int  | count(Agenda.Situacao IN ('A', 'V'))                       |
| `inProgress` | int  | count(ProcedureStatus()=`preparation` OR `administering`)) |
| `waiting`    | int  | count(ProcedureStatus()=`waiting` OR `checked`)            |
| `scheduled`  | int  | count(ProcedureStatus()=`scheduled`)                       |

#### Funções de cálculo

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

| Status retornado                   | Condiçã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:

| Valor | Significado         |
| ----- | ------------------- |
| C     | Consulta |
| Q     | Quimioterapia |
| R     | Radioterapia |
| S     | Reserva de sala para assuntos não assistenciais |

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

| Valor | Significado                     |
| ----- | ------------------------------- |
| A     | Aberta                          |
| V     | Confirmada (check-in realizado) |
| C     | Cancelada pelo usuário          |
| D     | Cancelada pelo paciente         |
| M     | Cancelada pelo médico           |
| F     | Falta                           |
| I     | Cancelado por internação        |
| O     | Cancelada por óbito             |
| T     | Transferido (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

| Tabela         | Banco             | Função no endpoint                    |
| -------------- | ----------------- | ------------------------------------- |
| Agenda         | GescomClienteAlfa | Tabela principal — dados da agenda    |
| Paciente       | GescomClienteAlfa | Dados do paciente (nome, nome social) |
| Prescricao     | GescomClienteAlfa | Diagnóstico oncológico do paciente    |
| TermoTraducao  | IpTerminologia    | Tradução do modo de atendimento       |

#### Mapa de campos

| Campo         | Tipo | Banco                         |
| :------------ | :--- | :---------------------------- |
| `inTreatment` | int  | PatientInTreatmentCount()     |
| `nonAdherent` | int  | TreatmentPlanAdherenceCount() |

#### 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

| Tabela               | Banco             | Função no endpoint                                                        |
| --------------------- | ------------------ | ---------------------------------------------------------------------------- |
| Prescricao             | GescomClienteAlfa | Tabela principal — versão ativa (`Situacao <> 'C'`), médico prescritor        |
| PrescricaoAssinatura   | GescomClienteAlfa | Histórico de assinaturas/revisões — usada para determinar se a prescrição está revisada |
| Agenda                 | GescomClienteAlfa | Data/hora agendada da aplicação (via `Prescricao.IdAgenda`)                   |

#### Mapa de campos

| Campo              | Tipo | Banco                          | Observação |
| :------------------ | :--- | :------------------------------ | :--------- |
| `urgent`            | int  | PrescriptionUrgentCount()       | |
| `toReview`          | int  | PrescriptionToReviewCount()     | |
| `toSignNext7Days`   | int  | PrescriptionToSignNext7DaysCount() | |

#### 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:

```sql
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

| Tabela               | Banco             | Função no endpoint                                          |
| --------------------- | ------------------ | -------------------------------------------------------------- |
| Prescricao             | GescomClienteAlfa | Tabela principal — versão ativa (`Situacao <> 'C'`); `Identificacao` já traz protocolo + ciclo/sessão formatados |
| PrescricaoAssinatura   | GescomClienteAlfa | Determina se a prescrição está assinada e/ou revisada (ver 4.6) |
| Paciente               | GescomClienteAlfa | Nome social/civil do paciente e médico assistente               |
| Agenda                 | GescomClienteAlfa | Data/hora agendada da aplicação                                 |

#### Domínio — PrescricaoAssinatura.TipoAssinatura

| Valor | Significado                                                            |
| ----- | ------------------------------------------------------------------------ |
| `M`   | Assinatura do médico (assinatura original da prescrição ou de uma nova versão gerada por edição) |
| `R`   | Confirmaçã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

| Campo                        | Tipo    | Banco | Observação |
| :----------------------------- | :------ | :---- | :--------- |
| `id`                           | uuid    | Prescricao.IdPrescricao | identifica diretamente a versão ativa — não há campo de número de versão a considerar à parte |
| `patient.id`                   | uuid    | Prescricao.IdPaciente | |
| `patient.preferredName`        | string  | Paciente.NomeSocial | mesmo padrão de `appointments` (4.1) e `procedures` (4.3) — enviado sempre, mesmo vazio, para o front sinalizar nome social ao médico |
| `patient.legalName`            | string  | Paciente.Nome | enviado sempre, junto com `preferredName` |
| `prescriptionCode`             | string  | Prescricao.Identificacao | substitui os antigos `protocol`/`cycle` — já vem formatado do banco (ex: "CARBO-TAXOL C3D1"), sem necessidade de montar a string a partir de `Protocolo`/`PrescricaoProtocolo` |
| `scheduleDate`                 | datetime| Agenda.DhAgendaIniUTC, via Prescricao.IdAgenda | convertida para o fuso da clínica na exibição |
| `hoursRemaining`               | int     | calculado: `Agenda.DhAgendaIniUTC - Now()` em horas | |
| `type`                         | string  | calculado | `to_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) |
| `isPreferredReviewer`          | bool    | calculado | `true` 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._