# Épico 5 — Menu Lateral — Mapeamento de Banco de Dados (v1.5)

**Documentos deste épico:** [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.5.md) (v1.5) · [03 - Protótipo](./03%20-%20Prot%C3%B3tipo%20v1.6.md) (v1.6, código executável em `03 - Protótipo v1.6.html`) · [04 - Mapeamento de Banco de Dados](./04%20-%20Mapeamento%20de%20Banco%20de%20Dados%20v1.5.md) (v1.5). Este épico faz parte do documento guarda-chuva [Check-in de Usuários](../00%20-%20Guarda-chuva%20v2.25.md).

---

## SEÇÃO 4 — MAPEAMENTO DE BANCO DE DADOS

### 4.1 Endpoint: GET /api/v1/menu

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 (02 - Especificação, "Integração com Backend").

#### Tabelas envolvidas

| Tabela | Banco | Função no endpoint |
|---|---|---|
| ClienteProcesso | IpSeguranca | Habilitação de cada `Processo` para o `ClienteBD` (tenant) do usuário — só processos habilitados entram na consulta |
| ClientePerfilAcessoUsuario | IpSeguranca | Resolve o perfil de acesso vigente do usuário na clínica atual (`RemovidoEm` nulo) |
| ClientePerfilAcesso | IpSeguranca | Perfil de acesso resolvido a partir de `ClientePerfilAcessoUsuario` |
| ClientePerfilAcessoProcesso | IpSeguranca | Liga o perfil de acesso a um `ClienteProcesso`; `ExibeMenu` e `Ordem` decidem quais itens aparecem e em que posição (RN-CIU-027) |
| Processo | IpSeguranca | Nome, ícone e rota de cada item de menu |
| ProcessoGrupo | IpSeguranca | Nome do grupo a que um item pertence, quando existe |
| ClienteUsuarioMenuFavorito | IpSeguranca | Marca quais itens estão favoritados para este usuário/perfil/clínica (RN-CIU-028) |
| ClienteEmpresa | IpSeguranca | Nome/logo da clínica atual — campo `clinicaAtual` da resposta |

#### Mapa de campos

| Campo | Tipo | Banco | Observação |
|---|---|---|---|
| `clinicaAtual.clienteEmpresaId` | uuid | `ClienteEmpresa.Id` (uniqueidentifier) | |
| `clinicaAtual.nome` | string | `ClienteEmpresa.Nome` (varchar(50)) | |
| `clinicaAtual.caminhoLogo` | string | `ClienteEmpresa.CaminhoLogo` (varchar(100), nullable) | |
| `grupos[].processoGrupoId` | uuid | `ProcessoGrupo.Id` (uniqueidentifier) | |
| `grupos[].nome` | string | `ProcessoGrupo.Nome` (varchar(20)) | |
| `grupos[].itens[].clientePerfilAcessoProcessoId` | uuid | `ClientePerfilAcessoProcesso.Id` (uniqueidentifier) | identifica o item já resolvido para o perfil vigente — é o id usado depois pelos endpoints de favoritar (4.2/4.3) |
| `grupos[].itens[].processoId` | uuid | `Processo.Id` (uniqueidentifier) | |
| `grupos[].itens[].nome` | string | `Processo.Nome` (varchar(50)) | |
| `grupos[].itens[].icone` | string | `Processo.Icone` (varchar(40), nullable) | nome de ícone de lucide.dev/icons ou react-icons.github.io, nunca um arquivo próprio |
| `grupos[].itens[].rota` | string | `Processo.Rota` (varchar(128), nullable) | |
| `grupos[].itens[].favorito` | bool | calculado | existe linha ativa (`RemovidoEm` nulo) em `ClienteUsuarioMenuFavorito` para o par (`ClientePerfilAcessoUsuarioId` do usuário/clínica atual, `ClientePerfilAcessoProcessoId` do item) |
| `itensSemGrupo[]` | mesmos 5 campos de `grupos[].itens[]` acima | `Processo.ProcessoGrupoId IS NULL` | mesma origem, apenas sem o agrupamento |
| `favoritos[]` | mesmos 5 campos, sem `favorito` (a própria presença na lista já é o favorito) | `ClienteUsuarioMenuFavorito` filtrado por `ClientePerfilAcessoUsuarioId` do usuário/clínica atual, `RemovidoEm` nulo | ordenado por `Processo.Nome` (RN-CIU-028) |

#### Domínios

`ExibeMenu` (domínio de `ClientePerfilAcessoProcesso.ExibeMenu`, char(1), default `'S'`):

| Valor | Significado |
|---|---|
| S | Item aparece no menu para este perfil de acesso |
| N | Item habilitado para o cliente (`ClienteProcesso`) mas oculto do menu para este perfil especificamente |

#### Filtros do endpoint

- `ClienteProcesso.ClienteBDId = {ClienteBD do usuário autenticado}` AND `ClienteProcesso.RemovidoEm IS NULL` — apenas processos habilitados para o tenant
- `ClientePerfilAcessoUsuario` referente ao (usuário logado, `ClienteEmpresa` atual da sessão), `RemovidoEm IS NULL` — resolve o `ClientePerfilAcessoId` vigente
- `ClientePerfilAcessoProcesso.ClientePerfilAcessoId = {perfil resolvido}` AND `ExibeMenu = 'S'` AND `RemovidoEm IS NULL` — só os itens liberados para exibição no menu (RN-CIU-027)
- Ordenação dos itens dentro de cada grupo (ou da lista sem grupo): `ClientePerfilAcessoProcesso.Ordem` ascendente
- `favoritos`: `ClienteUsuarioMenuFavorito.ClientePerfilAcessoUsuarioId = {vínculo usuário/perfil/clínica atual}` AND `RemovidoEm IS NULL`, ordenado por `Processo.Nome` (RN-CIU-028)

---

### 4.2 Endpoint: POST /api/v1/menu/items/{clientePerfilAcessoProcessoId}/favorite

Favorita um item do menu para o usuário autenticado, na clínica atual (02 - Especificação, "Integração com Backend").

#### Tabelas envolvidas

| Tabela | Banco | Função no endpoint |
|---|---|---|
| ClientePerfilAcessoProcesso | IpSeguranca | Valida que o item existe, pertence ao perfil de acesso vigente e está com `ExibeMenu = 'S'` — senão 404 |
| ClienteUsuarioMenuFavorito | IpSeguranca | Insere (ou reativa, se já existia com `RemovidoEm` preenchido — RN-CIU-005) a linha do par usuário/item |

#### Mapa de campos

| Campo | Tipo | Banco | Observação |
|---|---|---|---|
| `clientePerfilAcessoProcessoId` (path) | uuid | `ClienteUsuarioMenuFavorito.ClientePerfilAcessoProcessoId` (uniqueidentifier) | metade da PK composta |
| — | — | `ClienteUsuarioMenuFavorito.ClientePerfilAcessoUsuarioId` (uniqueidentifier) | outra metade da PK composta — resolvido do usuário/clínica atual da sessão, não vem no request |
| `favorito` (response) | bool | fixo `true` | |

#### Filtros do endpoint

- Valida que `clientePerfilAcessoProcessoId` pertence ao perfil de acesso vigente do usuário na clínica atual, com `ExibeMenu = 'S'` (mesmo filtro do GET, 4.1) — senão 404
- Exclusão lógica (RN-CIU-005, transversal): se já existe uma linha para o par com `RemovidoEm` preenchido, o INSERT vira UPDATE limpando `RemovidoEm`, em vez de criar uma segunda linha — a PK composta (`ClientePerfilAcessoUsuarioId`, `ClientePerfilAcessoProcessoId`) não permite duplicidade

---

### 4.3 Endpoint: DELETE /api/v1/menu/items/{clientePerfilAcessoProcessoId}/favorite

Desfavorita um item do menu para o usuário autenticado, na clínica atual (02 - Especificação, "Integração com Backend").

#### Tabelas envolvidas

| Tabela | Banco | Função no endpoint |
|---|---|---|
| ClienteUsuarioMenuFavorito | IpSeguranca | Exclusão lógica (`RemovidoEm`) da linha do par usuário/item |

#### Mapa de campos

| Campo | Tipo | Banco | Observação |
|---|---|---|---|
| `clientePerfilAcessoProcessoId` (path) | uuid | `ClienteUsuarioMenuFavorito.ClientePerfilAcessoProcessoId` (uniqueidentifier) | junto de `ClientePerfilAcessoUsuarioId` (resolvido da sessão), identifica a linha a remover |
| `favorito` (response) | bool | fixo `false` | |

#### Filtros do endpoint

- `ClienteUsuarioMenuFavorito.ClientePerfilAcessoUsuarioId = {vínculo usuário/perfil/clínica atual}` AND `ClientePerfilAcessoProcessoId = {path}` AND `RemovidoEm IS NULL` — 404 se não existia favoritado
- Exclusão lógica (RN-CIU-005, transversal): marca `RemovidoEm`, nunca remove a linha fisicamente

---

### Tabelas existentes utilizadas (consolidado)

Consolidado por tabela, como referência rápida — o detalhamento de campos e uso já está nas seções de endpoint acima (4.1 a 4.3), não repetido aqui (Lição #10 da Skill Designer).

| Tabela | Banco | Endpoints que usam |
|---|---|---|
| Processo | IpSeguranca | 4.1 |
| ProcessoGrupo | IpSeguranca | 4.1 |
| ClienteProcesso | IpSeguranca | 4.1 |
| ClientePerfilAcesso | IpSeguranca | 4.1 |
| ClientePerfilAcessoUsuario | IpSeguranca | 4.1 |
| ClientePerfilAcessoProcesso | IpSeguranca | 4.1, 4.2 |
| ClienteUsuarioMenuFavorito | IpSeguranca | 4.1, 4.2, 4.3 |
| ClienteEmpresa | IpSeguranca | 4.1 |

Nenhuma tabela nova. Toda a estrutura necessária — itens de menu, agrupamento, habilitação por cliente, liberação e ordem por perfil de acesso, favoritos, e a identificação da clínica no cabeçalho do menu — já existe em produção no banco IpSeguranca. Tipos e nullability confirmados na Biblioteca de Schema (DDL), `IpSeguranca.sql`, nesta versão (16/09/2026).

**Separação de bancos:** todas as tabelas utilizadas por este épico pertencem ao banco IpSeguranca.

### Schema legado identificado e descartado

O banco de template `GescomZeradoPadronizacao` (mesmo arquivo de origem da Biblioteca de Schema) tem uma estrutura equivalente e mais antiga para menu: `SegMenu`, `SegPastaMenu`, `SegMenuGrupo` e `SegMenuDetalhe` — esta última com um campo `PaginaInicial` que corresponde, na estrutura legada, ao mesmo papel do campo `ProcessoAbertura` de `ClienteUsuarioMenuFavorito` na estrutura atual — correspondência que ajudou a localizar o campo, com o significado hoje confirmado na Seção 1 (RN-CIU-028).

Essa estrutura legada foi identificada e descartada em favor do schema moderno acima: pertence ao banco de template pré-Clean-Architecture, chaveado por identificadores numéricos locais (`smallint`) em vez de `uniqueidentifier`, e não tem nenhum dos conceitos centrais da arquitetura atual — não existe `Cliente`, `ClienteBD` (banco por tenant) nem `ClienteEmpresa` (clínica) na cadeia de chaves de `SegMenuDetalhe`, apenas um `IdUsuario` local. Não é uma base compatível com o modelo multi-tenant deste projeto.

### Campo novo proposto: `ClientePerfilAcessoUsuario.CodProfissional`

A Seção 1 (RN-CIU-028) documenta que, na ausência de uma escolha manual de tela inicial, a tela inicial padrão do usuário é seu próprio cockpit, quando seu perfil de acesso tiver um indicado. Esse indicador não existe hoje em nenhuma base consultada (Biblioteca de Schema (DDL) nem `EsquemaGemed21.csv` — checado em 15/09/2026, reconfirmado em 16/09/2026) — confirmado pelo solicitante como campo novo a criar:

|Campo|Tabela|Tipo|Obrigatoriedade|Valor padrão|Descrição|
|---|---|---|---|---|---|
|`CodProfissional`|`ClientePerfilAcessoUsuario` (IpSeguranca)|`char(3)`|Nullable — confirmado pelo solicitante; ausência de código é o que produz "sem tela inicial" (RN-CIU-028) quando também não há escolha manual|Sem valor padrão (NULL)|Código do tipo de cockpit/central padrão do usuário nessa combinação perfil × clínica — determina qual cockpit abre como tela inicial na ausência de uma escolha manual de tela inicial (RN-CIU-028). Nome, tabela, tipo, nullability e domínio de valores confirmados pelo solicitante. Domínio: `MED`, `ENF`, `FAR`, `REC`, `ADM`, `BKO` — cada valor aponta para a central (cockpit) correspondente; `MED`/`ENF`/`FAR`/`BKO` correspondem aos fluxos por profissional já documentados no projeto (médico, enfermagem, farmácia, backoffice), `REC`/`ADM` apontam para centrais ainda não especificadas em nenhum épico consultado até aqui.|

Migração (estrutura confirmada pelo solicitante; execução real no banco ainda pendente): `ALTER TABLE IPSeguranca.dbo.ClientePerfilAcessoUsuario ADD CodProfissional char(3) NULL` — pendente de execução real no banco e de registro na Biblioteca de Schema (DDL) depois de aplicada. Ver `Log de Mudanças Estruturais do Banco de Dados`, entrada de 15/09/2026.

Nota: este campo não é consultado por nenhum dos 3 endpoints deste épico (4.1 a 4.3) — a resolução de tela inicial por `CodProfissional` acontece no roteamento pós-login (E1), não na montagem do menu em si. Permanece documentado aqui, e não numa seção de endpoint, por ser um achado de estrutura do épico como um todo.

### Seeds da Funcionalidade

|Seed|Tabela(s)|Por cliente ou global?|Status|Detalhe completo|
|---|---|---|---|---|
|Item de menu "Suporte Gemed" (link externo à aplicação de suporte técnico da Interprocess TI)|Processo (mais ClienteProcesso e ClientePerfilAcessoProcesso, por cliente/perfil, para habilitá-lo)|Global o cadastro do Processo; a habilitação por cliente e perfil de acesso é individual|**[PROPOSTA]** — item de exemplo, existência e nome exatos a confirmar contra o mockup original do menu, hoje indisponível|01 - Definição, "Lista consolidada de itens [PROPOSTA]", item 2|
|Árvore completa de grupos e itens do menu (quais Processo existem, em quais ProcessoGrupo, com quais ícones e rotas)|Processo, ProcessoGrupo, ClienteProcesso, ClientePerfilAcessoProcesso|Processo/ProcessoGrupo globais; ClienteProcesso e ClientePerfilAcessoProcesso por cliente/perfil|**[PROPOSTA]** — pendente de um levantamento de produto que substitua o mockup perdido; sem essa árvore, nenhum cliente novo tem menu funcional além dos módulos já especificados individualmente (Central do Médico/Cockpit, Agenda do Médico)|01 - Definição, "Lista consolidada de itens [PROPOSTA]", item 1|

Nenhum parâmetro de configuração (`IpParametro`/`IpParametroChave` ou equivalente) é necessário para esta funcionalidade — o comportamento do menu (filtragem, favoritos, busca, responsividade) não depende de nenhum valor configurável por cliente além da própria estrutura de `Processo`/`ClientePerfilAcessoProcesso` já listada acima.

---

## Histórico de Versões

- **v1.0** (15/09/2026) — versão inicial do épico. Estrutura de dados localizada por completo na Biblioteca de Schema (DDL), banco IpSeguranca — nenhuma tabela nova. Schema legado equivalente (`GescomZeradoPadronizacao.dbo.SegMenu`/`SegPastaMenu`/`SegMenuGrupo`/`SegMenuDetalhe`) identificado e descartado, com a correspondência de `SegMenuDetalhe.PaginaInicial` registrada como base da interpretação [PROPOSTA] de `ClienteUsuarioMenuFavorito.ProcessoAbertura`. Dois seeds registrados como [PROPOSTA] — item "Suporte Gemed" e a árvore completa de grupos/itens do menu, ambos pendentes do mockup original perdido.
- **v1.1** (15/09/2026) — `ClienteUsuarioMenuFavorito.ProcessoAbertura` deixa de ser [PROPOSTA]: confirmado como o indicador da escolha do usuário de tela inicial do sistema (RN-CIU-028), sobrepondo o cockpit padrão quando presente. Novo achado: o campo que identifica o cockpit padrão do usuário em `ClientePerfilAcessoUsuario`, citado pelo solicitante, não foi localizado na Biblioteca de Schema (DDL) nem no `EsquemaGemed21.csv` — registrado como pendência técnica nesta seção e no `Log de Mudanças Estruturais do Banco de Dados`.
- **v1.2** (15/09/2026) — confirmada pelo solicitante a criação de `ClientePerfilAcessoUsuario.CodProfissional`, `char(3)` — a pendência técnica anterior (campo não localizado) vira proposta de estrutura: nova subseção "Campo novo proposto" substitui "Pendência técnica: campo do cockpit padrão", com a migração sugerida. Nullability e domínio de valores do campo seguem [PROPOSTA], não confirmados pelo solicitante. `Log de Mudanças Estruturais do Banco de Dados` atualizado.
- **v1.3** (15/09/2026) — confirmados pelo solicitante os dois atributos de `CodProfissional` que seguiam [PROPOSTA]: nullable; domínio `MED`, `ENF`, `FAR`, `REC`, `ADM`, `BKO` (cada código aponta para a central/cockpit correspondente). Tabela de especificação do campo e migração sugerida atualizadas para refletir a estrutura confirmada — só a execução real da migração no banco segue pendente. `Log de Mudanças Estruturais do Banco de Dados` atualizado.
- **v1.4** (15/09/2026) — pedido do solicitante ao revisar o protótipo: `ClienteEmpresa` passa de "não consultada para montar o menu" para efetivamente consultada — `Nome` e `CaminhoLogo` alimentam o novo campo `clinicaAtual` (**[PROPOSTA]**) da resposta de `GET /api/v1/menu`, para o cabeçalho do menu exibir o nome da clínica atual (Seção 2, "Cabeçalho do Menu"). Mesmos campos de `ClienteEmpresa` já usados por E3/E6 para nome/logo de clínica — nenhuma estrutura nova, nenhuma tabela nova.
- **v1.5** (16/09/2026) — Reestruturação da Seção 4, a pedido do solicitante: a antiga tabela única "Tabelas existentes utilizadas" foi substituída por 3 subseções por endpoint (4.1 `GET /api/v1/menu`, 4.2 `POST .../favorite`, 4.3 `DELETE .../favorite`), cada uma com Tabelas envolvidas, Mapa de campos, Domínios (quando aplicável) e Filtros do endpoint — mesmo padrão (mais detalhado) já usado em Central do Médico (Cockpit) e Agenda do Médico, escolhido pelo solicitante em vez do padrão mais leve usado até então neste próprio épico e no E6 (uma linha "Tabelas envolvidas" dentro do endpoint, na Seção 2). Tipos de campo (`uniqueidentifier`, `varchar(N)`, `char(1)`, `tinyint`) confirmados na Biblioteca de Schema (DDL), `IpSeguranca.sql`, nesta versão. A tabela consolidada por tabela foi mantida, ao final, como referência rápida, sem repetir o detalhamento já dado por endpoint (Lição #10). "Schema legado identificado e descartado", "Campo novo proposto: CodProfissional" e "Seeds da Funcionalidade" preservados sem alteração de conteúdo. Nenhuma tabela nova, nenhuma mudança de estrutura de dados — reorganização documental. Em consequência, a Seção 2 (02 - Especificação, v1.5) teve as linhas inline "Tabelas envolvidas: ..." de cada endpoint removidas, substituídas por uma nota única apontando para esta Seção 4 — mesma convenção de Central do Médico/Agenda do Médico, evitando repetir a mesma informação em dois lugares (Lição #10).
