# Épico 5 — Menu Lateral — Especificação (v1.7)

**Documentos deste épico:** [01 - Definição](./01%20-%20Defini%C3%A7%C3%A3o%20v1.9.md) (v1.9) · [02 - Especificação](./02%20-%20Especifica%C3%A7%C3%A3o%20v1.7.md) (v1.7) · [03 - Protótipo](./03%20-%20Prot%C3%B3tipo%20v1.8.md) (v1.8, código executável em `03 - Protótipo v1.8.html`) · [04 - Mapeamento de Banco de Dados](./04%20-%20Mapeamento%20de%20Banco%20de%20Dados%20v1.7.md) (v1.7). Este épico faz parte do documento guarda-chuva [Check-in de Usuários](../00%20-%20Guarda-chuva%20v2.27.md).

---

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

### Histórias de Usuário

- **US-CIU-010:** Como usuário autenticado, quero navegar entre os módulos que meu perfil de acesso libera a partir de um único menu lateral, para encontrar rapidamente as funcionalidades da minha rotina sem me perder em opções que não uso.
- **US-CIU-011:** Como usuário trabalhando numa clínica de um Ambiente de teste, quero perceber isso a todo momento, sem perder espaço de tela, para não confundir o teste com o atendimento real.

### Descrição Funcional Detalhada

#### Cabeçalho do Menu (identificação da clínica)

No topo do menu, antes dos grupos, um indicador visual (círculo colorido) e o nome da clínica em que o usuário está trabalhando nesta sessão (E1, E6) — ex.: "Clínica Onco". No mobile, o mesmo nome aparece na barra superior fixa, sem o indicador visual. Quando o menu está recolhido no desktop (ver "Comportamento Responsivo"), só o indicador visual permanece; o nome é ocultado junto com o restante do texto do menu recolhido.

Motivador: dar ao usuário uma referência constante de em qual clínica está trabalhando, especialmente relevante para quem atua em mais de uma (RN-CIU-009, em CIU-E1) — sem essa identificação, trocar de clínica (ver "Botão Trocar" abaixo) não teria uma confirmação visual de que a troca realmente ocorreu.

#### Estrutura do Menu

Ao carregar, o menu busca a árvore de grupos e itens já filtrada pelo perfil de acesso do usuário na clínica atual (RN-CIU-027). Cada grupo é exibido com seu nome e a lista de itens que contém, na ordem definida para aquele perfil de acesso; itens sem grupo aparecem soltos, na lista principal, junto dos grupos. Um grupo sem nenhum item liberado pelo perfil de acesso não é exibido (RN-CIU-026) — o back-end já não o devolve. Um grupo começa recolhido, exibindo apenas seu nome (ver "Premissas", 01 - Definição), e pode ser expandido/recolhido individualmente ao ser tocado, sem afetar os demais grupos (RN-CIU-026). Cada item exibe um ícone e o nome do módulo; ao ser selecionado, navega para a rota daquele item.

Motivador: a filtragem no carregamento (RN-CIU-027), em vez de itens desabilitados na tela, evita qualquer ambiguidade sobre o que o usuário pode ou não acessar — o item simplesmente não existe ali para ele.

#### Seção Favoritos

Exibida no topo do menu, acima dos grupos, apenas quando o usuário tem ao menos um item favoritado nesta clínica (RN-CIU-028) — sem favoritos, a seção não é renderizada. Cada item favoritado aparece com o mesmo ícone e nome de sua entrada original, e um indicador de estrela preenchida; o mesmo indicador aparece junto ao item em seu grupo de origem, permitindo favoritar/desfavoritar a partir de qualquer um dos dois lugares. Os itens da seção Favoritos são listados em ordem alfabética pelo nome, conforme a collation do banco — a lista já chega ordenada do back-end (RN-CIU-028). Só aparecem favoritos de itens que continuam liberados pelo perfil de acesso na clínica atual; um favorito de item que deixou de ser liberado não é exibido (RN-CIU-028). A busca não afeta esta seção: durante uma busca, todos os favoritos continuam visíveis, sem filtro (RN-CIU-030). Tocar na estrela de um item não favoritado o adiciona à seção Favoritos (CA-010.2); tocar na estrela preenchida de um item já favoritado o remove da seção, sem afetar sua presença no grupo de origem (CA-010.3).

Quando o menu está recolhido no desktop (ver "Comportamento Responsivo"), apenas os ícones dos itens desta seção permanecem visíveis — sem nenhum favorito, o menu recolhido fica vazio.

Motivador: separar Favoritos da árvore normal, em vez de reordenar os itens dentro dos próprios grupos, evita que o usuário perca a referência de onde cada módulo mora na estrutura fixa do sistema (RN-CIU-028, Seção 1).

#### Busca

Campo de busca no topo do menu, abaixo da seção Favoritos (quando presente). A cada caractere digitado, filtra a lista de itens pelo nome, em tempo real, sem exigir confirmação (RN-CIU-030). A busca é por aproximação: não diferencia maiúsculas de minúsculas nem letras acentuadas de não acentuadas — "medico", "MEDICO" e "Médico" encontram os mesmos itens. A busca só afeta a árvore (grupos e itens); a seção Favoritos permanece intacta. Durante uma busca com texto, os grupos são ignorados como unidade de exibição — a lista mostra diretamente os itens cujo nome corresponde ao texto buscado, independentemente do grupo a que pertencem estarem expandidos ou recolhidos (CA-010.4). Limpar o campo de busca restaura a exibição normal, com os grupos no estado de expansão em que estavam antes da busca. Quando nenhum item corresponde ao texto buscado, é exibido um estado vazio (EX-E5-02).

Motivador: a busca é uma ferramenta de atalho para quem já sabe o nome do que procura — achatar a árvore evita a etapa extra de abrir manualmente o grupo certo.

#### Comportamento Responsivo

No desktop (largura suficiente para o menu ao lado do conteúdo), o menu tem dois estados: expandido (padrão) e recolhido, alternados por um controle posicionado fora do próprio menu, numa posição fixa que não se desloca entre os dois estados — evita que o usuário precise localizar o controle em lugares diferentes da tela conforme o menu muda de largura. Expandido, ocupa uma faixa lateral fixa com grupos e itens por extenso; o conteúdo principal ocupa o espaço restante. Recolhido, mostra apenas os ícones dos itens da seção Favoritos, em coluna estreita; o conteúdo principal se redimensiona para ocupar o espaço liberado (CA-010.7). Sem nenhum favorito, a coluna recolhida fica vazia — nenhum ícone de navegação (RN-CIU-029). Um ícone do menu recolhido navega direto para o item ao ser clicado — não é necessário expandir o menu antes.

No mobile (largura insuficiente para o menu ao lado do conteúdo), o menu fica oculto por padrão; um ícone no cabeçalho da tela o abre como uma camada sobreposta ao conteúdo principal, sem redimensionar nada por baixo (CA-010.8). Selecionar um item ou tocar fora da camada fecha o menu, revelando o conteúdo como estava.

Motivador: RN-CIU-029, Seção 1 — os dois comportamentos (redimensionar vs. sobrepor) são deliberadamente opostos, cada um adequado ao espaço disponível na respectiva largura de tela.

#### Botão Trocar (clínica)

Botão compacto com ícone e o rótulo de texto "Trocar" (fonte reduzida em relação ao restante do cabeçalho), posicionado no cabeçalho do menu, ao lado do nome da clínica — não um botão largo separado abaixo do cabeçalho. Exibido apenas quando o usuário tem acesso a mais de uma clínica (RN-CIU-009, em CIU-E1) — com exatamente 1 clínica acessível, o botão não aparece (CA-010.5). Ao ser tocado, leva o usuário à tela de seleção de clínica (E6, RN-CIU-025), onde pode escolher outra clínica de trabalho (CA-010.6). Trocar de clínica reconstrói o menu inteiro (itens, favoritos e a identificação da clínica no cabeçalho) a partir do perfil de acesso da nova clínica (RN-CIU-028, Seção 1) — não há tentativa de preservar o estado da clínica anterior. Some junto com o resto do texto do cabeçalho quando o menu está recolhido no desktop (ver "Comportamento Responsivo").

Motivador: ocultar o botão para quem só tem uma clínica evita oferecer uma ação sem efeito útil; reconstruir o menu do zero ao trocar reflete o fato de que itens e favoritos são específicos da combinação vínculo × perfil × clínica (RN-CIU-028). Posição e tamanho discretos junto ao nome da clínica, em vez de um botão de destaque separado, refletem que trocar de clínica é uma ação pouco frequente para a maioria dos usuários — não deve competir visualmente com a navegação principal do menu; o rótulo de texto (retomado nesta versão, após uma rodada anterior só com ícone) evita a ambiguidade de um ícone isolado sem contexto textual.

#### Sinalização de Ambiente de teste (RN-CIU-032)

Aplica os itens 1 a 3 de RN-CIU-032. A origem do dado é o campo `ambienteTipo` de `GET /api/v1/menu` (ver "Integração com Backend"): `"homologacao"` liga a sinalização, `"producao"` não liga nada. O app-shell (a moldura comum a todas as telas, que contém o menu) aplica os três efeitos abaixo a cada resposta desse endpoint — ou seja, no carregamento inicial após o login/seleção de clínica, a cada troca de clínica (que já reconstrói o menu inteiro, ver "Botão Trocar") e a cada recarregamento da página.

1. **Fundo do menu.** O painel lateral inteiro — cabeçalho, área de itens e rodapé — troca o fundo `--color-base-pure` por `--color-env-test-surface` (amarelo claro; Design System, seção 8), nos três estados: desktop expandido, desktop recolhido (a coluna estreita continua pintada mesmo sem nenhum favorito) e overlay mobile. Nada mais no menu muda: textos, ícones, item ativo, estrela de favorito, campo de busca e botão Trocar mantêm os tokens de sempre — com uma única exceção: o realce de hover da estrela de favorito, que normalmente usa `--color-highlight-light` e ficaria invisível sobre o mesmo amarelo, passa a `--color-highlight-medium`. A barra superior mobile, o conteúdo principal e o controle de recolher/expandir (que fica fora do menu) também não mudam.
2. **Barra de status do celular.** Ao entrar em teste, o app-shell guarda o estado atual da tag `<meta name="theme-color">` (valor, ou ausência da tag) e passa a defini-la com o valor de `--color-env-test-surface` calculado no `:root` no tema vigente. Recalcula esse valor sempre que o tema muda durante a sessão — tanto pela preferência do sistema operacional (modo Automático, evento `change` de `matchMedia('(prefers-color-scheme: dark)')`) quanto pela escolha fixada no menu do usuário (mudança do atributo `data-theme` do `<html>`; Design System, seção 6). Ao sair do teste, restaura exatamente o estado guardado. Em produção, esta regra não toca a tag. O efeito depende do navegador — alguns ignoram `theme-color`, ou o ignoram no tema escuro; nesses casos não há sinal substituto (pendência **[A DEFINIR]** de RN-CIU-032), e no celular o aviso fica visível só com o menu aberto.
3. **Título da aba.** As telas não escrevem o título da aba diretamente: informam ao app-shell apenas o título base (ex.: "Central do Médico"). O app-shell compõe o título final — em teste, prefixo MSG-T5-02 no idioma do usuário + um espaço + título base (ex.: "[TESTE] Central do Médico"); em produção, só o título base. A composição parte sempre do título base, nunca do título já exibido, para que o prefixo não se repita; e é refeita a cada navegação, a cada mudança de Ambiente e a cada mudança de idioma.

Enquanto `GET /api/v1/menu` não respondeu (skeleton) ou falhou (EX-E5-04), o tipo de Ambiente é desconhecido e nenhum dos três efeitos é aplicado — o menu nesse momento também não permite navegar, e a sinalização aparece assim que o menu carrega. Uma resposta de sucesso sem nenhum item liberado (EX-E5-01) já traz o tipo de Ambiente, e a sinalização é aplicada normalmente.

Ao sair do app-shell — botão Trocar (indo para a seleção de clínica, E6), saída do sistema ou sessão expirada (resposta 401) —, os três efeitos são retirados antes de a próxima tela aparecer: fundo padrão, `theme-color` restaurada e título sem prefixo (RN-CIU-032: fora de uma clínica de trabalho definida, a regra não se aplica).

No tema escuro, `--color-env-test-surface` assume o valor escuro definido no Design System (mesma regra de conversão dos demais tons tingidos) — o fundo do menu continua diferente do de produção. Os textos do menu em tokens neutros mantêm contraste mínimo de 4,5:1 sobre o amarelo nos dois temas (valores no Design System, seção 8). O rótulo do botão Trocar (`--color-secondary-dark`, 10px) fica em 3,2:1 sobre o amarelo claro — já abaixo de 4,5:1 sobre o branco de produção (3,4:1); é uma pendência do Design System, anterior a esta regra, não introduzida por ela.

Motivador: RN-CIU-032 — sinalizar o Ambiente de teste sem acrescentar elemento nem ocupar altura da tela. O menu já é uma faixa fixa no computador; no celular, onde ele fica fechado, a barra de status do aparelho assume o papel; o prefixo da aba resolve a confusão entre abas abertas lado a lado. A cor é a mesma do cabeçalho do Ambiente de teste na lista de clínicas (E6, RN-CIU-031), para que o usuário reconheça o mesmo sinal antes e depois de escolher a clínica.

#### Rodapé

Faixa fixa na base do menu com o texto "Powered by Interprocess TI" (MSG-T5-01) — rótulo estático, sem link nem ação associada.

### Critérios de Aceitação

**CA-010.1**: Dado um usuário autenticado com um perfil de acesso definido, quando o sistema monta o menu, então só aparecem os itens permitidos por esse perfil (RN-CIU-027).

**CA-010.2**: Dado um item não favoritado, quando o usuário toca na estrela ao lado dele, então o item passa a aparecer na seção Favoritos.

**CA-010.3**: Dado um item na seção Favoritos, quando o usuário toca na estrela preenchida, então o item some dos Favoritos (mas continua na árvore, desfavoritado).

**CA-010.4**: Dado o usuário digitando no campo de busca, quando o texto corresponde a um ou mais itens permitidos, então só esses itens aparecem, independentemente do estado de expansão dos grupos.

**CA-010.5**: Dado um usuário com acesso a exatamente 1 clínica, quando o menu é exibido, então o botão "Trocar" não aparece.

**CA-010.6**: Dado um usuário com acesso a mais de 1 clínica, quando toca em "Trocar", então é redirecionado à tela de seleção de clínica (E6).

**CA-010.7**: Dado o menu expandido no desktop, quando o usuário o recolhe, então o conteúdo principal se redimensiona para ocupar o espaço liberado, e só os ícones dos favoritos permanecem visíveis.

**CA-010.8**: Dado o mobile, quando o usuário aciona o ícone de abertura, então o menu aparece sobre o conteúdo, sem redimensioná-lo.

**CA-010.9**: Dado um grupo recolhido, quando o usuário toca nele, então ele expande mostrando seus itens, sem afetar o estado dos demais grupos.

**CA-011.1**: Dado um usuário numa clínica de Ambiente de teste, quando o menu carrega, então o fundo do menu fica amarelo claro no desktop expandido, no desktop recolhido e no overlay mobile, e o restante da tela permanece como em produção.

**CA-011.2**: Dado um usuário numa clínica de Ambiente de produção, quando o menu carrega, então o fundo do menu é o padrão, o título da aba não tem prefixo e a tag `theme-color` está como estaria sem esta regra.

**CA-011.3**: Dado um usuário numa clínica de Ambiente de teste, quando navega entre telas, então o título da aba sempre começa com "[TESTE] " seguido do título da tela, sem repetir o prefixo.

**CA-011.4**: Dado um usuário numa clínica de Ambiente de teste, num celular cujo navegador aplica `theme-color`, quando o menu carrega, então a barra de status do aparelho fica na mesma cor do fundo do menu, inclusive com o menu fechado.

**CA-011.5**: Dado um usuário com acesso a uma clínica de produção e a uma clínica de teste, quando troca de uma para a outra pelo botão Trocar, então a sinalização é aplicada (produção → teste) ou retirada (teste → produção) assim que o menu da nova clínica carrega.

**CA-011.6**: Dado um usuário numa clínica de Ambiente de teste usando o tema escuro, quando o menu carrega, então o fundo do menu usa o valor escuro de `--color-env-test-surface`, diferente do fundo padrão do menu no tema escuro, e a tag `theme-color` recebe esse mesmo valor (a cor efetiva da barra de status depende de o navegador aplicar `theme-color` no tema escuro).

**CA-011.7**: Dado um usuário numa clínica de Ambiente de teste, quando sai do app-shell (botão Trocar, saída do sistema ou sessão expirada), então o fundo do menu, a tag `theme-color` e o título da aba voltam ao estado sem sinalização antes de a próxima tela aparecer.

### Fluxos de Exceção

**EX-E5-01 — Perfil de acesso sem nenhum item de menu liberado**

Gatilho: perfil de acesso do usuário, na clínica atual, não libera nenhum item para exibição no menu (RN-CIU-027). Comportamento: menu exibido vazio, com mensagem informativa orientando a contatar o administrador da clínica (MSG-I5-01). Recuperação: usuário aguarda o administrador configurar seu perfil de acesso. Nota: cenário de baixa probabilidade nesta versão do sistema — a Central do Médico é hoje o único módulo com item de menu real cadastrado, e todo médico deveria ter perfil de acesso a ele — mas o comportamento vale para qualquer perfil, presente ou futuro, que eventualmente fique sem nenhum item liberado.

**EX-E5-02 — Busca sem nenhum resultado**

Gatilho: texto digitado no campo de busca não corresponde a nenhum item permitido pelo perfil de acesso. Comportamento: estado vazio no lugar da lista, com mensagem orientando a limpar o filtro (MSG-I5-02). Recuperação: usuário apaga ou ajusta o texto buscado.

**EX-E5-03 — Falha ao favoritar/desfavoritar um item**

Gatilho: erro de rede ou falha do back-end ao processar a ação de favoritar ou desfavoritar um item. Comportamento: o estado visual da estrela é revertido ao que era antes do toque, e uma mensagem de erro é exibida (MSG-E5-01). Recuperação: usuário tenta novamente.

**EX-E5-04 — Falha ao carregar os itens do menu no login**

Gatilho: erro de rede ou falha do back-end ao buscar a árvore de itens do menu para o usuário autenticado. Comportamento: estado de erro no lugar do menu, com mensagem (MSG-E5-03) e ação "Tentar novamente" (MSG-B5-01) — sem menu carregado, o usuário não tem como navegar para lugar nenhum. Recuperação: usuário aciona "Tentar novamente"; se persistir, orientação a contatar o suporte.

### Validações de Campos

O único campo de entrada desta funcionalidade é o campo de busca — texto livre, sem obrigatoriedade, sem validação de formato: qualquer texto digitado (incluindo vazio, que restaura a exibição normal) é aceito e usado para filtrar a lista de itens.

### Mapeamento de Componentes de Interface

|Componente|Variante|Estados|Tokens aplicados|Uso nesta tela|
|---|---|---|---|---|
|Painel lateral|Menu (desktop expandido)|default|`--color-base-pure` bg, `--shadow-level-medium`, largura fixa|Estrutura principal do menu, desktop|
|Painel lateral|Menu (desktop recolhido)|default|`--color-base-pure` bg, largura reduzida a ícones|Estado recolhido, só ícones de favoritos|
|Painel overlay|Menu (mobile)|default, entrando/saindo|`--shadow-level-heavy`, sobreposto ao conteúdo com camada de fundo semitransparente|Estado aberto do menu em mobile|
|Painel lateral e painel overlay|Ambiente de teste|default (os três estados acima)|`--color-env-test-surface` bg no lugar de `--color-base-pure`; demais tokens inalterados|Clínica atual em Ambiente de teste (RN-CIU-032, CA-011.1)|
|Meta tag `theme-color`|Ambiente de teste|—|valor resolvido de `--color-env-test-surface` no tema vigente|Barra de status do celular (RN-CIU-032, CA-011.4)|
|Item de grupo (accordion)|Grupo|default, expandido, recolhido|`--spacing-sm` padding, `--color-neutral-pure` texto de rótulo, ícone de chevron rotativo|Cada grupo do menu (RN-CIU-026)|
|Item de menu|Padrão / Favorito|default, hover, active (rota atual), focus|`--radius-m`, `--color-primary-pure` no item ativo, `--spacing-xs` entre ícone e texto|Cada item dentro de um grupo, da lista sem grupo ou da seção Favoritos|
|Ícone de estrela|Favoritar|vazia (não favoritado), preenchida (favoritado), loading|`--color-highlight-pure` (preenchida), `--color-neutral-light` (vazia)|Ação de favoritar/desfavoritar, junto de cada item|
|Input de busca|Busca do menu|default, focus, com texto|`--input-height` reduzido (32px), `--radius-pill`, `--color-neutral-lighter` bg|Campo de busca, topo do menu (RN-CIU-030)|
|Indicador + texto|Marca/Identificação da clínica|default|`--color-primary-pure` (indicador), `--font-size-lg` (nome)|Cabeçalho do menu — nome da clínica atual, oculto (só o indicador permanece) no menu recolhido|
|Button (compacto)|Secondary compacto (Trocar)|default, hover|24px altura, `--font-size-xs`, borda `--color-secondary-pure`|Botão "Trocar" (ícone + rótulo) no cabeçalho do menu, ao lado do nome da clínica, quando visível (CA-010.5/6)|
|Button (icon-only)|Ghost (Recolher/expandir)|default, hover, pressed|`--icon-btn` 36px, borda `--color-neutral-lighter`, `--shadow-level-medium`|Controle de recolher/expandir o menu, fora do menu, em posição fixa (desktop, CA-010.7)|
|Banner/Ícone informativo|Info|default|`--color-secondary-pure`|Mensagem de perfil sem itens (MSG-I5-01) e de busca sem resultado (MSG-I5-02)|
|Toast|Error|default|`--color-error-pure`|Falha ao favoritar (MSG-E5-01)|
|Estado de erro em tela cheia|Erro de carregamento|default|`--color-error-light` bg do ícone, `--color-error-dark` texto do ícone|Falha ao carregar o menu (EX-E5-04)|
|Skeleton|Menu|loading|`--color-neutral-lighter`|Carregamento inicial do menu|
|Rodapé|Marca|default|`--font-size-xs`, `--color-neutral-pure`|Texto estático "Powered by Interprocess TI" (MSG-T5-01)|

### Integração com Backend

**GET /api/v1/menu**
Função: retorna, para o usuário autenticado, a árvore de grupos e itens de menu já filtrada pelo perfil de acesso vigente na clínica atual, com a marcação de quais itens estão favoritados.
Request: nenhum parâmetro (usuário e clínica atual identificados pelo token de sessão, já resolvido em E1/E6).
Response: `{ clinicaAtual: { clienteEmpresaId, nome, caminhoLogo }, ambienteTipo, grupos: [{ processoGrupoId, nome, itens: [{ clientePerfilAcessoProcessoId, processoId, nome, icone, rota, favorito }] }], itensSemGrupo: [{ clientePerfilAcessoProcessoId, processoId, nome, icone, rota, favorito }], favoritos: [{ clientePerfilAcessoProcessoId, processoId, nome, icone, rota }] }` — os itens já vêm na ordem definida para o perfil de acesso (RN-CIU-027); `favoritos` é a lista já pronta para a seção Favoritos e para o menu recolhido, evitando que o front-end precise recalculá-la a partir dos grupos — contém só itens ainda liberados pelo perfil de acesso (subconjunto dos itens de `grupos`/`itensSemGrupo`), ordenados por nome conforme a collation do banco; `grupos` só contém grupos com ao menos um item. A quantidade de clínicas acessíveis, que decide a visibilidade do ícone Trocar (CA-010.5/6), não é recalculada aqui — reaproveita o campo `clinicasAcessiveis` já retornado pelo login (E1). **[PROPOSTA]** `clinicaAtual` é campo novo nesta versão, para o cabeçalho do menu (nome/logo da clínica atual) sobreviver a um recarregamento de página sem depender de o front-end reter o dado desde o login/E6 — mesmos campos (`nome`, `caminhoLogo`) já usados em `ClienteEmpresa` por E3/E6; nenhuma tabela nova. **[PROPOSTA]** `ambienteTipo` é campo novo nesta versão: tipo do Ambiente de trabalho da clínica atual, `"producao"` ou `"homologacao"` (Ambiente de teste), sempre presente — mesmo nome de campo, mesmos valores e mesma tradução de `ClienteBD.Tipo` (`P` → `"producao"`, `T` → `"homologacao"`) já usados por `GET .../clinic-selection` na Seleção de Clínica (E6) (casos de dado ausente ou fora do domínio: Seção 4, 4.1); liga ou não a sinalização de Ambiente de teste (RN-CIU-032). Vem nesta resposta, e não do login, porque o Ambiente só é conhecido depois que a clínica de trabalho é definida e muda a cada troca de clínica — exatamente os momentos em que este endpoint é chamado. O nome do Ambiente não é enviado: não é exibido em lugar nenhum desta funcionalidade (RN-CIU-032).
Códigos: 200 (sucesso — `grupos`, `itensSemGrupo` e `favoritos` podem vir vazios); 401 (não autenticado); 500 (falha ao carregar — EX-E5-04).

**POST /api/v1/menu/items/{clientePerfilAcessoProcessoId}/favorite**
Função: favorita um item do menu para o usuário autenticado, na clínica atual.
Request: nenhum corpo — `clientePerfilAcessoProcessoId` no path identifica o item já filtrado pelo perfil de acesso vigente.
Response: `{ clientePerfilAcessoProcessoId, favorito: true }`.
Códigos: 201 (favoritado); 404 (item não encontrado ou não liberado pelo perfil de acesso atual); 500 (falha — EX-E5-03).

**DELETE /api/v1/menu/items/{clientePerfilAcessoProcessoId}/favorite**
Função: desfavorita um item do menu para o usuário autenticado, na clínica atual.
Request: nenhum corpo — `clientePerfilAcessoProcessoId` no path.
Response: `{ clientePerfilAcessoProcessoId, favorito: false }`.
Códigos: 200 (desfavoritado); 404 (item não estava favoritado); 500 (falha — EX-E5-03).

O mapeamento das tabelas consultadas por estes 3 endpoints, com o detalhamento de campos, domínios e filtros, está na Seção 4 (Mapeamento de Banco de Dados, v1.6) — não repetido aqui (Lição #10 da Skill Designer).

Nota: a busca (RN-CIU-030) não tem endpoint próprio — opera em memória, no front-end, sobre a árvore já retornada por `GET /api/v1/menu`, filtrando por nome a cada caractere digitado, sem diferenciar maiúsculas/minúsculas nem acentos (a comparação é feita no front-end, não pela collation do banco). Isso evita uma chamada de rede a cada tecla, num campo cujo próprio propósito é agilizar a navegação.

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

**Erros:**

|ID|Contexto|pt-BR|en-US|es-419|
|---|---|---|---|---|
|MSG-E5-01|Falha ao favoritar/desfavoritar um item (EX-E5-03)|"Não foi possível atualizar seus favoritos. Tente novamente."|"Could not update your favorites. Please try again."|"No fue posible actualizar sus favoritos. Inténtelo de nuevo."|
|MSG-E5-03|Falha ao carregar os itens do menu (EX-E5-04)|"Não foi possível carregar o menu. Tente novamente."|"Could not load the menu. Please try again."|"No fue posible cargar el menú. Inténtelo de nuevo."|

**Informativas / estado vazio:**

|ID|Contexto|pt-BR|en-US|es-419|
|---|---|---|---|---|
|MSG-I5-01|Perfil de acesso sem nenhum item liberado (EX-E5-01)|"Seu perfil de acesso ainda não libera nenhum item de menu. Entre em contato com o administrador da sua clínica."|"Your access profile doesn't release any menu item yet. Contact your clinic's administrator."|"Su perfil de acceso aún no libera ningún elemento de menú. Comuníquese con el administrador de su clínica."|
|MSG-I5-02|Busca sem nenhum resultado (EX-E5-02)|"Nenhum item encontrado. Tente limpar o filtro de busca."|"No items found. Try clearing the search filter."|"No se encontraron elementos. Intente borrar el filtro de búsqueda."|

**Placeholder:**

|ID|Contexto|pt-BR|en-US|es-419|
|---|---|---|---|---|
|MSG-P5-01|Campo de busca do menu|"Buscar no menu"|"Search menu"|"Buscar en el menú"|

**Textos orientadores:**

|ID|Contexto|pt-BR|en-US|es-419|
|---|---|---|---|---|
|MSG-T5-01|Rodapé do menu (rótulo estático, sem tradução de marca)|"Powered by Interprocess TI"|"Powered by Interprocess TI"|"Powered by Interprocess TI"|
|MSG-T5-02|Prefixo do título da aba em Ambiente de teste (RN-CIU-032), seguido de um espaço e do título da tela|"[TESTE]"|"[TEST]"|"[PRUEBA]"|

**Botões/links:**

|ID|Contexto|pt-BR|en-US|es-419|
|---|---|---|---|---|
|MSG-B5-01|Ação de recuperação (erro de carregamento do menu)|"Tentar novamente"|"Try again"|"Intentar de nuevo"|
|MSG-B5-02|Botão de troca de clínica no cabeçalho do menu|"Trocar"|"Switch"|"Cambiar"|

### Conformidade SBIS (detalhamento)

**ECF.17.18 — Idioma do S-RES** (estágio 1, obrigatório) — todos os rótulos, ícones textuais e mensagens do menu são exibidos em português do Brasil, com suporte adicional a en-US e es-419 (catálogo acima); o requisito cita "menus" explicitamente entre os elementos que devem seguir essa regra. O prefixo de Ambiente de teste no título da aba (MSG-T5-02) segue a mesma regra. A sinalização de Ambiente de teste (RN-CIU-032) não corresponde a nenhum requisito SBIS próprio.

**ECF.17.19 — Mensagens do sistema** (estágio 1, obrigatório) — todas as mensagens do menu (erro, informativa, estado vazio, orientadora) estão catalogadas acima, em linguagem não técnica, sem termos de banco de dados ou de infraestrutura visíveis ao usuário.

**NGS1.03.01 — Impedir acesso por pessoas não autorizadas** (estágio 1, obrigatório) — o menu nunca exibe um item para o qual o usuário não tenha permissão: a filtragem por perfil de acesso (RN-CIU-027) ocorre no carregamento da árvore, no back-end, não como uma regra visual aplicada depois de uma lista completa chegar ao front-end.

**NGS1.03.03 — Gerenciamento de perfis** (estágio 1, obrigatório) — o menu consome, sem redefinir, a atribuição de permissões por perfil de acesso já gerenciada no Contexto de Segurança; cada alteração de quais itens um perfil libera se reflete no menu no próximo carregamento.

**NGS1.03.07 — Atribuição de mais de um perfil para um usuário** (estágio 1, obrigatório) — como um usuário pode ter um perfil de acesso diferente em cada clínica, o menu (itens e favoritos) é recarregado por completo a cada troca de clínica (RN-CIU-028), refletindo sempre o perfil vigente naquela clínica, nunca um acúmulo de permissões de clínicas diferentes.

---

## Histórico de Versões

- **v1.0** (15/09/2026) — versão inicial do épico. Especificação construída a partir dos critérios de aceitação e fluxos de exceção já confirmados, e da estrutura de dados de menu/RBAC/favoritos localizada na Biblioteca de Schema (DDL) — nenhuma tabela nova, 3 endpoints (leitura do menu, favoritar, desfavoritar), busca resolvida inteiramente no front-end sobre a árvore já carregada.
- **v1.1** (15/09/2026) — Terminologia revisada de "profissional" para "usuário", termo próprio do Contexto de Check-in de Usuários (ver 01 - Definição, Histórico de Versões, v1.1). Sem mudança de conteúdo funcional.
- **v1.2** (15/09/2026) — grupo passa a começar recolhido (não expandido) a cada nova sessão; seção Favoritos passa a listar os itens em ordem alfabética pelo nome — ambos confirmados pelo solicitante (ver 01 - Definição, Histórico de Versões, v1.2).
- **v1.3** (15/09/2026) — pedido do solicitante ao revisar o protótipo: nova subseção "Cabeçalho do Menu (identificação da clínica)", documentando pela primeira vez o indicador + nome da clínica no topo do menu (antes só a marca do produto, sem essa informação — gap não documentado). "Botão Trocar" reescrito para a nova posição discreta, ao lado do nome da clínica. "Comportamento Responsivo" ganhou nota sobre o controle de recolher/expandir ficar fora do menu, em posição fixa. Mapeamento de Componentes atualizado (nova linha para a identificação da clínica, linha do Trocar revisada para ícone, nova linha para o controle de recolher/expandir, antes ausente da tabela). `GET /api/v1/menu` ganhou o campo `clinicaAtual` (**[PROPOSTA]**) na resposta, e `ClienteEmpresa` entrou na lista de tabelas envolvidas do endpoint.
- **v1.4** (15/09/2026) — pedido do solicitante ao revisar o protótipo: "Botão Trocar" reescrito — volta a ter rótulo de texto "Trocar" (fonte reduzida, botão mais baixo), em vez do ícone isolado da v1.3, mantendo a posição discreta ao lado do nome da clínica. Linha do Trocar no Mapeamento de Componentes atualizada de "ícone apenas" para "compacto com rótulo".
- **v1.5** (16/09/2026) — "Integração com Backend": removida a linha inline "Tabelas envolvidas: ..." de cada um dos 3 endpoints, substituída por uma nota única apontando para a Seção 4 (Mapeamento de Banco de Dados, v1.5), que passou a detalhar tabelas, campos, domínios e filtros por endpoint — mesma convenção já usada em Central do Médico e Agenda do Médico, escolhida pelo solicitante para este épico. Nenhuma mudança de comportamento, request/response ou código HTTP dos 3 endpoints — só a localização de onde a ligação com o banco de dados é documentada (Lição #10 da Skill Designer).
- **v1.6** (07/10/2026) — aplicação de RN-CIU-032 (sinalização de Ambiente de teste, guarda-chuva v2.26), decidida pelo solicitante: nova história US-CIU-011; nova subseção "Sinalização de Ambiente de teste" (fundo do menu com uma exceção no hover da estrela, `theme-color`, prefixo da aba, comportamento durante skeleton/erro/perfil sem itens e no tema escuro); 7 critérios de aceitação novos (CA-011.1 a CA-011.7, o último acrescentado na revisão de crítico abaixo); 2 linhas novas no Mapeamento de Componentes; campo `ambienteTipo` (**[PROPOSTA]**) na resposta de `GET /api/v1/menu`; nova mensagem MSG-T5-02 ("[TESTE]" / "[TEST]" / "[PRUEBA]" — traduções escolhidas pelo Designer); nota em ECF.17.18. Escolhas do Designer, não pedidas pelo solicitante: o app-shell (e não cada tela) aplica o prefixo; em produção a tag `theme-color` não é tocada por esta regra; sem sinal substituto quando o navegador ignora `theme-color`; nenhum efeito enquanto o menu carrega ou falha; o nome do Ambiente não é enviado pela API, por não ser exibido.
  **Revisão por Dois Críticos** (crítico técnico, subagente independente, mesma sessão; cada achado conferido contra o texto antes de aplicar): `theme-color` passa a ser guardada e restaurada ao sair do teste (antes, a especificação só dizia que produção não toca a tag, sem dizer como desfazer a mudança); mecanismo de atualização da `theme-color` ao mudar o tema descrito (`matchMedia` + atributo `data-theme`); contrato do título da aba (telas informam só o título base; o app-shell compõe, sem repetir o prefixo, e recompõe ao mudar idioma); retirada dos efeitos ao sair do app-shell (Trocar, saída do sistema, 401) e novo CA-011.7; a afirmação de contraste mínimo de 4,5:1 "dos textos do menu" era falsa para o rótulo do Trocar (3,2:1 sobre o amarelo, 3,4:1 já sobre branco) — restrita aos tokens neutros e o rótulo do Trocar registrado como pendência do Design System; CA-011.2 e CA-011.6 reescritos para não depender do navegador; coluna do menu recolhido continua pintada mesmo sem favoritos. Total: 7 CA novos (CA-011.1 a CA-011.7).
- **v1.7** (07/10/2026) — acompanha 01 - Definição v1.9 (6 decisões do solicitante). "Estrutura do Menu": grupo sem nenhum item liberado não é exibido. "Seção Favoritos": ordem alfabética conforme a collation do banco; só favoritos de itens ainda liberados; a busca não afeta a seção; menu recolhido sem favoritos fica vazio. "Busca": por aproximação, sem diferenciar maiúsculas/minúsculas nem acentos; só afeta a árvore. "Comportamento Responsivo": coluna recolhida vazia sem favoritos. "Integração com Backend": descrição de `favoritos` e `grupos` no `GET /api/v1/menu` e nota da busca atualizadas. Nenhum endpoint, campo, código HTTP, critério de aceitação ou mensagem novos.
