# Agenda do Médico — Especificação (v1.1)

**Documentos desta funcionalidade:** [01 - Definição](./01%20-%20Defini%C3%A7%C3%A3o%20v1.6.md) (v1.6) · [02 - Especificação](./02%20-%20Especifica%C3%A7%C3%A3o%20v1.1.md) (v1.1) · [03 - Protótipo](./03%20-%20Prot%C3%B3tipo%20v1.0.md) (v1.0, código executável em `03 - Protótipo v1.0.html`) · Mapeamento de Banco de Dados (Seção 4): **pendente**.

---

## SEÇÃO 2 — ESPECIFICAÇÃO

Premissa de design: toda decisão de design nesta especificação é justificada pelo workflow documentado na Seção 1 — o médico chega aqui a partir da Central do Médico (título do painel "Consultas" ou indicador "Consultas Hoje") quando precisa da visão completa do dia (não só os próximos atendimentos) ou quer bloquear um horário. Layout mobile-first (Seção 1, "Premissas"): uma coluna única de lista em qualquer largura; em telas largas, a coluna fica centralizada com largura máxima de leitura, sem mudar a estrutura. Em telas estreitas, todo alvo de toque (botões, dias do calendário, opções de duração, "Desfazer bloqueio") tem no mínimo 44×44px.

Referência de tempo: "hoje", "agora", "dia passado" e "horário já decorrido" são sempre avaliados no fuso horário da clínica e pelo relógio do servidor, não do dispositivo — `GET /day` devolve `serverNow` (data e hora atuais no fuso da clínica), usado pelo front para o rótulo "Hoje", a linha "AGORA", o sinalizador de atraso, as opções de início do bloqueio e a disponibilidade de "Bloquear horário" e "Desfazer bloqueio"; entre duas atualizações, o front avança esse horário pelo próprio relógio.

### Histórias de Usuário

- **US-AGM-001:** Como médico, quero ver minha agenda do dia em lista, com os mesmos elementos de identificação de paciente já usados na Central do Médico, para organizar meu trabalho do dia.
- **US-AGM-002:** Como médico, quero navegar entre dias — dia a dia ou pulando direto para o próximo dia com consulta — para checar minha agenda com agilidade, mesmo em dias sem nenhum compromisso.
- **US-AGM-003:** Como médico, quero bloquear um horário vago e futuro da minha agenda, para reservar tempo para atividades não assistenciais (reunião, ausência).
- **US-AGM-004:** Como médico, quero desfazer um bloqueio que eu mesmo criei e que ainda não começou, para corrigir um bloqueio feito por engano ou cujo motivo não existe mais.
- **US-AGM-005:** Como médico, quero que consultas já realizadas e consultas canceladas fiquem agrupadas, separadamente, e fora do caminho, para manter o foco nas consultas pendentes sem perder a visão de que o dia inteiro está ali.
- **US-CM-000** (Central do Médico, Seção 2.1 — "Buscar pacientes rapidamente") aplica-se também a esta tela (RN-AGM-014), sem redefinição.

### Descrição Funcional Detalhada

#### Cabeçalho do Sistema (RN-AGM-014)

A tela usa o mesmo cabeçalho da Central do Médico (Central do Médico, Seção 2.1): nome da clínica à esquerda, campo de busca de pacientes ao centro e menu do usuário (avatar com dropdown) à direita. Comportamento da busca (disparo após 2 caracteres e 1 segundo de pausa, busca aproximada, interpretação por dígito/letra, campos mínimos do resultado, abertura do PEP ao selecionar), do menu do usuário, critérios de aceitação e mensagens (`MSG_searchPac`, `MSG_searchFoot`, `MSG_searchMin`, `MSG_searchNone`) são os da Central do Médico, Seção 2.1 — referenciados, não repetidos aqui. Mesmo endpoint: `GET /api/v1/patients/search` (Central do Médico, Seção 2.9). Em telas estreitas (celular), o nome da clínica é ocultado para dar largura ao campo de busca; busca e avatar continuam sempre visíveis.

Justificativa de workflow: o médico que está conferindo a agenda do dia pode precisar de um paciente que não está nela (ex.: um resultado de exame chegou para um paciente de outro dia) — a busca no cabeçalho evita voltar à Central só para isso.

#### Barra de Navegação do Dia

Barra fixa logo abaixo do cabeçalho do sistema, com:

1. **Data exibida em destaque** — dia da semana + data completa (ex.: "Terça-feira, 29 de setembro"). Quando o dia exibido é hoje, um rótulo "Hoje" aparece ao lado.
2. **Navegação por dia (RN-AGM-003):**
    - Setas sequenciais (◂ ▸) avançam ou retrocedem um dia por vez — o uso mais frequente, sempre visível.
    - Um segundo par de ícones de atalho, imediatamente ao lado das setas sequenciais, pula direto para o próximo/anterior dia que tenha ao menos uma consulta agendada não cancelada — dias com apenas bloqueios ou apenas consultas canceladas são ignorados (RN-AGM-003). Fica desabilitado quando não há nenhum dia com consulta naquela direção.
    - Um ícone de calendário abre um seletor de data em formato de mini-calendário mensal; os dias com ao menos uma consulta (mesmo critério do atalho) aparecem marcados visualmente (ponto sob o número do dia). Selecionar um dia fecha o seletor e carrega a agenda daquele dia.
    - Botão "Hoje" — sempre visível, retorna ao dia atual em um toque.
3. **Botão "Bloquear horário"** — ação secundária, sempre visível na barra. Habilitado quando o dia exibido é hoje ou um dia futuro; **indisponível em dias passados** (RN-AGM-012): aparência desabilitada, mas continua focável e tocável (`aria-disabled`, não `disabled`) — ao ser acionado, não abre o formulário e exibe MSG-TAGM-02 em toast, para que a explicação chegue também no toque e no teclado. No dia de hoje, fica indisponível da mesma forma quando não resta nenhum horário de início possível no dia (após o último intervalo de 15 minutos), com MSG-TAGM-04.

Motivador: os dois mecanismos de pular dias (atalho sequencial + calendário) atendem necessidades diferentes do mesmo touchpoint — o atalho é mais rápido para "o próximo dia que eu trabalho", o calendário é necessário quando o médico já sabe a data exata que quer checar. Disposição em duas linhas, em qualquer largura: na primeira, a data exibida (com "Hoje" e o indicador "Offline") e o botão "Bloquear horário" à direita; na segunda, os controles de navegação. Em telas estreitas, a data pode ser truncada com reticências e o botão mostra só o ícone (cadeado), mantendo o rótulo acessível.

#### Lista de Consultas do Dia

Item por consulta, em ordem cronológica pelo horário de início. Cada item exibe (RN-AGM-009, elementos herdados da Central do Médico — mesma origem e lógica já especificadas em Central do Médico, Seção 2.3):

- Paciente: nome (preferido, com o nome legal como alternativa), foto (ou avatar com as iniciais do primeiro e do último nome, texto `color-neutral-darker` sobre a cor do status — texto branco não tem contraste suficiente sobre as cores claras da paleta), diagnóstico(s) oncológico(s).
- Horário (início–fim).
- Status do atendimento (chip colorido, mesma paleta e rótulos da Central — Agendado, Aguardando Recepção, Recepcionado, Em Atendimento, Finalizado — mais **Cancelado**, exclusivo desta tela, ver abaixo).
- Destaque visual por status: borda lateral esquerda de 3px para "Recepcionado" (secondary-pure) e "Aguardando Recepção" (#FF8A80) — mesmo padrão da Central.
- Sinalizador de atraso "Atrasado · Xmin" (badge pulsante, mesmo componente da Central) — **somente quando o dia exibido é hoje**, e só para consultas cujo horário de início já passou e que ainda não foram iniciadas nem finalizadas (status Agendado, Aguardando Recepção ou Recepcionado), mesma regra da Central. Em dias passados ou futuros, o sinalizador não aparece.
- Modo de atendimento (Presencial / Teleatendimento).
- Tags do paciente, pelo critério de RN-AGM-006 (mesmo da Central, RN-CM-025), e a tag "1ª Consulta" quando aplicável (RN-CM-028) — já filtradas pelo back-end.

Nota de nomenclatura: "Modo de atendimento" (campo `attendanceMode` na API — presencial, teleatendimento etc.) e "Tipo de consulta" (campo `appointmentType`, RN-AGM-008) são dois campos distintos, apesar do nome parecido — o primeiro descreve o canal do atendimento, o segundo é um domínio configurável pela clínica (ex.: retorno, revisão).

Mais dois elementos exclusivos desta tela:

- **Complemento** (RN-AGM-007) — quando preenchido, exibido como uma linha de texto secundária abaixo do horário, sem rótulo.
- **Tipo de consulta** (RN-AGM-008) — quando a clínica configurou esse domínio, exibido como um chip curto ao lado do horário; ausente quando a clínica não configurou.

**Status "Cancelado":** consultas canceladas por qualquer motivo (inclusive falta do paciente) aparecem com o chip "Cancelado" (fundo `color-neutral-light`, texto `color-neutral-dark`; rótulo: termo `status-cancelado` já catalogado na Central do Médico, Seção 2.6) e o avatar na mesma cor neutra. Só aparecem dentro do bloco de canceladas (ver abaixo).

Toque em qualquer parte do item de consulta abre o PEP do paciente (RN-AGM-009) — inclusive consultas realizadas e canceladas, dentro dos blocos expandidos.

**Itens de horário bloqueado (RN-AGM-004, RN-AGM-011):** aparecem na mesma lista, na posição cronológica correspondente, visualmente diferenciados dos itens de consulta — fundo `color-neutral-lighter`, sem foto, diagnóstico, status ou tags (não há paciente real associado a exibir), com ícone de cadeado, o rótulo "Bloqueado", o horário e o complemento (quando preenchido). Não abrem o PEP ao toque. Exibem a ação "Desfazer bloqueio" **somente enquanto o bloqueio ainda não começou** (horário de início posterior ao momento atual — RN-AGM-012); um bloqueio em andamento ou já ocorrido permanece como item individual, na sua posição de horário, sem a ação e com aparência esmaecida (mesma opacidade das consultas finalizadas na Central). Bloqueios nunca entram nos blocos recolhidos (RN-AGM-010).

#### Blocos de Consultas Realizadas e Canceladas (RN-AGM-010)

Consultas com status `finished` e com status `canceled` não aparecem como itens individuais na lista principal — são substituídas por **dois** itens recolhidos, no topo da lista, nesta ordem:

1. **Realizadas** — "N consultas realizadas ▸" (singular: "1 consulta realizada ▸"), com as consultas `finished` do dia.
2. **Canceladas** — "N consultas canceladas ▸" (singular: "1 consulta cancelada ▸"), com as consultas `canceled` do dia (qualquer motivo de cancelamento, inclusive falta).

Cada bloco só aparece quando N ≥ 1. Tocar num bloco expande só aquele bloco, revelando as consultas individuais em ordem cronológica, no mesmo formato de item da lista normal, esmaecidas (mesmo tratamento das consultas finalizadas da Central do Médico, Seção 2.3); tocar novamente recolhe. Os dois blocos se expandem e recolhem de forma independente e começam recolhidos a cada carregamento de dia. Não há mudança de posição quando uma consulta muda de status durante a atualização automática: ela simplesmente passa da lista principal para o bloco correspondente.

**Linha "AGORA":** somente quando o dia exibido é hoje, uma linha de ancoragem "AGORA · HH:MM" é inserida na lista principal na posição cronológica do horário atual — depois de todos os itens com horário de início anterior ou igual ao momento atual (ex.: bloqueios já ocorridos, consultas atrasadas ainda não iniciadas) e antes do próximo item. Sem nenhum item individual antes do horário atual, a linha fica logo abaixo dos blocos. **Posição inicial da rolagem (dia de hoje):** a tela abre rolada até a primeira consulta que ainda exige ação — a de horário mais cedo entre as de status Agendado, Aguardando Recepção, Recepcionado ou Em Atendimento — mesmo que ela esteja antes da linha "AGORA" (ex.: uma consulta atrasada); sem nenhuma consulta nesses status, a rolagem vai para a linha "AGORA". O deslocamento considera a altura real do cabeçalho e da barra do dia, para o item não ficar escondido atrás delas. A linha é reposicionada a cada atualização automática (RN-AGM-013), sem mover a rolagem. Em qualquer outro dia, a linha "AGORA" não aparece e a tela abre com a rolagem no topo da lista.

#### Fluxo de Bloqueio de Horário (RN-AGM-004, RN-AGM-012, US-AGM-003)

Ao tocar em "Bloquear horário": abre um formulário em modal (em telas estreitas, bottom sheet — mesma anatomia de modal do Design System) com:

- **Data** — o dia exibido na tela, somente leitura (para bloquear outro dia, o médico navega até ele antes).
- **Início** — seleção em intervalos de 15 minutos (00:00, 00:15, ... 23:45). Sugestão inicial: 12:00 (ou, no dia de hoje depois desse horário, o primeiro horário oferecido). No dia de hoje, só são oferecidos horários posteriores ao momento atual (o primeiro intervalo de 15 minutos ainda não iniciado).
- **Duração** — opções pré-definidas 15, 30, 45 e 60 minutos, mais "Outro", que abre um campo numérico em minutos, em múltiplos de 15 (mínimo 15). O horário de término (início + duração) é exibido logo abaixo, só leitura, e não pode ultrapassar o fim do dia exibido — o valor "24:00" é aceito e significa exatamente o fim do dia (ver `endTime` em Integração com Backend).
- **Complemento** (RN-AGM-007) — campo de texto livre, opcional, até 128 caracteres — mesmo campo e limite já usados nas consultas.
- Botões "Cancelar" e "Confirmar bloqueio".

Validação (no front, repetida pelo back-end):

- O intervalo não pode sobrepor uma consulta ativa (qualquer status exceto `canceled`) nem outro bloqueio (EX-AGM-01). Consultas canceladas não ocupam o horário (RN-AGM-004).
- O início não pode estar no passado (RN-AGM-012) — já garantido pelas opções oferecidas, mas revalidado ao confirmar, porque o horário pode passar enquanto o formulário está aberto (EX-AGM-07).
- A duração "Outro" deve ser múltiplo de 15, no mínimo 15, e não pode levar o término além do fim do dia (MSG-EAGM-08).
- O complemento é validado e gravado sem espaços nas pontas; o contador de caracteres conta o mesmo valor que é validado.

Acessibilidade do formulário: o foco fica preso no modal enquanto ele está aberto (o conteúdo de fundo fica inerte), "Esc" fecha, e a mensagem de erro inline é associada ao campo em erro (`aria-invalid` + `aria-describedby`).

Ao confirmar com sucesso, o modal fecha e o novo item bloqueado aparece na lista, na posição cronológica correspondente.

#### Fluxo de Desfazer Bloqueio (US-AGM-004, RN-AGM-012)

Cada item bloqueado que ainda não começou exibe a ação "Desfazer bloqueio". Confirmação rápida inline, sem modal: ao primeiro toque, o botão muda para "Confirmar?" (estado *confirming*, texto `color-error-pure`) por 5 segundos; um segundo toque dentro desse intervalo efetiva a remoção; sem o segundo toque, o botão volta sozinho ao estado normal e nada é alterado. Motivador: evita desfazer por toque acidental sem impor a fricção de um modal para uma ação de baixo risco e reversível (o horário só volta a ficar vago; nenhum dado de paciente é afetado). Ao efetivar, o item sai da lista e o horário volta a ficar vago (disponível para a Recepção agendar uma consulta real ali). Se o bloqueio começar enquanto o botão está em "Confirmar?", a remoção é recusada (EX-AGM-08). O estado "Confirmar?" pertence ao item, não à renderização: uma atualização automática ou qualquer outra atualização da lista durante os 5 segundos não o interrompe nem reinicia a contagem.

#### Atualização Automática e Conexão (RN-AGM-013)

A agenda do dia exibido é recarregada em segundo plano a cada 1 minuto (polling do `GET /api/v1/agenda/doctor/day`, mesmo intervalo do painel de Consultas da Central, Central do Médico, Seção 2.9), sem perder o estado de expansão dos blocos, a posição de rolagem nem o foco do teclado. O polling só roda quando o dia exibido foi carregado com sucesso — não durante o carregamento (skeleton) nem no estado de erro de EX-AGM-02, em que a recuperação é pelo "Tentar novamente". A cada troca de dia e a cada atualização, os atalhos de próximo/anterior dia com consulta são reavaliados (`GET /next-appointment-date`). Leitores de tela não recebem o anúncio da lista inteira a cada atualização: só o indicador "Offline" e os toasts são regiões anunciadas.

**Virada do dia:** a tela não muda sozinha de dia. Se o dia exibido era hoje e a meia-noite passa (no fuso da clínica), na atualização seguinte ele passa a ser tratado como dia passado — some o rótulo "Hoje", a linha "AGORA" e os sinalizadores de atraso, e "Bloquear horário" fica indisponível; o botão "Hoje" leva ao novo dia. A mesma atualização reavalia o sinalizador de atraso, a linha "AGORA" e a disponibilidade da ação "Desfazer bloqueio". Se uma atualização em segundo plano falhar (queda de conexão ou erro do back-end) depois de a agenda já ter sido carregada, os últimos dados continuam na tela e um indicador discreto "Offline" aparece na barra de navegação do dia — mesmo padrão da Central do Médico, Seção 2.7 (EX-AGM-09); o indicador some na próxima atualização bem-sucedida. Enquanto "Offline", "Bloquear horário" e "Desfazer bloqueio" continuam acionáveis — uma falha no envio segue os fluxos EX-AGM-04/05.

### Critérios de Aceitação

**CA-001.1**: Dado que o médico abre a Agenda a partir da Central do Médico (título do painel "Consultas" ou indicador "Consultas Hoje"), quando a tela carrega, então exibe a agenda do dia atual, em formato de lista, com as consultas em ordem cronológica.

**CA-001.2**: Dado que uma consulta tem tags do paciente cadastradas, quando o item é exibido, então aparecem apenas as tags permitidas pelo critério de RN-CM-025 (habilitadas para agendas e dentro da vigência da própria tag) mais a tag VIP, quando o paciente a tiver — as demais, mesmo existindo, não são exibidas.

**CA-001.3**: Dado que uma consulta tem o campo de complemento preenchido, quando o item é exibido, então o complemento aparece como texto secundário abaixo do horário.

**CA-001.4**: Dado que a clínica não configurou tipos de consulta, quando os itens são exibidos, então nenhum chip de tipo de consulta aparece em nenhum item.

**CA-001.5**: Dado que o médico toca em um item de consulta (inclusive dentro de um bloco expandido), então o sistema abre o PEP do paciente correspondente.

**CA-001.6**: Dado que ocorre erro de rede ou falha do back-end ao carregar a agenda de um dia (carregamento inicial ou troca de dia), então a tela exibe o estado de erro (EX-AGM-02) com MSG-EAGM-03 e a ação "Tentar novamente", sem nenhum item exibido.

**CA-001.7**: Dado que o médico navega para um dia sem nenhuma consulta nem bloqueio, então a tela exibe o estado vazio (EX-AGM-03) com MSG-TAGM-01; o botão "Bloquear horário" continua disponível se o dia for hoje ou futuro, e indisponível se o dia for passado.

**CA-001.8**: Dado que uma consulta é a primeira consulta do paciente, quando o item é exibido, então a tag "1ª Consulta" aparece junto às demais tags (RN-CM-028).

**CA-001.9**: Dado que o dia exibido é hoje, uma consulta das 09:00 ainda não foi iniciada e são 09:15, então o item exibe o sinalizador "Atrasado · 15min". Dado que o dia exibido não é hoje, então nenhum item exibe o sinalizador de atraso.

**CA-001.10**: Dado que uma consulta tem status "Recepcionado" (ou "Aguardando Recepção"), então o item exibe a borda lateral esquerda na cor secondary-pure (ou #FF8A80), como na Central do Médico.

**CA-001.11**: Dado que a tela está aberta com o dia carregado, quando passa 1 minuto, então a agenda do dia exibido é recarregada em segundo plano, refletindo mudanças de status, sem recolher blocos expandidos, sem perder a posição de rolagem e sem tirar o foco do elemento focado. Dado que a tela está no estado de erro de EX-AGM-02, então nenhuma atualização automática substitui esse estado.

**CA-001.12**: Dado que a agenda já está carregada e uma atualização automática falha, então os últimos dados permanecem visíveis e o indicador "Offline" aparece (EX-AGM-09); na próxima atualização bem-sucedida, o indicador some.

**CA-001.13**: Dado que o médico digita no campo de busca do cabeçalho, então o comportamento é o da Central do Médico, Seção 2.1 (critérios de aceitação de US-CM-000), e selecionar um paciente abre o PEP.

**CA-002.1**: Dado que o médico toca na seta sequencial "próximo dia", então a tela recarrega mostrando o dia seguinte ao atualmente exibido, independentemente de haver ou não consulta nele.

**CA-002.2**: Dado que o médico toca no atalho "próximo dia com consulta", então a tela pula diretamente para a data da próxima consulta não cancelada do médico, ignorando dias vazios, dias só com bloqueios e dias só com consultas canceladas.

**CA-002.3**: Dado que não existe nenhuma consulta futura não cancelada para o médico, quando a tela avalia o atalho "próximo dia com consulta", então o atalho aparece desabilitado (não há para onde pular).

**CA-002.4**: Dado que o médico abre o seletor de calendário, quando o mini-calendário é exibido, então os dias com ao menos uma consulta não cancelada aparecem marcados visualmente, diferenciados dos demais.

**CA-002.5**: Dado que o médico está em qualquer dia diferente de hoje, quando toca em "Hoje", então a tela recarrega mostrando o dia atual, com a rolagem na posição inicial descrita em "Linha AGORA".

**CA-002.6**: Dado que a consulta de dias com consulta falha (EX-AGM-06), então os dois atalhos de pular dias aparecem desabilitados e o calendário abre sem os dias marcados, enquanto as setas dia a dia e o botão "Hoje" continuam funcionando, sem mensagem de erro na tela.

**CA-003.1**: Dado que o médico toca em "Bloquear horário" num dia hoje ou futuro e escolhe um horário vago, quando confirma sem preencher o complemento, então o bloqueio é criado com sucesso e aparece na lista, na posição cronológica.

**CA-003.2**: Dado que o médico escolhe, no formulário de bloqueio, um intervalo que sobrepõe uma consulta ativa ou outro bloqueio, quando tenta confirmar, então o sistema impede a confirmação e exibe MSG-EAGM-01.

**CA-003.3**: Dado que o médico preenche o complemento com mais de 128 caracteres, quando tenta confirmar, então o sistema impede a confirmação e exibe MSG-EAGM-02.

**CA-003.4**: Dado que o back-end retorna erro ao tentar salvar um bloqueio já validado no front, então o sistema exibe o toast MSG-EAGM-04 (EX-AGM-04) e mantém o formulário aberto com os dados preenchidos.

**CA-003.5**: Dado que o dia exibido é anterior a hoje, então o botão "Bloquear horário" aparece indisponível; ao ser acionado, não abre o formulário e exibe MSG-TAGM-02.

**CA-003.6**: Dado que o dia exibido é hoje e são 10:07, quando o médico abre o formulário de bloqueio, então o primeiro horário de início oferecido é 10:15 e nenhum horário anterior aparece nas opções.

**CA-003.7**: Dado que o médico abriu o formulário hoje com início 10:15 selecionado, quando confirma às 10:16, então o sistema impede a confirmação e exibe MSG-EAGM-06 (EX-AGM-07), mantendo o formulário aberto com as opções de início atualizadas.

**CA-003.8**: Dado que existe uma consulta cancelada das 14:00 às 14:30, quando o médico bloqueia o intervalo das 14:00 às 14:30, então o bloqueio é criado normalmente (consulta cancelada não ocupa o horário).

**CA-003.9**: Dado que o médico escolhe a duração "Outro" e informa um valor que não é múltiplo de 15, menor que 15, ou que leva o término além do fim do dia, quando tenta confirmar, então o sistema impede a confirmação e exibe MSG-EAGM-08.

**CA-004.1**: Dado que o médico toca em "Desfazer bloqueio" num bloqueio que ainda não começou, quando toca em "Confirmar?" dentro de 5 segundos, então o item sai da lista e o horário volta a ficar vago.

**CA-004.2**: Dado que o médico toca em "Desfazer bloqueio" mas não toca em "Confirmar?" dentro de 5 segundos, então o botão volta ao estado normal, nenhuma alteração é feita e o item permanece bloqueado.

**CA-004.3**: Dado que o back-end retorna erro ao tentar remover um bloqueio já confirmado, então o sistema exibe o toast MSG-EAGM-05 (EX-AGM-05) e o item permanece na lista, marcado como bloqueado.

**CA-004.4**: Dado que um bloqueio já começou ou já terminou, então o item é exibido esmaecido, na sua posição de horário, sem a ação "Desfazer bloqueio".

**CA-004.5**: Dado que o botão está em "Confirmar?" e o horário de início do bloqueio chega antes do segundo toque, quando o médico confirma, então a remoção é recusada com MSG-EAGM-07 (EX-AGM-08) e o item passa a ser exibido sem a ação de desfazer.

**CA-004.6**: Dado que o bloqueio já foi desfeito em outra sessão, quando o médico confirma "Desfazer bloqueio", então o item sai da lista, o sistema exibe MSG-IAGM-01 e recarrega a agenda do dia (EX-AGM-10).

**CA-005.1**: Dado que existem consultas com status `finished` no dia, quando a tela carrega, então elas aparecem agrupadas no bloco recolhido "N consultas realizadas", no topo da lista, com a contagem correta.

**CA-005.2**: Dado que existem consultas com status `canceled` no dia (qualquer motivo, inclusive falta), quando a tela carrega, então elas aparecem agrupadas no bloco recolhido "N consultas canceladas", logo abaixo do bloco de realizadas, com o chip "Cancelado".

**CA-005.3**: Dado que o médico toca em um dos blocos, então só aquele bloco expande, revelando cada consulta individualmente; tocar de novo recolhe.

**CA-005.4**: Dado que nenhuma consulta do dia tem status `finished` (ou `canceled`), quando a tela carrega, então o bloco de realizadas (ou de canceladas) não aparece.

**CA-005.5**: Dado que o dia exibido é hoje, são 10:07 e há uma consulta Recepcionada das 09:45 ainda não iniciada, quando a tela carrega, então a linha "AGORA · 10:07" aparece na posição cronológica do horário atual e a rolagem deixa visível, abaixo das barras fixas, a consulta das 09:45. Dado que o dia exibido não é hoje, então a linha não aparece e a rolagem fica no topo.

**CA-005.6**: Dado que existe um bloqueio já ocorrido no dia, quando a tela carrega, então ele aparece como item individual na sua posição de horário, fora dos blocos recolhidos.

**CA-005.7**: Dado que o dia exibido é hoje e passa da meia-noite com a tela aberta, quando ocorre a próxima atualização automática, então o dia continua exibido, agora sem o rótulo "Hoje", sem a linha "AGORA" e com "Bloquear horário" indisponível.

**CA-006.1**: Dado que o médico criou um bloqueio para hoje, quando a Central do Médico carrega, então o bloqueio não aparece no painel de Consultas nem entra em nenhum número do indicador "Consultas Hoje" (RN-AGM-011; critério detalhado na Central do Médico, Seção 2.2/2.3).

### Fluxos de Exceção

**EX-AGM-01 — Horário de bloqueio sobreposto**

Gatilho: o médico tenta confirmar um bloqueio cujo intervalo sobrepõe uma consulta ativa ou outro bloqueio existente. Comportamento: a confirmação é impedida, com mensagem inline MSG-EAGM-01 apontando o conflito. Recuperação: o médico ajusta o horário e tenta novamente.

**EX-AGM-02 — Falha ao carregar a agenda do dia**

Gatilho: erro de rede ou falha do back-end ao buscar a agenda do dia solicitado, no carregamento inicial ou ao trocar de dia. Comportamento: estado de erro na tela (mensagem MSG-EAGM-03 + ação "Tentar novamente"), sem nenhum item exibido. Recuperação: o médico aciona "Tentar novamente"; se persistir, orientação a contatar o suporte. (Falha numa atualização automática, com a agenda já carregada, segue EX-AGM-09, não este fluxo.)

**EX-AGM-03 — Dia sem nenhuma consulta nem bloqueio**

Gatilho: o médico navega para um dia em que não há nenhuma consulta agendada nem horário bloqueado. Comportamento: estado vazio com mensagem orientativa MSG-TAGM-01; o botão "Bloquear horário" segue a regra normal (disponível hoje e no futuro, desabilitado no passado). Não é um erro — é um estado esperado (ex.: fim de semana, dia de folga).

**EX-AGM-04 — Falha ao criar bloqueio**

Gatilho: o back-end retorna erro ao tentar salvar um bloqueio já validado no front (ex.: condição de corrida — outro processo ocupou o horário entre a validação local e o envio). Comportamento: toast de erro MSG-EAGM-04 (ou MSG-EAGM-01 inline, se o back-end responder com conflito de horário); o formulário permanece aberto com os dados preenchidos. Recuperação: o médico escolhe outro horário ou tenta novamente.

**EX-AGM-05 — Falha ao desfazer bloqueio**

Gatilho: o back-end retorna erro ao tentar remover um bloqueio. Comportamento: toast de erro MSG-EAGM-05; o item permanece na lista, marcado como bloqueado. Recuperação: o médico tenta novamente.

**EX-AGM-06 — Falha ao carregar dias com consulta (atalho/calendário)**

Gatilho: erro de rede ou falha do back-end ao consultar quais dias têm consulta (atalho sequencial ou seletor de calendário). Comportamento: degradação silenciosa — o atalho de pular dias e o marcador de dias-com-consulta no calendário ficam indisponíveis (atalho desabilitado; calendário abre sem os dias marcados), sem interromper nem exibir erro na tela principal, já que a navegação dia a dia continua funcionando normalmente. Recuperação: o recurso volta ao normal na próxima tentativa de abrir o calendário ou de carregar um dia.

**EX-AGM-07 — Início do bloqueio já passou**

Gatilho: ao confirmar um bloqueio no dia de hoje, o horário de início escolhido já passou (o tempo avançou com o formulário aberto), ou o back-end recusa a criação por horário passado. Comportamento: a confirmação é impedida com MSG-EAGM-06 inline; as opções de início são recalculadas a partir do momento atual. Recuperação: o médico escolhe um novo horário de início.

**EX-AGM-08 — Bloqueio já começou ao desfazer**

Gatilho: o médico confirma "Desfazer bloqueio" depois de o horário de início do bloqueio já ter chegado (ex.: o tempo passou com o botão em "Confirmar?"), ou o back-end recusa a remoção por esse motivo. Comportamento: toast MSG-EAGM-07; o item permanece na lista, agora sem a ação de desfazer (RN-AGM-012). Recuperação: nenhuma — comportamento esperado da regra.

**EX-AGM-10 — Bloqueio já desfeito em outra sessão**

Gatilho: o back-end responde 404 ao `DELETE /blocks/{id}` (o bloqueio não existe mais no escopo do médico — ex.: desfeito em outro dispositivo). Comportamento: o item sai da lista, toast informativo MSG-IAGM-01 e recarga da agenda do dia. Recuperação: nenhuma necessária.

**EX-AGM-09 — Falha na atualização automática**

Gatilho: erro de rede ou falha do back-end numa atualização automática (RN-AGM-013), com a agenda do dia já carregada. Comportamento: os últimos dados permanecem na tela, com o indicador discreto "Offline" (MSG-TAGM-03) na barra de navegação do dia; nenhuma mensagem de erro em tela cheia. Recuperação: automática, na próxima atualização bem-sucedida.

### Validações de Campos

| Campo | Tipo | Obrigatório | Validação |
|---|---|---|---|
| Data do bloqueio | data (somente leitura) | Sim | Dia exibido na tela; deve ser hoje ou futuro (RN-AGM-012) — o formulário não abre em dia passado. |
| Início do bloqueio | seleção de horário, intervalos de 15 min | Sim | No dia de hoje, só horários posteriores ao momento atual; revalidado ao confirmar (EX-AGM-07, MSG-EAGM-06). |
| Duração do bloqueio | seleção (15/30/45/60/Outro) + número em minutos para "Outro" | Sim | "Outro": múltiplo de 15, mínimo 15; término (início + duração) não pode ultrapassar 24:00 do dia exibido (MSG-EAGM-08). O intervalo resultante não pode sobrepor consulta ativa nem outro bloqueio (EX-AGM-01). |
| Complemento (bloqueio) | texto livre | Não | Até 128 caracteres (mesmo limite do campo já usado nas consultas, RN-AGM-007). |

### Mapeamento de Componentes de Interface

| Componente | Variante | Estados | Tokens aplicados | Uso nesta tela |
|---|---|---|---|---|
| Cabeçalho do sistema | Clínica + busca + menu do usuário | — | Mesmo componente da Central do Médico, Seção 2.1/2.8 (Input Bordered, User Menu Dropdown) | Topo da tela (RN-AGM-014) |
| Card Highlight (Consulta) | Item de lista | default, hover, focus, recepcionado, aguardando, esmaecido (dentro dos blocos), loading | Mesma anatomia, cores por status e bordas já definidas na Central do Médico (Seção 2.3/2.8) | Cada consulta do dia |
| Avatar | Iniciais na cor do status | default | bg: cor do status (paleta da Central, Seção 2.3; Cancelado: `color-neutral-light`); texto: `color-neutral-darker` | Consulta sem foto do paciente |
| Card | Item bloqueado | default, hover, past | `color-neutral-lighter` bg, ícone de cadeado (Lucide `lock`); past: opacidade reduzida (mesma das consultas finalizadas da Central) | Cada horário bloqueado |
| Chip | Status (consulta) | default | Paleta da Central (RN-CM-005/Seção 2.3) + Cancelado: bg `color-neutral-light`, texto `color-neutral-dark` | Status de cada consulta |
| Badge | Atraso | default (pulsante) | Mesmo componente da Central (bg `color-error-pure`, texto `color-base-pure`) | Consultas atrasadas, só no dia de hoje |
| Chip | Tag do paciente / 1ª Consulta | default | Cor da própria tag (cadastro) e cor fixa de "1ª Consulta" — mesmas da Central | Tags exibidas por consulta |
| Chip | Tipo de consulta | default | `color-neutral-lighter` bg, `color-neutral-darker` texto | Quando a clínica configurou tipos de consulta |
| Accordion/Collapsible | Bloco de realizadas / bloco de canceladas | recolhido, expandido | `radius-m`, `color-neutral-lighter` bg quando recolhido; ícone Lucide `check-circle` (realizadas) e `x-circle` (canceladas) | Blocos de RN-AGM-010 |
| Divider com rótulo | Linha "AGORA" | default | `color-error-pure` (linha e texto) | Posição do horário atual, só no dia de hoje |
| Button | Secondary (Bloquear horário) | default, hover, indisponível (`aria-disabled`) | Mesmos tokens de botão secundário já usados na Central (Seção 2.8) | Barra de navegação do dia |
| Button | Tertiary (Desfazer bloqueio) | default, hover, confirming | `color-error-pure` texto no estado "confirming" ("Confirmar?", 5 s) | Item bloqueado futuro |
| Modal/Bottom Sheet | Formulário de bloqueio | default, loading, error | Mesma anatomia de modal já usada no Design System; bottom sheet em telas estreitas | Fluxo de bloqueio de horário |
| Segmented/Radio pill | Duração do bloqueio | active, inactive | Mesmos tokens do Toggle Pill da Central | 15/30/45/60/Outro |
| Date Picker (calendário) | Mini-calendário mensal | default, dia-com-consulta, hoje, selecionado | Ponto sob o número do dia que tem consulta | Seletor de data |
| Indicador | Offline | default | Ícone Lucide `wifi-off`, texto `color-neutral-pure` — mesmo padrão da Central (Seção 2.7) | EX-AGM-09 |
| Toast | Error | default | `color-error-pure` | EX-AGM-04, 05, 08 |
| Empty/Error State | Tela cheia (sem itens) | error | `color-error-pure` ícone e texto, botão "Tentar novamente" | EX-AGM-02 |
| Empty/Error State | Tela cheia (sem itens) | empty | Mesma anatomia do estado de erro, sem o botão "Tentar novamente" | EX-AGM-03 |
| Skeleton | Lista | loading | `color-neutral-lighter` | Carregamento de um dia |

### Integração com Backend

**GET /api/v1/patients/search** — endpoint da Central do Médico (Seção 2.9), reutilizado sem mudança pela busca do cabeçalho.

**GET /api/v1/agenda/doctor/day**

Função: retorna a agenda do médico logado para um dia específico — consultas (de qualquer status, inclusive canceladas) e horários bloqueados.
Query params: `date` (obrigatório, `YYYY-MM-DD`).
Polling: a cada 1 minuto, para o dia exibido (RN-AGM-013).
Códigos: 200 (sucesso); 400 (`date` ausente ou inválida); 500 (falha — EX-AGM-02 no carregamento, EX-AGM-09 no polling).
Response 200: `{ "date": "2026-09-29", "serverNow": "2026-09-29T10:07:00-03:00", "items": [ { "kind": "appointment", "id": "uuid", "patient": { "id": "uuid", "preferredName": "", "legalName": "Maria da Silva", "photo": "url|null", "diagnosis": ["Ca. Mama"] }, "startTime": "08:00", "endTime": "08:30", "status": "finished", "attendanceMode": "Presencial", "delayMinutes": 0, "firstTime": false, "tags": ["vip"], "complement": "string|null", "appointmentType": "string|null" }, { "kind": "block", "id": "uuid", "startTime": "12:00", "endTime": "13:00", "complement": "Reunião administrativa|null" } ] }`
- `status`: presente só quando `kind = "appointment"`; um dos valores de `AppointmentStatus()` da Central do Médico (Seção 4.1): `scheduled | waiting | checked | consultation | finished | canceled` — mesma função, reutilizada. Não confundir com o campo `result` da resposta de `DELETE /blocks/{id}`.
- `delayMinutes`: mesma regra do campo homônimo da Central do Médico (Seção 2.9/4.1) — minutos de atraso, positivo só quando o horário de início já passou e a consulta não foi iniciada nem finalizada; sempre `0` quando `date` não é hoje (no fuso da clínica). O front exibe o sinalizador quando `delayMinutes > 0`.
- `serverNow`: data e hora atuais do servidor, no fuso da clínica (ISO 8601 com deslocamento) — referência de tempo da tela (ver "Referência de tempo", no início desta Seção).
- `tags`: já filtradas pelo back-end pelo critério de RN-CM-025 (RN-AGM-006) — o front não faz esse filtro. Nunca contém a tag "1ª Consulta": ela é derivada de `firstTime` (boolean), que faz o front exibi-la (RN-CM-028). Cor e descrição de cada tag: mesmo contrato do endpoint de consultas da Central do Médico — lacuna registrada no Histórico de Versões desta Especificação, a resolver na Seção 4.
- `attendanceMode`: modo de atendimento, já traduzido para o idioma da clínica (mesma origem do campo homônimo da Central do Médico, Seção 4.1 — termo de `TermoTraducao`), ex. "Presencial", "Teleatendimento" — distinto de `appointmentType` (RN-AGM-008).
- `startTime`/`endTime`: `HH:MM` no fuso da clínica; `endTime = "24:00"` indica o fim exato do dia (bloqueio até a meia-noite).
- Itens `kind = "block"` são os registros de bloqueio (RN-AGM-004) — não têm `patient`, `status`, `tags` nem `delayMinutes`.
- Mapeamento de BD: Seção 4 (a escrever).

**GET /api/v1/agenda/doctor/days-with-appointments**

Função: retorna as datas, dentro de um intervalo limitado, que têm ao menos uma consulta não cancelada do médico logado — usado pelo marcador visual do seletor de calendário (RN-AGM-003), que exibe um mês por vez. Bloqueios e consultas canceladas não contam.
Query params: `from` (obrigatório, `YYYY-MM-DD`), `to` (obrigatório, `YYYY-MM-DD`; intervalo máximo de 62 dias).
Códigos: 200; 400 (datas inválidas ou intervalo acima do máximo); 500 (EX-AGM-06).
Response 200: `{ "dates": ["2026-10-01", "2026-10-03", "2026-10-08"] }`
- O front consulta o mês exibido no mini-calendário a cada abertura/navegação de mês. Não é usado pelo atalho de pular dias — ver `GET /next-appointment-date`.

**GET /api/v1/agenda/doctor/next-appointment-date**

Função: retorna a data da próxima (ou anterior) consulta não cancelada do médico logado, sem limite de horizonte — usado pelo atalho sequencial de pular dias (RN-AGM-003). Bloqueios e consultas canceladas não contam.
Query params: `direction` (obrigatório, `next` ou `previous`), `from` (obrigatório, `YYYY-MM-DD` — data de referência, normalmente o dia exibido; a própria data de referência não é considerada).
Chamado a cada carregamento de dia e a cada atualização automática, uma vez por direção.
Códigos: 200; 400 (parâmetros inválidos); 500 (EX-AGM-06).
Response 200: `{ "date": "2026-10-15" }` ou `{ "date": null }` quando não há nenhuma consulta naquela direção (CA-002.3 usa esse `null` para desabilitar o atalho).

**POST /api/v1/agenda/doctor/blocks**

Função: cria um bloqueio de horário na agenda do médico logado (RN-AGM-004, RN-AGM-012).
Request: `{ "date": "2026-09-29", "startTime": "12:00", "endTime": "13:00", "complement": "string|null" }`
Response 201: `{ "kind": "block", "id": "uuid", "date": "2026-09-29", "startTime": "12:00", "endTime": "13:00", "complement": "string|null" }`
Códigos: 201 (sucesso); 400 (dados inválidos — horário fora da grade de 15 min ou término além do fim do dia, exibido como MSG-EAGM-08 inline; complemento acima de 128 caracteres, MSG-EAGM-02 inline); 409 (conflito com consulta ativa ou outro bloqueio — EX-AGM-01, MSG-EAGM-01); 422 (início no passado — EX-AGM-07, MSG-EAGM-06); 500 (falha ao salvar — EX-AGM-04).
Tabelas envolvidas e mecanismo do registro de bloqueio: Seção 4 (a escrever).

**DELETE /api/v1/agenda/doctor/blocks/{id}**

Função: desfaz um bloqueio de horário que ainda não começou (US-AGM-004, RN-AGM-012).
Response 200: `{ "id": "uuid", "result": "removed" }`
Códigos: 200 (sucesso); 404 (bloqueio não encontrado — cobre tanto "já desfeito por outra sessão" quanto "não pertence ao médico logado": como o endpoint é escopado ao médico da sessão (RN-AGM-002), um bloqueio de outro médico simplesmente não existe nesse escopo — não há um 403 separado, para não revelar a outro médico que aquele horário está bloqueado — tratamento no front: EX-AGM-10); 422 (bloqueio já começou ou já terminou — EX-AGM-08, MSG-EAGM-07); 500 (falha ao remover — EX-AGM-05).

### Catálogo de Mensagens do Sistema e Termos de Interface (i18n)

Mensagens da busca do cabeçalho: ver Central do Médico, Seção 2.1 (`MSG_searchPac`, `MSG_searchFoot`, `MSG_searchMin`, `MSG_searchNone`). Rótulos de status e "Atrasado": ver Central do Médico, Seção 2.3 — o rótulo "Cancelado" é o termo `status-cancelado` da Central do Médico, Seção 2.6.

| ID | Contexto | pt-BR | en-US | es-419 |
|---|---|---|---|---|
| MSG-EAGM-01 | Horário de bloqueio sobreposto (EX-AGM-01) | "Esse horário já está ocupado por uma consulta ou outro bloqueio." | "That time slot is already taken by an appointment or another block." | "Ese horario ya está ocupado por una consulta u otro bloqueo." |
| MSG-EAGM-02 | Complemento acima do limite | "O complemento pode ter no máximo 128 caracteres." | "The note can have at most 128 characters." | "La nota puede tener como máximo 128 caracteres." |
| MSG-EAGM-03 | Falha ao carregar a agenda do dia (EX-AGM-02) | "Não foi possível carregar a agenda. Tente novamente." | "Could not load the schedule. Please try again." | "No fue posible cargar la agenda. Inténtelo de nuevo." |
| MSG-EAGM-04 | Falha ao criar bloqueio (EX-AGM-04) | "Não foi possível bloquear este horário. Tente novamente." | "Could not block this time slot. Please try again." | "No fue posible bloquear este horario. Inténtelo de nuevo." |
| MSG-EAGM-05 | Falha ao desfazer bloqueio (EX-AGM-05) | "Não foi possível desfazer o bloqueio. Tente novamente." | "Could not undo the block. Please try again." | "No fue posible deshacer el bloqueo. Inténtelo de nuevo." |
| MSG-EAGM-06 | Início do bloqueio no passado (EX-AGM-07) | "Esse horário já passou. Escolha um horário futuro." | "That time has already passed. Choose a future time." | "Ese horario ya pasó. Elija un horario futuro." |
| MSG-EAGM-07 | Bloqueio já começou ao desfazer (EX-AGM-08) | "Este bloqueio já começou e não pode mais ser desfeito." | "This block has already started and can no longer be undone." | "Este bloqueo ya comenzó y ya no se puede deshacer." |
| MSG-EAGM-08 | Duração inválida | "Informe uma duração em múltiplos de 15 minutos, terminando até o fim do dia." | "Enter a duration in multiples of 15 minutes, ending by the end of the day." | "Indique una duración en múltiplos de 15 minutos, que termine antes del fin del día." |
| MSG-TAGM-01 | Dia sem consulta nem bloqueio (EX-AGM-03) | "Nenhuma consulta ou bloqueio neste dia." | "No appointments or blocks on this day." | "Ninguna consulta o bloqueo en este día." |
| MSG-TAGM-02 | Dica do botão de bloqueio desabilitado em dia passado | "Não é possível bloquear horários em dias passados." | "Time slots cannot be blocked on past days." | "No es posible bloquear horarios en días pasados." |
| MSG-TAGM-03 | Indicador de atualização com falha (EX-AGM-09) | "Offline" | "Offline" | "Sin conexión" |
| MSG-TAGM-04 | Botão de bloqueio indisponível hoje (sem horário restante) | "Não há mais horários disponíveis hoje." | "There are no more time slots available today." | "No hay más horarios disponibles hoy." |
| MSG-TAGM-05 | Legenda do calendário | "Dia com consulta" | "Day with appointments" | "Día con consultas" |
| MSG-TAGM-06 | Calendário sem marcadores (EX-AGM-06) | "Marcadores indisponíveis no momento." | "Markers are unavailable right now." | "Marcadores no disponibles en este momento." |
| MSG-SAGM-01 | Sucesso ao bloquear | "Horário bloqueado: {início} - {fim}." | "Time slot blocked: {start} - {end}." | "Horario bloqueado: {inicio} - {fin}." |
| MSG-SAGM-02 | Sucesso ao desfazer | "Bloqueio desfeito. O horário voltou a ficar vago." | "Block undone. The time slot is free again." | "Bloqueo deshecho. El horario volvió a quedar libre." |
| MSG-IAGM-01 | Bloqueio já desfeito em outra sessão (EX-AGM-10) | "Este bloqueio já tinha sido desfeito." | "This block had already been undone." | "Este bloqueo ya había sido deshecho." |
| MSG-BAGM-01 | Botão de bloqueio de horário | "Bloquear horário" | "Block time slot" | "Bloquear horario" |
| MSG-BAGM-02 | Botão de desfazer bloqueio | "Desfazer bloqueio" | "Undo block" | "Deshacer bloqueo" |
| MSG-BAGM-03 | Botão de voltar para hoje | "Hoje" | "Today" | "Hoy" |
| MSG-BAGM-04 | Rótulo do item bloqueado | "Bloqueado" | "Blocked" | "Bloqueado" |
| MSG-BAGM-05 | Estado de confirmação rápida do desfazer | "Confirmar?" | "Confirm?" | "¿Confirmar?" |
| MSG-BAGM-06 | Botão do formulário de bloqueio | "Confirmar bloqueio" | "Confirm block" | "Confirmar bloqueo" |
| MSG-BAGM-07 | Bloco de realizadas (singular / plural) | "1 consulta realizada" / "{n} consultas realizadas" | "1 completed appointment" / "{n} completed appointments" | "1 consulta realizada" / "{n} consultas realizadas" |
| MSG-BAGM-08 | Bloco de canceladas (singular / plural) | "1 consulta cancelada" / "{n} consultas canceladas" | "1 canceled appointment" / "{n} canceled appointments" | "1 consulta cancelada" / "{n} consultas canceladas" |
| MSG-BAGM-09 | Linha do horário atual | "AGORA · {hh:mm}" | "NOW · {hh:mm}" | "AHORA · {hh:mm}" |
| MSG-BAGM-11 | Rótulos do formulário de bloqueio | "Data" / "Início" / "Duração" / "Outro" / "minutos (múltiplos de 15)" / "Término" / "Complemento (opcional)" / "(hoje)" | "Date" / "Start" / "Duration" / "Other" / "minutes (multiples of 15)" / "End" / "Note (optional)" / "(today)" | "Fecha" / "Inicio" / "Duración" / "Otro" / "minutos (múltiplos de 15)" / "Fin" / "Nota (opcional)" / "(hoy)" |
| MSG-BAGM-12 | Botões genéricos da tela | "Tentar novamente" / "Cancelar" / "Salvando…" | "Try again" / "Cancel" / "Saving…" | "Intentar de nuevo" / "Cancelar" / "Guardando…" |

### Conformidade SBIS (detalhamento)

**ECF.05.02 — Bloqueios na agenda** (estágio 2, recomendado) — **atendimento parcial** (ver Definição, tabela SBIS): o requisito pede parametrização de bloqueios da clínica em dias específicos (fins de semana, feriados), que pertence à parametrização de agendas; esta tela cobre o bloqueio pontual pelo médico. O fluxo de bloqueio de horário (US-AGM-003/004, `POST`/`DELETE /api/v1/agenda/doctor/blocks`) implementa este requisito, com as restrições de tempo de RN-AGM-012; o mecanismo de persistência (paciente/convênio reservados) é detalhado na Seção 4, quando escrita, junto da subseção "Seeds da Funcionalidade".

**ECF.05.04 — Especificação do tipo de consulta** (estágio 2, recomendado) — atendido pela exibição do tipo de consulta em cada item da lista, quando configurado pela clínica (RN-AGM-008).

**ECF.03.11 / ECF.03.14 — Busca simples de pacientes / Dados da lista de pacientes para seleção de prontuários** (estágio 1, obrigatórios) — atendidos pela busca do cabeçalho, reutilizada da Central do Médico (RN-AGM-014); detalhamento na Central do Médico, Seção 2.10.

**NGS1.07.03 / NGS1.07.04 — Eventos registrados na trilha de auditoria** (estágio 1 / 2) — a leitura da agenda de um dia (`GET /day` no carregamento de um dia — a lista expõe nome e diagnóstico de pacientes; o polling não gera novo evento para o mesmo dia), a abertura do PEP a partir dela e a criação e a remoção de um bloqueio (`POST`/`DELETE` acima) devem gerar evento de auditoria, mesmo padrão já usado em outras funcionalidades assistenciais deste projeto (RN-AGM-004).

**ECF.17.19 — Mensagens do sistema** (estágio 1, obrigatório) — todas as mensagens exibidas ao médico estão catalogadas acima (ou na Central do Médico, para os elementos reutilizados), em linguagem não técnica, em português do Brasil, com suporte multilíngue para en-US e es-419.

---

## Histórico de Versões

- **v1.0** (31/08/2026) — Arquivo criado. Especificação completa a partir das RNs fechadas na Seção 1 (v1.5): cabeçalho de navegação (RN-AGM-003, com os dois mecanismos de atalho confirmados pelo solicitante — setas de atalho e seletor de calendário), lista de consultas com os elementos herdados e os dois campos novos (RN-AGM-006/007/008/009), bloco de consultas já realizadas (RN-AGM-010), e o fluxo completo de bloqueio de horário (RN-AGM-004), incluindo a confirmação do solicitante de que o próprio médico pode desfazer um bloqueio e que o complemento é opcional nesse fluxo. Duas decisões de UI ainda não pedidas ao solicitante ficaram marcadas **[PROPOSTA]** no corpo (granularidade de horário do formulário de bloqueio; confirmação leve inline ao desfazer) — a confirmar antes do Protótipo (Seção 3). Deixado **[A DEFINIR]** se um bloqueio já ocorrido também deveria entrar no bloco recolhido de RN-AGM-010, por não estar coberto pela redação literal da regra.
- **v1.0 (revisão)** (01/09/2026) — Submetido ao subagente crítico técnico antes de fechar a fase (Lição #20). Achados verificados contra o texto e corrigidos: (1) campo `type` renomeado para `attendanceMode` no JSON de exemplo, com nota de nomenclatura no corpo distinguindo-o de `appointmentType` — nomes muito parecidos, campos diferentes; (2) removido o campo `delayMinutes` do JSON de exemplo — não estava descrito em nenhuma regra nem na lista de elementos exibidos, ficou como campo "fantasma"; (3) resposta do `DELETE /blocks/{id}` renomeada de `status` para `result`, evitando colisão de nome com o `status` de atendimento clínico usado no `GET /day`; (4) adicionado `"kind": "block"` na resposta do `POST /blocks`, alinhando com o formato do item de bloqueio já usado no `GET /day`; (5) adicionadas CA-001.6, CA-001.7, CA-003.4 e CA-004.3, cobrindo os quatro Fluxos de Exceção (EX-AGM-02/03/04/05) que não tinham nenhum Critério de Aceitação correspondente; (6) corrigida a tabela de Mapeamento de Componentes — EX-AGM-02 estava listado como "Toast", mas o texto do próprio fluxo descreve um estado de erro em tela cheia; criadas linhas próprias para os estados de erro/vazio de tela cheia (EX-AGM-02, EX-AGM-03), mantendo Toast só para EX-AGM-04/05; (7) qualificada a linha "AGORA" (RN-AGM-010) como exclusiva do dia de hoje — em outro dia a lista abre no topo, sem a linha; (8) identificada e resolvida a tensão entre RN-AGM-003 ("sem limite de horizonte") e o endpoint `days-with-appointments`, que exige `from`/`to` limitados: criado um segundo endpoint, `GET /next-appointment-date`, sem limite de intervalo, dedicado ao atalho sequencial — `days-with-appointments` passa a servir só o marcador visual do calendário (mês exibido); (9) criado EX-AGM-06 (falha ao consultar dias com consulta), cobrindo um cenário de erro que não tinha nenhum tratamento especificado, com degradação silenciosa por não ser caminho crítico; (10) removido o código 403 do `DELETE /blocks/{id}` — como o endpoint já é escopado ao médico logado (RN-AGM-002), um bloqueio de outro médico não é alcançável nesse escopo; consolidado em 404, evitando revelar a existência de bloqueios de outros médicos; (11) adicionada validação **[PROPOSTA]** impedindo bloqueio de horário já no passado — não pedida ao solicitante, a confirmar. Nenhum achado do crítico foi descartado como falso positivo nesta rodada.
- **v1.1** (29/09/2026) — Acompanha 01-Definição v1.6 (alinhamento com a Central do Médico e decisões do solicitante desta rodada). **Pedidos/decisões do solicitante:** (1) cabeçalho com a mesma busca de pacientes da Central do Médico — nova subseção "Cabeçalho do Sistema", reutilizando por referência a Seção 2.1 da Central (US-CM-000, mensagens `MSG_search*`, `GET /api/v1/patients/search`), e a barra de navegação do dia passa a ficar abaixo dele; (2) bloqueio já ocorrido permanece como item individual — resolvido o **[A DEFINIR]** da v1.0, com CA-005.6; (3) bloqueio no passado proibido — **[PROPOSTA]** da v1.0 confirmada (RN-AGM-012): botão desabilitado em dias passados (CA-001.7 ajustado, CA-003.5 novo), opções de início só futuras no dia de hoje (CA-003.6), revalidação ao confirmar (EX-AGM-07, MSG-EAGM-06, CA-003.7, código 422 no `POST`); extensão ao desfazer — só antes de o bloqueio começar (EX-AGM-08, MSG-EAGM-07, CA-004.4/004.5, código 422 no `DELETE`); (4) selo de atraso como na Central — `delayMinutes` volta ao JSON de `GET /day` (tinha sido removido na revisão técnica da v1.0 como campo "fantasma", mas é um elemento herdado da Central), exibido só no dia de hoje (CA-001.9); (5) consultas realizadas e canceladas em dois blocos separados, não num bloco único "já realizadas" (que misturava canceladas e faltas sob um rótulo de "realizadas") — subseção reescrita, CA-005.1 a 005.4, MSG-BAGM-07/08; (6) as duas **[PROPOSTA]** de UI da v1.0 confirmadas: formulário com intervalos de 15 minutos e durações 15/30/45/60/Outro (detalhado: campo de data somente leitura, término calculado, limite no fim do dia, validação de "Outro" — MSG-EAGM-08, CA-003.9, código 400) e desfazer com confirmação rápida inline — o intervalo de "alguns segundos" da v1.0 foi fixado em 5 segundos, valor escolhido pelo Designer nesta versão, sujeito a ajuste. **Alinhamento com a Central do Médico (aprovado pelo solicitante):** tags pelo critério de RN-CM-025 (CA-001.2 reescrito — antes citava só o bit de agendas) e tag "1ª Consulta" por RN-CM-028 (CA-001.8); status `canceled` com chip "Cancelado" em token neutro (`color-neutral-light`/`color-neutral-dark`) — a paleta da Central não tinha esse status porque a Central não exibe canceladas; destaque por borda lateral de "Recepcionado"/"Aguardando Recepção" (CA-001.10); lista de valores de `status` explicitada como a de `AppointmentStatus()` da Central (Seção 4.1); atualização automática a cada 1 minuto e indicador "Offline" (RN-AGM-013 — CA-001.11/001.12, EX-AGM-09, MSG-TAGM-03); indicador "Consultas Hoje" da Central como segundo ponto de entrada (CA-001.1); bloqueios fora do painel e do KPI da Central (RN-AGM-011 — CA-006.1, detalhe na Central do Médico, Especificação v4.37). **Outros ajustes desta versão:** (a) a linha "AGORA" passa a ser posicionada cronologicamente entre os itens individuais, não mais "logo abaixo do bloco" — ajuste necessário porque, com bloqueios já ocorridos e consultas atrasadas permanecendo como itens individuais, a descrição anterior colocaria a linha acima de itens anteriores ao horário atual (esclarecimento de comportamento, proposto pelo Designer); (b) atalho "próximo dia com consulta", marcador do calendário e endpoints `days-with-appointments`/`next-appointment-date` passam a ignorar bloqueios (consequência de RN-AGM-011) e consultas canceladas (proposta do Designer, ver Histórico da Definição v1.6); (c) mecanismo do registro de bloqueio (paciente/convênio reservados, `TipoAgenda = 'C'` como default, decidido pelo solicitante) deixa de ser citado no corpo do `POST` — fica para a Seção 4; (d) layout mobile-first explicitado (premissa da Definição v1.6), com comportamento do cabeçalho e da barra em telas estreitas; (e) formulário de bloqueio como modal / bottom sheet (a v1.0 deixava "modal ou tela dedicada" para a Seção 3); (f) nova linha de componentes: cabeçalho do sistema, badge de atraso, pill de duração, indicador offline; estado "past" do item bloqueado; (g) nova subseção de conformidade ECF.03.11/03.14 (por referência). Acompanha 03-Protótipo v1.0.
- **v1.1 — Revisão por Dois Críticos** (29/09/2026, mesma versão, antes da entrega ao solicitante) — Crítico técnico (subagente independente, com execução do protótipo no Playwright em 360px e 1280px) sobre esta Especificação e o Protótipo v1.0; 30 achados, cada um verificado contra o texto/código antes de aplicar. **Aplicados nesta Especificação:** (1) posição inicial da rolagem escondia consultas atrasadas ainda pendentes atrás das barras fixas (medido) — rolagem passa a ir para a primeira consulta que ainda exige ação, com deslocamento pela altura real das barras (CA-005.5 reescrito; mesmo achado do crítico de negócio); (2) referência de tempo ambígua (relógio do dispositivo × fuso da clínica) — novo campo `serverNow` em `GET /day` e parágrafo "Referência de tempo"; regra de virada do dia (CA-005.7); (3) polling podia substituir o estado de erro de EX-AGM-02 e o skeleton (medido) — polling só com o dia carregado (CA-001.11 ampliado), sem perda de foco e sem anunciar a lista inteira a leitores de tela; (4) estado "Confirmar?" sofria condição de corrida com re-renderizações (reproduzido) — explicitado que o estado pertence ao item; (5) `DELETE` 404 sem tratamento — novo EX-AGM-10, MSG-IAGM-01, CA-004.6; `POST` 400 mapeado para MSG-EAGM-08/02; (6) EX-AGM-06 era o único fluxo de exceção sem CA — novo CA-002.6; (7) textos exibidos fora do catálogo — incluídos MSG-TAGM-04/05/06, MSG-SAGM-01/02, MSG-BAGM-12 e novos rótulos em MSG-BAGM-11; "Cancelado" passa a reutilizar o termo `status-cancelado` da Central do Médico, Seção 2.6 (MSG-BAGM-10 removida — tinha es-419 divergente, "Cancelada"); (8) dica do botão desabilitado via `title` não chega ao toque nem ao teclado — botão passa a `aria-disabled`, com toast ao acionar (CA-003.5 reescrito); (9) contraste do avatar com texto branco sobre as cores claras de status (1,27:1 a 1,66:1) — texto `color-neutral-darker`; nova linha "Avatar" nos componentes; (10) `attendanceMode` tinha três representações (código no JSON, termo traduzido no Mapeamento da Central, rótulo no protótipo) — declarado como termo já traduzido, igual à Central 4.1, exemplo corrigido; (11) `firstTime` boolean e `tags` nunca contém "1ª Consulta" (evita duplicidade com a Central, que lista `1a_consulta` como valor de `tags`); (12) "24:00" declarado explicitamente em `endTime`; (13) códigos 400/500 dos GETs, intervalo máximo de 62 dias em `days-with-appointments` (valor escolhido pelo Designer — dois meses de calendário) e momento de chamada de `next-appointment-date`; (14) auditoria da leitura da agenda (`GET /day`) e da abertura do PEP; (15) acessibilidade do formulário (foco preso, `aria-invalid`), alvos de toque de 44px em telas estreitas, itens dos blocos expandidos esmaecidos como na Central, complemento validado sem espaços nas pontas com o contador contando o mesmo valor; (16) ECF.05.02 como atendimento parcial e títulos/estágios corretos de ECF.03.11/03.14 (conferidos na planilha SBIS — ver Definição v1.6). **Registrados como pendência, sem mudança:** o contrato de `tags` (strings) não traz cor nem descrição, embora a cor venha do cadastro da tag (RN-CM-025) — o endpoint de consultas da Central tem a mesma lacuna; a resolver junto com a Seção 4 das duas funcionalidades. **Não aplicados:** contraste de textos secundários (`color-neutral-medium`/`neutral-pure`) e da tag de quimioterapia, e divergência do par de cores do chip "Finalizado" — padrões pré-existentes da Central/Design System, fora do escopo desta revisão; prefixo AGM nos IDs de CA — o padrão atual `CA-00X.Y` é o mesmo da v1.0 e de outros documentos; padrão combobox completo da busca — comportamento da Central, registrado como achado para aquele documento.
