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

**Documentos desta funcionalidade:** [01 - Definição](./01%20-%20Defini%C3%A7%C3%A3o%20v1.7.md) (v1.7) · [02 - Especificação](./02%20-%20Especifica%C3%A7%C3%A3o%20v1.2.md) (v1.2) · [03 - Protótipo](./03%20-%20Prot%C3%B3tipo%20v1.1.md) (v1.1, código executável em `03 - Protótipo v1.1.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), de um horário livre ou de 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. A área fixa no topo (cabeçalho do sistema + barra do dia) é mantida no mínimo — cerca de 116px no celular, nunca mais que 120px — para que a lista, que é o conteúdo, ocupe a maior parte da tela. Todo alvo de toque (botões, dias do calendário, opções de duração, ações de bloqueio, horários livres) 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 estado "Hoje", a linha "AGORA", o sinalizador de atraso, os horários livres, as opções de início do bloqueio e a disponibilidade das ações de 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 livre e futuro dentro do meu horário de trabalho, de preferência tocando no próprio horário livre, para reservar tempo para atividades não assistenciais (reunião, ausência).
- **US-AGM-004:** Como médico, quero desfazer um bloqueio da minha agenda que ainda não começou — criado por mim ou pela Recepção para mim — 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 resumidas, 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-AGM-006:** Como médico, quero encerrar antes do fim um bloqueio em andamento, para liberar o restante do horário quando a atividade acabou mais cedo.
- **US-AGM-007:** Como médico, quero ver onde há horários livres no meu dia, para saber de relance se cabe um encaixe ou uma reserva de tempo.
- **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 e o logotipo é reduzido para dar largura ao campo de busca; busca e avatar continuam sempre visíveis; a altura do cabeçalho (64px) é a mesma da Central.

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 (RN-AGM-003)

Barra fixa logo abaixo do cabeçalho do sistema, **em uma única linha** (52px no celular, 56px em telas largas), com, da esquerda para a direita:

1. **Seta "dia anterior" (‹)** — retrocede um dia.
2. **Data exibida, como botão** — no celular, forma curta ("Hoje, Ter, 29 set" quando é hoje; "Qua, 30 set" nos demais dias); em telas largas, forma longa ("Terça-feira, 29 de setembro"), com um indicador de seta para baixo. **Tocar na data abre o seletor de calendário** (ver abaixo) — não há um botão de calendário separado. Quando uma atualização automática falha, um ícone discreto de "sem conexão" aparece dentro deste botão (EX-AGM-09).
3. **Seta "próximo dia" (›)** — avança um dia.
4. **Botão "Hoje"** — sempre visível. Quando o dia exibido é hoje, fica no estado ativo (destacado, `aria-current="date"`, sem ação) — esse estado substitui um rótulo "Hoje" separado; nos demais dias, retorna ao dia atual em um toque.
5. **Telas largas:** os atalhos "dia anterior com consulta" («) e "próximo dia com consulta" (») ficam ao lado das setas, e o botão **"Bloquear horário"** fica à direita da barra.
6. **Celular:** menu **"Mais opções" (⋮)** à direita, com três itens: "Bloquear horário"; "Próximo dia com consulta" e "Dia anterior com consulta", cada um com a data de destino escrita abaixo (ex.: "qua, 07/10"), ou "Nenhum" quando não há dia naquela direção (item indisponível).

Atalhos de dia com consulta: pulam 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). Ficam indisponíveis quando não há nenhum dia com consulta naquela direção.

"Bloquear horário" (botão em telas largas, item de menu no celular): **indisponível** em dias passados (MSG-TAGM-02), em dias sem horário de trabalho do médico (MSG-TAGM-07) e, no dia de hoje, quando não resta nenhum horário de início possível dentro do horário de trabalho (MSG-TAGM-04). Indisponível significa 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 a mensagem do motivo em snackbar. No celular, a forma principal de bloquear é tocar num **horário livre** da lista (RN-AGM-016); o item do menu cobre o caso de escolher o horário no formulário.

**Seletor de calendário** — abre como bottom sheet no celular e como painel sobre a lista em telas largas, com: no topo, os dois atalhos com rótulo e data de destino ("Próximo dia com consulta · qua, 07/10" / "Dia anterior com consulta · ter, 23/09"); abaixo, o mini-calendário mensal com navegação entre meses, o dia de hoje e o dia exibido destacados, e um ponto sob os dias com ao menos uma consulta não cancelada (mesmo critério dos atalhos). Selecionar um dia fecha o seletor e carrega a agenda daquele dia; o foco vai para o dia exibido ao abrir.

Motivador: a revisão com um médico mostrou que, na barra, o uso frequente é a data, "Hoje" e as setas dia a dia; os atalhos de dia com consulta e o bloqueio são de uso eventual — ficam a um toque a mais, com rótulo explícito (o ícone de seta dupla, sozinho, não é entendido), liberando a linha para o que se usa sempre. Em telas largas, onde há espaço, tudo fica visível na mesma linha.

#### Lista do Dia

Itens em ordem cronológica pelo horário de início: consultas, bloqueios e horários livres (RN-AGM-016), com a linha "AGORA" no dia de hoje. Todo item tem, à esquerda, uma **coluna de horário** de largura fixa: horário de início em destaque e horário de término abaixo, menor. A coluna fixa cria um eixo de leitura estável — agenda se lê pela hora.

**Item de consulta** (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), com anatomia fixa:

- **Linha 1:** nome do paciente (preferido, com o nome legal como alternativa; truncado com reticências se não couber) e, à direita, o **status** (chip colorido, mesma paleta e rótulos da Central — Agendado, Aguardando Recepção, Recepcionado, Em Atendimento, Finalizado — mais **Cancelado**, exclusivo desta tela). O status é sempre exibido, inclusive "Agendado".
- **Linha 2:** diagnóstico(s) oncológico(s), tipo de consulta (RN-AGM-008, quando a clínica configurou; como texto, não chip) e modo de atendimento — **só quando não é o presencial** (padrão, omitido): "Teleatendimento" e "Customizado" aparecem sempre, em cor de destaque —, separados por "·" e truncados se não couberem; à direita, o **sinalizador de atraso**, quando houver.
- **Linha 3 (só quando houver):** tags do paciente, pelo critério de RN-AGM-006 (mesmo da Central, RN-CM-025), a tag "1ª Consulta" (RN-CM-028) e o complemento (RN-AGM-007), em texto secundário.
- Destaque visual por status: borda lateral esquerda de 3px para "Recepcionado" (secondary-pure) e "Aguardando Recepção" (#FF8A80) — mesmo padrão da Central.
- Foto do paciente / avatar: em telas largas, entre a coluna de horário e o conteúdo (foto, ou iniciais do primeiro e do último nome, texto `color-neutral-darker` sobre a cor do status); **no celular, o avatar não é exibido** — a coluna de horário ocupa o seu lugar, e o status já está no chip.

**Sinalizador de atraso (RN-AGM-009) — somente quando o dia exibido é hoje**, para consultas cujo horário de início já passou e que ainda não foram iniciadas nem finalizadas, em duas variantes:

- **"Esperando · Xmin"** — status Aguardando Recepção ou Recepcionado (o paciente já está na clínica; quem está atrasado é o atendimento): badge pulsante, fundo `color-error-pure` (mesmo componente do badge de atraso da Central).
- **"Não chegou · Xmin"** — status Agendado (o paciente ainda não chegou): badge neutro, fundo `color-neutral-lighter`, texto `color-neutral-dark`, sem animação.

X = minutos desde o horário de início (`delayMinutes`). Em dias passados ou futuros, o sinalizador não aparece. Esta distinção é exclusiva desta tela; a Central do Médico mantém um único sinalizador "Atrasado".

Nota de nomenclatura: "Modo de atendimento" (campo `attendanceMode` na API — presencial, teleatendimento, customizado) 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).

**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). Só aparecem dentro do grupo 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 grupos expandidos.

**Item de bloqueio (RN-AGM-004, RN-AGM-011, RN-AGM-012):** coluna de horário + ícone de cadeado, rótulo "Bloqueado" e complemento (quando houver), numa linha, truncado se não couber; fundo `color-neutral-lighter`, borda tracejada; sem foto, diagnóstico, status ou tags. Não abre o PEP. A ação à direita depende do momento do bloqueio:

- **Ainda não começou** → ação "Desfazer" (US-AGM-004).
- **Em andamento** (início já passou, término não) → ação "Encerrar agora" (US-AGM-006).
- **Já terminou** → sem ação; o item vira uma **linha fina** (32px, esmaecida), na sua posição de horário. Bloqueios nunca entram nos grupos de realizadas/canceladas (RN-AGM-010).

Vale para qualquer bloqueio da agenda do médico, criado por ele ou pela Recepção para ele (RN-AGM-004) — o critério é o bloqueio estar na agenda do médico logado, sem distinção de quem o criou.

**Horário livre (RN-AGM-016):** nos dias de hoje e futuros, cada intervalo do horário de trabalho do médico sem consulta ativa nem bloqueio aparece como uma linha própria, na sua posição de horário: coluna de horário com o início, texto "Livre até HH:MM" e, à direita, a indicação "Bloquear" com ícone de cadeado; borda tracejada, sem fundo. No dia de hoje, só a parte ainda não decorrida do intervalo aparece, a partir do próximo intervalo de 15 minutos. Consultas canceladas não ocupam o horário. Intervalos menores que 15 minutos não aparecem. Tocar num horário livre abre o formulário de bloqueio já preenchido com o intervalo inteiro (início = início do livre; duração = duração do livre — uma das opções prontas, quando coincide, ou "Outro" com o valor). Consultas encaixadas fora do horário de trabalho aparecem normalmente na lista, mas não geram horário livre ao redor.

**Dia sem horário de trabalho por ausência (RN-AGM-015):** quando o médico está ausente no dia exibido (ex.: férias, folga), um aviso aparece no topo da lista — "{motivo} — sem horário de trabalho neste dia" — e não há horários livres; consultas e bloqueios existentes no dia, se houver, continuam aparecendo. Dias sem horário de trabalho por rotina (ex.: fim de semana) não mostram aviso nem horários livres.

**Dia sem nenhum item:** sem consultas, bloqueios nem ausência, e sem horário de trabalho → estado vazio (EX-AGM-03) com MSG-TAGM-01. Com horário de trabalho mas sem nenhuma consulta nem bloqueio → a mensagem MSG-TAGM-01 aparece em texto discreto, seguida dos horários livres do dia.

#### Resumo 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. No topo da lista, **uma única linha** com até dois botões lado a lado, nesta ordem:

1. **"✓ N realizadas"** (singular: "✓ 1 realizada") — consultas `finished` do dia.
2. **"✕ N canceladas"** (singular: "✕ 1 cancelada") — consultas `canceled` do dia (qualquer motivo, inclusive falta).

Cada botão só aparece quando N ≥ 1 (a linha some quando os dois são zero). Tocar num botão expande, logo abaixo da linha, só aquele grupo, com as consultas individuais em ordem cronológica, no mesmo formato de item da lista, esmaecidas (mesmo tratamento das consultas finalizadas da Central do Médico, Seção 2.3); tocar de novo recolhe. Os dois grupos se expandem e recolhem de forma independente (`aria-expanded`) e começam recolhidos a cada carregamento de dia. Quando uma consulta muda de status durante a atualização automática, ela simplesmente passa da lista principal para o grupo correspondente.

**Linha "AGORA":** somente quando o dia exibido é hoje, uma linha fina marca o horário atual na lista principal, com o horário ("10:07") em vermelho na própria coluna de horário e um traço atravessando a largura — inserida depois de todos os itens com horário de início anterior ou igual ao momento atual e antes do próximo. É reposicionada a cada atualização automática (RN-AGM-013), sem mover a rolagem.

**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 — quando o horário dela já passou (ex.: uma consulta atrasada); caso contrário, até a linha "AGORA". O deslocamento considera a altura real do cabeçalho e da barra do dia. Em qualquer outro dia, a linha "AGORA" não aparece e a tela abre no topo da lista.

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

Pontos de entrada: tocar num **horário livre** (formulário pré-preenchido com o intervalo) ou "Bloquear horário" (botão em telas largas, menu ⋮ no celular — formulário com o primeiro horário livre do dia pré-selecionado, ou o primeiro horário de início possível). Abre um formulário em bottom sheet no celular (com alça de arrasto e rodapé fixo com as ações) e em modal em telas largas:

- **Título:** "Bloquear horário · {data curta}" — a data do bloqueio é sempre o dia exibido (para bloquear outro dia, o médico navega até ele antes).
- **Início** — seleção em intervalos de 15 minutos, **somente dentro do horário de trabalho do médico no dia** (RN-AGM-015). No dia de hoje, só horários posteriores ao momento atual (a partir do primeiro intervalo de 15 minutos ainda não iniciado).
- **Duração** — opções 15, 30, 45 e 60 minutos e "Outro", numa única linha; "Outro" abre um campo numérico em minutos, múltiplos de 15 (mínimo 15). Abaixo, só leitura: "Término: HH:MM · horário de trabalho até HH:MM" — o término não pode passar do fim do intervalo de trabalho em que o início está.
- **Complemento** (RN-AGM-007) — texto livre, opcional, até 128 caracteres, em campo de uma linha que cresce conforme o texto; contador de caracteres ao lado do rótulo.
- Rodapé: "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 intervalo precisa estar inteiro dentro de um intervalo do horário de trabalho do médico (EX-AGM-11, MSG-EAGM-09).
- 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 (MSG-EAGM-08).
- O complemento é validado e gravado sem espaços nas pontas; o contador conta o mesmo valor que é validado.

Acessibilidade do formulário: o foco fica preso no formulário enquanto ele está aberto (o conteúdo de fundo fica inerte), "Esc" fecha, a mensagem de erro inline é associada ao campo em erro (`aria-invalid` + `aria-describedby`), e as opções de duração formam um grupo de rádio navegável pelas setas.

Ao confirmar com sucesso, o formulário fecha, o novo bloqueio aparece na lista, na posição cronológica correspondente (o horário livre ocupado some ou encolhe), e a snackbar MSG-SAGM-01 confirma.

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

Mesmo padrão de **confirmação rápida inline** para as duas ações, sem modal: ao primeiro toque, o botão muda para "Confirmar?" (estado *confirming*, texto `color-error-dark` com borda `color-error-pure`) por 5 segundos; um segundo toque dentro desse intervalo efetiva a ação; sem o segundo toque, o botão volta sozinho ao estado normal e nada é alterado. 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. Motivador: evita a ação por toque acidental sem impor a fricção de um modal para ações de baixo risco (o horário só volta a ficar livre; nenhum dado de paciente é afetado).

- **Desfazer** (bloqueio que ainda não começou): o item sai da lista e o intervalo volta a aparecer como horário livre (disponível para a Recepção agendar uma consulta real ali). Snackbar MSG-SAGM-02. Se o bloqueio começar enquanto o botão está em "Confirmar?", o desfazer é recusado (EX-AGM-08).
- **Encerrar agora** (bloqueio em andamento): o término do bloqueio passa a ser o momento atual (minuto exato); o restante do intervalo volta a ficar livre e aparece como horário livre a partir do próximo intervalo de 15 minutos. O item passa a ser exibido como bloqueio já terminado (linha fina). Snackbar MSG-SAGM-03. Se o bloqueio terminar sozinho enquanto o botão está em "Confirmar?", o encerramento é recusado (EX-AGM-12).

#### 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 grupos, a posição de rolagem nem o foco do teclado. A mesma atualização reavalia os sinalizadores de atraso, a linha "AGORA", os horários livres e a fase de cada bloqueio (desfazer / encerrar / terminado). 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 aviso de "sem conexão" e as snackbars são regiões anunciadas.

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 ícone discreto de "sem conexão" aparece dentro do botão da data, com o texto MSG-TAGM-03 como rótulo acessível e dica — mesmo princípio da Central do Médico, Seção 2.7 (EX-AGM-09); o ícone some na próxima atualização bem-sucedida. Enquanto isso, as ações de bloqueio continuam acionáveis — uma falha no envio segue os fluxos EX-AGM-04/05.

**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 — o botão "Hoje" sai do estado ativo, somem a linha "AGORA", os sinalizadores de atraso e os horários livres, e "Bloquear horário" fica indisponível; o botão "Hoje" leva ao novo dia.

#### Snackbar

Confirmações e erros de ação (bloquear, desfazer, encerrar, motivos de indisponibilidade) aparecem numa snackbar na base da tela, centralizada — não no topo, para não cobrir a data e a barra do dia.

### 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, em ordem cronológica, com o botão "Hoje" no estado ativo.

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

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

**CA-001.4**: Dado que a clínica não configurou tipos de consulta, quando os itens são exibidos, então nenhum 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 grupo 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 e sem horário de trabalho, então a tela exibe o estado vazio (EX-AGM-03) com MSG-TAGM-01. Dado que o dia não tem consulta nem bloqueio, mas tem horário de trabalho no futuro, então a tela exibe MSG-TAGM-01 em texto discreto e os horários livres do dia.

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

**CA-001.9**: Dado que o dia exibido é hoje, são 10:07 e uma consulta das 09:45 com status Recepcionado ainda não foi iniciada, então o item exibe o sinalizador forte "Esperando · 22min". Dado que uma consulta das 09:15 com status Agendado ainda não teve chegada registrada, então o item exibe o sinalizador neutro "Não chegou · 52min". Dado que o dia exibido não é hoje, então nenhum item exibe 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 grupos 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 ícone de "sem conexão" aparece no botão da data (EX-AGM-09); na próxima atualização bem-sucedida, o ícone 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-001.14**: Dado que uma consulta tem modo de atendimento presencial, então nenhum modo de atendimento aparece no item. Dado que o modo é teleatendimento ou customizado, então "Teleatendimento" ou "Customizado" aparece na segunda linha do item.

**CA-001.15**: Dado que uma consulta tem status Agendado, então o chip "Agendado" é exibido na primeira linha do item, como os demais status.

**CA-001.16**: Dado que a tela é exibida num celular (largura abaixo de 640px), então a área fixa do topo (cabeçalho + barra do dia) tem no máximo 120px de altura, a barra do dia ocupa uma única linha e os itens de consulta não exibem avatar.

**CA-002.1**: Dado que o médico toca na seta "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 aciona "Próximo dia com consulta" (menu ⋮ no celular, atalho » em telas largas ou atalho no topo do calendário), 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, então o atalho "Próximo dia com consulta" aparece indisponível em todos os pontos de entrada, com "Nenhum" no lugar da data de destino no menu.

**CA-002.4**: Dado que o médico toca na data da barra, então o seletor de calendário abre com os dois atalhos rotulados com a data de destino no topo e, no mini-calendário, os dias com ao menos uma consulta não cancelada marcados.

**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". Dado que o dia exibido já é hoje, então o botão "Hoje" está no estado ativo e tocar nele não faz nada.

**CA-002.6**: Dado que a consulta de dias com consulta falha (EX-AGM-06), então os atalhos de dia com consulta aparecem indisponíveis (no menu, com MSG-TAGM-06 no lugar da data) 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 num horário livre "Livre até 15:00" que começa às 14:00, então o formulário de bloqueio abre com início 14:00 e duração 60 min selecionada, e ao confirmar sem complemento o bloqueio é criado e o horário livre some da lista.

**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 a snackbar 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 "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, são 10:07 e o horário de trabalho é 07:30–12:00 e 14:00–18:00, quando o médico abre o formulário de bloqueio, então as opções de início começam em 10:15, não incluem nenhum horário entre 12:00 e 13:45 nem a partir de 18:00.

**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, então o intervalo aparece como horário livre e o médico consegue bloqueá-lo normalmente.

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

**CA-003.10**: Dado que o médico escolhe início 17:30 com duração 60 min e o horário de trabalho termina às 18:00, quando tenta confirmar, então o sistema impede a confirmação e exibe MSG-EAGM-09 (EX-AGM-11), com o término do horário de trabalho indicado.

**CA-003.11**: Dado que o dia exibido não tem horário de trabalho (ex.: férias ou fim de semana), então "Bloquear horário" aparece indisponível; ao ser acionado, exibe MSG-TAGM-07; e não há horários livres na lista.

**CA-004.1**: Dado que o médico toca em "Desfazer" num bloqueio que ainda não começou — criado por ele ou pela Recepção para ele —, quando toca em "Confirmar?" dentro de 5 segundos, então o item sai da lista e o intervalo volta a aparecer como horário livre.

**CA-004.2**: Dado que o médico toca em "Desfazer" (ou "Encerrar agora") mas não toca em "Confirmar?" dentro de 5 segundos, então o botão volta ao estado normal e nada é alterado.

**CA-004.3**: Dado que o back-end retorna erro ao tentar desfazer ou encerrar um bloqueio já confirmado, então o sistema exibe a snackbar MSG-EAGM-05 (ou MSG-EAGM-10) e o item permanece como estava (EX-AGM-05).

**CA-004.4**: Dado que um bloqueio já terminou, então o item é exibido como linha fina esmaecida, na sua posição de horário, sem nenhuma ação.

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

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

**CA-004.7**: Dado que são 11:37 e existe um bloqueio das 11:30 às 12:00, então o item oferece "Encerrar agora"; quando o médico confirma, o bloqueio passa a terminar às 11:37, é exibido como terminado, a snackbar MSG-SAGM-03 confirma e o intervalo a partir de 11:45 até 12:00 aparece como horário livre.

**CA-004.8**: Dado que o botão está em "Confirmar?" para encerrar e o bloqueio termina sozinho antes do segundo toque, quando o médico confirma, então o encerramento é recusado com MSG-EAGM-11 (EX-AGM-12).

**CA-005.1**: Dado que existem consultas com status `finished` no dia, quando a tela carrega, então o botão "✓ N realizadas" aparece na linha de resumo, no topo da lista, com a contagem correta, e as consultas não aparecem individualmente na lista principal.

**CA-005.2**: Dado que existem consultas com status `canceled` no dia (qualquer motivo, inclusive falta), quando a tela carrega, então o botão "✕ N canceladas" aparece ao lado do de realizadas, e as consultas expandidas exibem o chip "Cancelado".

**CA-005.3**: Dado que o médico toca em um dos botões do resumo, então só aquele grupo expande, logo abaixo da linha de resumo, com os itens esmaecidos; tocar de novo recolhe.

**CA-005.4**: Dado que nenhuma consulta do dia tem status `finished` (ou `canceled`), então o botão correspondente não aparece; sem nenhuma das duas, a linha de resumo não aparece.

**CA-005.5**: Dado que o dia exibido é hoje, são 10:07 e há uma consulta Agendada das 09:15 ainda sem chegada, quando a tela carrega, então a linha "AGORA" aparece com "10:07" na coluna de horário, na posição cronológica do horário atual, e a rolagem deixa visível, abaixo das barras fixas, a consulta das 09:15. 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á terminado no dia, quando a tela carrega, então ele aparece como linha fina individual na sua posição de horário, fora dos grupos de realizadas/canceladas.

**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 com o botão "Hoje" fora do estado ativo, sem a linha "AGORA", sem horários livres 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).

**CA-007.1**: Dado que o dia exibido é hoje, são 10:07, o horário de trabalho é 14:00–18:00 à tarde e há consultas às 15:00–15:30 (ativa) e às 14:00–14:30 (cancelada), então a lista mostra "Livre até 15:00" às 14:00 e "Livre até 18:00" às 15:30.

**CA-007.2**: Dado que o dia exibido é hoje e um intervalo livre começou às 13:00, são 13:20 e ele termina às 15:00, então o horário livre aparece a partir de 13:30 ("Livre até 15:00").

**CA-007.3**: Dado que o dia exibido é anterior a hoje, então nenhum horário livre aparece.

**CA-007.4**: Dado que o médico está de férias no dia exibido, então a lista mostra o aviso "Férias — sem horário de trabalho neste dia" e nenhum horário livre.

**CA-007.5**: Dado que há uma consulta encaixada pela Recepção às 18:30, fora do horário de trabalho (que termina às 18:00), então a consulta aparece normalmente na lista e nenhum horário livre é gerado depois das 18:00.

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

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

Gatilho: o médico navega para um dia sem nenhuma consulta nem horário bloqueado. Comportamento: sem horário de trabalho no dia → estado vazio com MSG-TAGM-01; com horário de trabalho → MSG-TAGM-01 em texto discreto e os horários livres. Não é um erro — é um estado esperado.

**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 — a Recepção ocupou o horário entre a validação local e o envio). Comportamento: snackbar 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 ou encerrar bloqueio**

Gatilho: o back-end retorna erro ao tentar remover ou encerrar um bloqueio. Comportamento: snackbar de erro MSG-EAGM-05 (desfazer) ou MSG-EAGM-10 (encerrar); o item permanece como estava. Recuperação: o médico tenta novamente.

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

Gatilho: erro de rede ou falha do back-end ao consultar quais dias têm consulta. Comportamento: degradação silenciosa — atalhos de dia com consulta indisponíveis (no menu, MSG-TAGM-06 no lugar da data) e calendário sem os dias marcados, sem interromper nem exibir erro na tela principal. 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, ou o back-end recusa a criação por horário passado. Comportamento: confirmação impedida com MSG-EAGM-06 inline; opções de início 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" depois de o horário de início do bloqueio já ter chegado, ou o back-end recusa a remoção por esse motivo. Comportamento: snackbar MSG-EAGM-07; o item permanece, agora com a ação "Encerrar agora" (se ainda em andamento) ou como bloqueio terminado. Recuperação: o médico pode encerrar o bloqueio, se ainda em andamento.

**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 ícone discreto de "sem conexão" no botão da data (MSG-TAGM-03 como rótulo acessível); nenhuma mensagem de erro em tela cheia. Recuperação: automática, na próxima atualização bem-sucedida.

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

Gatilho: o back-end responde 404 ao desfazer ou encerrar um bloqueio (ele não existe mais na agenda do médico — ex.: desfeito em outro dispositivo ou pela Recepção). Comportamento: o item sai da lista, snackbar informativa MSG-IAGM-01 e recarga da agenda do dia. Recuperação: nenhuma necessária.

**EX-AGM-11 — Bloqueio fora do horário de trabalho**

Gatilho: o intervalo escolhido não está inteiro dentro de um intervalo do horário de trabalho do médico (o término passa do fim do intervalo), ou o back-end recusa por esse motivo (o horário de trabalho pode ter mudado entre o carregamento e o envio). Comportamento: confirmação impedida com MSG-EAGM-09 inline, indicando o fim do horário de trabalho. Recuperação: o médico reduz a duração ou escolhe outro início.

**EX-AGM-12 — Bloqueio não está mais em andamento ao encerrar**

Gatilho: o médico confirma "Encerrar agora" depois de o bloqueio já ter terminado sozinho, ou o back-end recusa o encerramento porque o bloqueio não está em andamento. Comportamento: snackbar MSG-EAGM-11; o item é reexibido na fase atual (terminado). Recuperação: nenhuma necessária.

### Validações de Campos

| Campo | Tipo | Obrigatório | Validação |
|---|---|---|---|
| Data do bloqueio | data (implícita — dia exibido, no título) | Sim | Hoje ou futura (RN-AGM-012), com horário de trabalho (RN-AGM-015) — o formulário não abre em dia passado nem sem horário de trabalho. |
| Início do bloqueio | seleção de horário, intervalos de 15 min | Sim | Dentro do horário de trabalho do médico no dia; 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 (MSG-EAGM-08). Término (início + duração) dentro do mesmo intervalo do horário de trabalho (EX-AGM-11, MSG-EAGM-09). O intervalo não pode sobrepor consulta ativa nem outro bloqueio (EX-AGM-01). |
| Complemento (bloqueio) | texto livre, uma linha que cresce | Não | Até 128 caracteres, sem espaços nas pontas (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; no celular, nome da clínica oculto e logotipo de 28px | Topo da tela (RN-AGM-014) |
| Barra do dia | Linha única | — | Altura 52px (celular) / 56px (telas largas); fundo `color-base-pure`, borda inferior `color-neutral-lighter` | Navegação por dia |
| Button | Data (abre calendário) | default, hover, offline | Texto `color-neutral-darker`, 16px (celular) / 18px; ícone Lucide `chevron-down`; offline: ícone `wifi-off` em `color-highlight-dark` | Barra do dia |
| Button | Ícone (setas, atalhos, ⋮) | default, hover, disabled | 44×44px, ícones Lucide `chevron-left/right`, `chevrons-left/right`, `more-vertical` | Barra do dia |
| Button | "Hoje" (pill) | default, hover, active | active: bg `color-secondary-light`, texto `color-secondary-dark` — mesmo par do Toggle Pill ativo da Central | Barra do dia |
| Button | Secondary (Bloquear horário) | default, hover, indisponível (`aria-disabled`) | bg `color-secondary-light`, texto `color-secondary-dark` (mesmo par do botão secundário do protótipo da Central) | Barra do dia, telas largas |
| Menu | Overflow (⋮) | fechado, aberto; item indisponível | bg `color-base-pure`, `shadow-medium`, `radius-m`; itens 44px com subtítulo `color-neutral-pure` | Celular: bloquear e atalhos de dia com consulta |
| Linha de consulta | Coluna de horário + 2–3 linhas | default, hover, focus, recepcionado, aguardando, esmaecido (grupos) | Coluna 52px: início 14px `color-neutral-darker`, término 12px `color-neutral-pure`; bordas por status da Central (Seção 2.3/2.8) | Cada consulta do dia |
| Avatar | Iniciais na cor do status | default | bg: cor do status (paleta da Central; Cancelado: `color-neutral-light`); texto `color-neutral-darker`; **só em telas largas** | Consulta sem foto do paciente |
| Chip | Status (consulta) | default | Paleta da Central (RN-CM-005/Seção 2.3) + Cancelado: bg `color-neutral-light`, texto `color-neutral-dark`; 11px | Status de cada consulta |
| Badge | Atraso — "Esperando" | default (pulsante) | bg `color-error-pure`, texto `color-base-pure` (mesmo componente do badge de atraso da Central) | Paciente na clínica, horário vencido, só hoje |
| Badge | Atraso — "Não chegou" | default | bg `color-neutral-lighter`, texto `color-neutral-dark`, sem animação | Paciente não chegou, horário vencido, só hoje |
| Texto | Modo de atendimento | default | `color-secondary-dark` | Só teleatendimento/customizado |
| Chip | Tag do paciente / 1ª Consulta | default | Cor da própria tag (cadastro) e cor fixa de "1ª Consulta" — mesmas da Central | Linha 3 |
| Linha de bloqueio | Futuro / em andamento / terminado | default, confirming | bg `color-neutral-lighter`, borda tracejada `color-neutral-light`, ícone Lucide `lock`; terminado: linha de 32px, opacidade reduzida | Cada bloqueio |
| Button | Tertiary (Desfazer / Encerrar agora) | default, hover, confirming | 44px de altura; confirming: texto `color-error-dark`, borda `color-error-pure`, bg `color-error-light` ("Confirmar?", 5 s) | Item de bloqueio |
| Linha de horário livre | Tocável | default, hover, focus | Sem fundo, borda tracejada `color-neutral-light` (hover `color-primary-dark`); texto `color-neutral-pure`; "Bloquear" em `color-primary-dark` com ícone `lock`; 44px | Horários livres (RN-AGM-016) |
| Aviso | Ausência no dia | default | bg `color-highlight-light`, texto `color-neutral-dark`, ícone Lucide `calendar-off` | Férias, folga (RN-AGM-015) |
| Button | Pill de resumo (realizadas / canceladas) | recolhido, expandido | 44px; borda `color-neutral-lighter`; expandido: bg `color-neutral-lighter` | Resumo de RN-AGM-010 |
| Divider com rótulo | Linha "AGORA" | default | `color-error-pure` (horário na coluna de horário, ponto e traço) | Horário atual, só hoje |
| Bottom Sheet / Modal | Formulário de bloqueio; seletor de calendário | default, loading, error | Mesma anatomia de modal do Design System; no celular, bottom sheet com alça de arrasto e rodapé fixo | Bloqueio; escolha de dia |
| Segmented/Radio pill | Duração do bloqueio | active, inactive | Mesmos tokens do Toggle Pill da Central; 5 opções numa linha, 44px | 15/30/45/60/Outro |
| Date Picker | Mini-calendário mensal + atalhos rotulados | default, dia-com-consulta, hoje, selecionado | Ponto `color-primary-dark` sob o dia com consulta; dias de 44px | Seletor de data |
| Snackbar | Info / Error | default | bg `color-neutral-dark` (info) / `color-error-dark` (erro), texto `color-base-pure`; base da tela | Confirmações e erros de ação |
| Empty/Error State | Tela cheia (sem itens) | error, empty | `color-error-pure` ícone e texto, botão "Tentar novamente" (erro) | EX-AGM-02, 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), bloqueios da agenda do médico (criados por ele ou pela Recepção), o horário de trabalho do dia e os horários livres.
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", "workWindows": [ { "startTime": "07:30", "endTime": "12:00" }, { "startTime": "14:00", "endTime": "18:00" } ], "absence": null, "freeSlots": [ { "startTime": "14:00", "endTime": "15:00" }, { "startTime": "15:30", "endTime": "18: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": { "code": "P", "label": "Presencial" }, "delayMinutes": 0, "firstTime": false, "tags": ["vip"], "complement": "string|null", "appointmentType": "string|null" }, { "kind": "block", "id": "uuid", "startTime": "11:30", "endTime": "12:00", "complement": "Reunião com a enfermagem|null" } ] }`
- `serverNow`: data e hora atuais do servidor, no fuso da clínica (ISO 8601 com deslocamento) — referência de tempo da tela.
- `workWindows`: intervalos do horário de trabalho do médico no dia, já considerando a rotina semanal e as exceções por data (ausências removem, trabalho extra acrescenta) — RN-AGM-015. Lista vazia quando não há horário de trabalho no dia.
- `absence`: `null`, ou `{ "reason": "Férias" }` quando o médico está ausente no dia por uma exceção de ausência (motivo = descrição da exceção) — usado no aviso de ausência.
- `freeSlots`: horários livres (RN-AGM-016) — `workWindows` menos consultas ativas e bloqueios; no dia de hoje, só a partir do próximo intervalo de 15 minutos em relação a `serverNow`; intervalos menores que 15 minutos omitidos; vazio em dias passados. Calculado pelo back-end, para uma única fonte de verdade entre a Agenda e futuras telas (ex.: Agendamento).
- `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`.
- `attendanceMode`: `code` (`P` presencial — padrão, omitido na tela; `T` teleatendimento; `C` customizado) e `label`, termo já traduzido para o idioma da clínica (mesma origem do campo da Central do Médico, Seção 4.1). O código existe nesta tela porque a regra de omitir o valor padrão não pode depender de comparar o rótulo traduzido.
- `delayMinutes`: mesma regra do campo homônimo da Central do Médico (Seção 2.9/4.1) — minutos desde o início, 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. O front escolhe a variante do sinalizador pelo `status`: `waiting`/`checked` → "Esperando"; `scheduled` → "Não chegou".
- `tags`: já filtradas pelo back-end pelo critério de RN-CM-025 (RN-AGM-006). Nunca contém "1ª Consulta": ela é derivada de `firstTime` (boolean) (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 (v1.1), a resolver na Seção 4.
- `startTime`/`endTime`: `HH:MM` no fuso da clínica; `endTime = "24:00"` indica o fim exato do dia.
- Itens `kind = "block"` são os bloqueios da agenda do médico logado (RN-AGM-004), independentemente de quem os criou — 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 do calendário (RN-AGM-003). 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"] }`

**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 pelos atalhos de dia com consulta (menu ⋮, atalhos « » e topo do calendário, que exibem a data de destino). Bloqueios e consultas canceladas não contam.
Query params: `direction` (obrigatório, `next` ou `previous`), `from` (obrigatório, `YYYY-MM-DD` — normalmente o dia exibido; a própria data 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-07" }` ou `{ "date": null }` quando não há nenhuma consulta naquela direção.

**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, RN-AGM-015).
Request: `{ "date": "2026-09-29", "startTime": "14:00", "endTime": "15:00", "complement": "string|null" }`
Response 201: `{ "kind": "block", "id": "uuid", "date": "2026-09-29", "startTime": "14:00", "endTime": "15:00", "complement": "string|null" }`
Códigos: 201 (sucesso); 400 (dados inválidos — horário fora da grade de 15 min, duração inválida, complemento acima de 128 caracteres — exibidos como MSG-EAGM-08/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; fora do horário de trabalho — EX-AGM-11, MSG-EAGM-09; o corpo do erro indica qual das duas regras); 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 da agenda do médico logado 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 na agenda do médico logado — já desfeito em outra sessão, ou de outro profissional; não há um 403 separado, para não revelar a outro médico que aquele horário está bloqueado — EX-AGM-10); 422 (bloqueio já começou — EX-AGM-08, MSG-EAGM-07); 500 (falha ao remover — EX-AGM-05).

**PATCH /api/v1/agenda/doctor/blocks/{id}/end**

Função: encerra antes do fim um bloqueio em andamento da agenda do médico logado (US-AGM-006, RN-AGM-012) — o término passa a ser o momento atual do servidor.
Request: sem corpo (o término é definido pelo servidor, para não depender do relógio do dispositivo).
Response 200: `{ "kind": "block", "id": "uuid", "date": "2026-09-29", "startTime": "11:30", "endTime": "11:37", "complement": "string|null" }`
Códigos: 200 (sucesso); 404 (bloqueio não encontrado — EX-AGM-10); 422 (bloqueio não está em andamento — ainda não começou ou já terminou — EX-AGM-12, MSG-EAGM-11); 500 (falha — EX-AGM-05, MSG-EAGM-10).

### 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: 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. Rótulos de modo de atendimento: termos traduzidos do próprio domínio (`attendanceMode.label`).

| 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. Use \"Encerrar agora\"." | "This block has already started. Use \"End now\"." | "Este bloqueo ya comenzó. Use \"Terminar ahora\"." |
| MSG-EAGM-08 | Duração inválida | "Informe uma duração em múltiplos de 15 minutos." | "Enter a duration in multiples of 15 minutes." | "Indique una duración en múltiplos de 15 minutos." |
| MSG-EAGM-09 | Bloqueio fora do horário de trabalho (EX-AGM-11) | "O bloqueio precisa terminar dentro do seu horário de trabalho (até {hh:mm})." | "The block must end within your working hours (until {hh:mm})." | "El bloqueo debe terminar dentro de su horario de trabajo (hasta {hh:mm})." |
| MSG-EAGM-10 | Falha ao encerrar bloqueio (EX-AGM-05) | "Não foi possível encerrar o bloqueio. Tente novamente." | "Could not end the block. Please try again." | "No fue posible terminar el bloqueo. Inténtelo de nuevo." |
| MSG-EAGM-11 | Bloqueio não está mais em andamento (EX-AGM-12) | "Este bloqueio já terminou." | "This block has already ended." | "Este bloqueo ya terminó." |
| 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 | Bloquear indisponível — 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 | Atualização com falha (EX-AGM-09) — rótulo acessível do ícone | "Offline — dados podem estar desatualizados" | "Offline — data may be out of date" | "Sin conexión — los datos pueden estar desactualizados" |
| MSG-TAGM-04 | Bloquear indisponível — sem horário restante hoje | "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 | Atalhos/calendário sem dados (EX-AGM-06) | "Indisponível no momento" / "Marcadores indisponíveis no momento." | "Unavailable right now" / "Markers are unavailable right now." | "No disponible en este momento" / "Marcadores no disponibles en este momento." |
| MSG-TAGM-07 | Bloquear indisponível — sem horário de trabalho no dia | "Sem horário de trabalho neste dia." | "No working hours on this day." | "Sin horario de trabajo en este día." |
| MSG-TAGM-08 | Aviso de ausência (RN-AGM-015) | "{motivo} — sem horário de trabalho neste dia." | "{reason} — no working hours on this day." | "{motivo} — sin horario de trabajo en este día." |
| 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 livre." | "Block undone. The time slot is free again." | "Bloqueo deshecho. El horario volvió a quedar libre." |
| MSG-SAGM-03 | Sucesso ao encerrar | "Bloqueio encerrado às {hh:mm}. O restante do horário voltou a ficar livre." | "Block ended at {hh:mm}. The rest of the time slot is free again." | "Bloqueo terminado a las {hh:mm}. El resto del 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 | Ação de bloqueio de horário | "Bloquear horário" | "Block time slot" | "Bloquear horario" |
| MSG-BAGM-02 | Ação de desfazer bloqueio | "Desfazer" | "Undo" | "Deshacer" |
| MSG-BAGM-03 | Botão de voltar para hoje / prefixo da data de hoje | "Hoje" | "Today" | "Hoy" |
| MSG-BAGM-04 | Rótulo do item bloqueado | "Bloqueado" | "Blocked" | "Bloqueado" |
| MSG-BAGM-05 | Estado de confirmação rápida | "Confirmar?" | "Confirm?" | "¿Confirmar?" |
| MSG-BAGM-06 | Botão do formulário de bloqueio | "Confirmar bloqueio" | "Confirm block" | "Confirmar bloqueo" |
| MSG-BAGM-07 | Resumo de realizadas (singular / plural) | "✓ 1 realizada" / "✓ {n} realizadas" | "✓ 1 completed" / "✓ {n} completed" | "✓ 1 realizada" / "✓ {n} realizadas" |
| MSG-BAGM-08 | Resumo de canceladas (singular / plural) | "✕ 1 cancelada" / "✕ {n} canceladas" | "✕ 1 canceled" / "✕ {n} canceled" | "✕ 1 cancelada" / "✕ {n} canceladas" |
| MSG-BAGM-09 | Linha do horário atual (rótulo acessível) | "Agora, {hh:mm}" | "Now, {hh:mm}" | "Ahora, {hh:mm}" |
| MSG-BAGM-11 | Rótulos do formulário de bloqueio | "Bloquear horário · {data}" / "Início" / "Duração" / "Outro" / "minutos (múltiplos de 15)" / "Término: {hh:mm} · horário de trabalho até {hh:mm}" / "Complemento (opcional)" | "Block time slot · {date}" / "Start" / "Duration" / "Other" / "minutes (multiples of 15)" / "End: {hh:mm} · working hours until {hh:mm}" / "Note (optional)" | "Bloquear horario · {fecha}" / "Inicio" / "Duración" / "Otro" / "minutos (múltiplos de 15)" / "Fin: {hh:mm} · horario de trabajo hasta {hh:mm}" / "Nota (opcional)" |
| MSG-BAGM-12 | Botões genéricos da tela | "Tentar novamente" / "Cancelar" / "Salvando…" | "Try again" / "Cancel" / "Saving…" | "Intentar de nuevo" / "Cancelar" / "Guardando…" |
| MSG-BAGM-13 | Ação de encerrar bloqueio em andamento | "Encerrar agora" | "End now" | "Terminar ahora" |
| MSG-BAGM-14 | Sinalizadores de atraso | "Esperando · {n}min" / "Não chegou · {n}min" | "Waiting · {n}min" / "Not arrived · {n}min" | "Esperando · {n}min" / "No llegó · {n}min" |
| MSG-BAGM-15 | Horário livre | "Livre até {hh:mm}" / "Bloquear" | "Free until {hh:mm}" / "Block" | "Libre hasta {hh:mm}" / "Bloquear" |
| MSG-BAGM-16 | Menu e atalhos de dia com consulta | "Mais opções" / "Próximo dia com consulta" / "Dia anterior com consulta" / "Nenhum" / "Escolher dia" | "More options" / "Next day with appointments" / "Previous day with appointments" / "None" / "Choose day" | "Más opciones" / "Próximo día con consultas" / "Día anterior con consultas" / "Ninguno" / "Elegir día" |

### 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 e horários (Recepção/Administração); esta tela cobre o bloqueio pontual da agenda do médico e respeita o horário de trabalho e as ausências cadastradas (RN-AGM-015). O fluxo de bloqueio (US-AGM-003/004/006, `POST`/`DELETE`/`PATCH .../end` em `/api/v1/agenda/doctor/blocks`) implementa a parte que cabe a esta tela, 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, a remoção e o encerramento de um bloqueio (`POST`/`DELETE`/`PATCH .../end` 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.
- **v1.2** (29/09/2026) — Acompanha 01-Definição v1.7. **Redesenho de layout** a pedido do solicitante ("a parte fixa com a data e os botões de navegação ocupa muito espaço; no celular ocuparia metade da tela"), a partir de uma revisão por dois subagentes independentes — um médico oncologista (uso real entre consultas, no celular) e um especialista em UX mobile — que mediram o protótipo v1.0: área fixa de 181px (28% da tela útil num Android, 33% num iPhone SE) e, somando os grupos recolhidos e o bloqueio passado, primeira consulta que exige ação só depois de 55–64% da tela. Aplicado o que os dois recomendaram em comum e o solicitante aprovou ("pode seguir"): (1) barra do dia em **uma linha** — a data vira o botão que abre o calendário (sai o botão de calendário separado), o rótulo "Hoje" separado dá lugar ao estado ativo do botão "Hoje", e no celular os atalhos de dia com consulta saem da barra para o menu ⋮ e para o topo do calendário, **com a data de destino escrita** (o ícone de seta dupla, sozinho, não foi entendido pelo médico-crítico); em telas largas continuam ao lado das setas; área fixa-alvo ~116px; (2) **coluna de horário à esquerda** (início em destaque, término abaixo) — o horário ficava pequeno, cinza e à direita; (3) **anatomia fixa do card** em 2 linhas (+1 opcional para tags/complemento) — o card quebrava de 2 a 4 linhas de forma imprevisível; avatar removido no celular (a coluna de horário ocupa o lugar; em telas largas continua); (4) grupos de realizadas/canceladas viram **uma linha de resumo** com dois botões lado a lado; bloqueio terminado vira linha fina; (5) snackbar na base da tela, não no topo; ícone de "sem conexão" dentro do botão da data; formulário de bloqueio mais compacto (data no título, durações numa linha, complemento de uma linha que cresce, rodapé fixo). **Decisões do solicitante nesta rodada:** (a) "Bloquear horário": entre o botão flutuante (proposta do UX) e o menu ⋮ + toque num horário livre (proposta do médico), o solicitante escolheu a segunda para ver no protótipo — novas linhas de **horário livre** (RN-AGM-016, US-AGM-007), tocáveis, que abrem o formulário pré-preenchido com o intervalo; em telas largas o botão continua na barra; (b) sinalizador de atraso separado em **"Esperando"** (forte) e **"Não chegou"** (neutro), **só nesta tela** — a Central do Médico está congelada para fechar a versão (achado do médico-crítico: o mesmo selo vermelho servia para "o paciente está me esperando" e "o paciente não chegou"); (c) status "Agendado" continua sempre exibido, por consistência (o médico-crítico propôs escondê-lo); o modo de atendimento **presencial (padrão) é omitido** e teleatendimento/customizado aparecem sempre — o JSON de `GET /day` passa a trazer `attendanceMode` como `{ code, label }`, porque a omissão não pode depender do rótulo traduzido (na v1.1 era só o termo traduzido); (d) **horário de trabalho** (RN-AGM-015): o bloqueio só pode ser criado dentro dele — opções de início limitadas, término limitado ao fim do intervalo de trabalho, novo EX-AGM-11 / MSG-EAGM-09 / CA-003.10 / CA-003.11 e MSG-TAGM-07; aviso de ausência no dia (MSG-TAGM-08, CA-007.4); `GET /day` ganha `workWindows`, `absence` e `freeSlots` (horários livres calculados pelo back-end — escolha do Designer, para uma única fonte de verdade com o futuro Agendamento); (e) quem desfaz: qualquer bloqueio da agenda do médico, criado por ele ou pela Recepção — o critério é `Agenda.IdChRecurso`, sem saber quem criou (esclarecimento do solicitante) — US-AGM-004 e textos ajustados; (f) **encerrar antes do fim** um bloqueio em andamento — nova US-AGM-006, novo endpoint `PATCH /blocks/{id}/end` (término definido pelo servidor, no minuto exato — escolha do Designer; o solicitante não definiu arredondamento), EX-AGM-12, MSG-EAGM-10/11, MSG-SAGM-03, MSG-BAGM-13, CA-004.7/004.8; EX-AGM-08 e MSG-EAGM-07 passam a orientar para "Encerrar agora". **Não aplicado, registrado:** coluna lateral com mini-calendário fixo em telas largas (proposta opcional dos dois críticos) — deixada para avaliação depois de o solicitante ver o novo layout; gesto de deslizar entre dias (proposta do médico) — não implementado (o UX alertou para conflito com o gesto de voltar do sistema); resumo numérico do dia ("2 esperando · 5 restantes") proposto pelo médico — não incluído, para não somar uma linha à área fixa. Mensagens renumeradas/ajustadas: MSG-BAGM-02 passa a "Desfazer" (antes "Desfazer bloqueio"), MSG-BAGM-07/08 com "✓"/"✕", MSG-BAGM-09 passa a rótulo acessível, novas MSG-BAGM-14/15/16. Acompanha 03-Protótipo v1.1.
