Épico 5 — Menu Lateral — Especificação (v1.1)
Documentos deste épico: 01 - Definição (v1.1) · 02 - Especificação (v1.1) · 03 - Protótipo (v1.0, código executável em 03 - Protótipo v1.0.html) · 04 - Mapeamento de Banco de Dados (v1.1). Este épico faz parte do documento guarda-chuva Check-in de Usuários.
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.
Descrição Funcional Detalhada
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 começa expandido (ver “Premissas”, 01 - Definição) e pode ser recolhido/expandido 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. 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.
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). 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 no próprio menu. 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). 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)
Exibido no cabeçalho do menu, 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 e favoritos) 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.
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).
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.
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 |
| 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) |
| Button | Secondary (Trocar) | default, hover | --btn-height-sm, borda --color-secondary-pure | Botão “Trocar” no cabeçalho do menu, quando visível (CA-010.5/6) |
| 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: { 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. A quantidade de clínicas acessíveis, que decide a visibilidade do botão Trocar (CA-010.5/6), não é recalculada aqui — reaproveita o campo clinicasAcessiveis já retornado pelo login (E1).
Códigos: 200 (sucesso — grupos, itensSemGrupo e favoritos podem vir vazios); 401 (não autenticado); 500 (falha ao carregar — EX-E5-04).
Tabelas envolvidas: Processo, ProcessoGrupo, ClienteProcesso, ClientePerfilAcesso, ClientePerfilAcessoUsuario, ClientePerfilAcessoProcesso, ClienteUsuarioMenuFavorito (IpSeguranca).
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).
Tabelas envolvidas: ClienteUsuarioMenuFavorito (insere o par ClientePerfilAcessoUsuarioId/ClientePerfilAcessoProcessoId — IpSeguranca).
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).
Tabelas envolvidas: ClienteUsuarioMenuFavorito (remove o par — IpSeguranca).
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. 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” |
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.
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.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.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.