Épico 5 — Menu Lateral — Especificação (v1.4)
Documentos deste épico: 01 - Definição (v1.7) · 02 - Especificação (v1.4) · 03 - Protótipo (v1.4, código executável em 03 - Protótipo v1.4.html) · 04 - Mapeamento de Banco de Dados (v1.4). 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
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 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 (RN-CIU-028). 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 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). 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.
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) |
| 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 }, 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 í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, ClienteEmpresa já é uma das tabelas consultadas por este endpoint (ver Seção 4).
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, ClienteEmpresa (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.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.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/menuganhou o campoclinicaAtual([PROPOSTA]) na resposta, eClienteEmpresaentra na lista de tabelas envolvidas do endpoint — ver Seção 4. - 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.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.