# Épico 6 — Seleção de Clínica — Mapeamento de Banco de Dados (v2.0)

**Documentos deste épico:** [01 - Definição](./01%20-%20Defini%C3%A7%C3%A3o%20v2.0.md) (v2.0) · [02 - Especificação](./02%20-%20Especifica%C3%A7%C3%A3o%20v2.0.md) (v2.0) · [03 - Protótipo](./03%20-%20Prot%C3%B3tipo%20v2.0.md) (v2.0, código executável em `03 - Protótipo v2.0.html`) · [04 - Mapeamento de Banco de Dados](./04%20-%20Mapeamento%20de%20Banco%20de%20Dados%20v2.0.md) (v2.0). 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

### Tabelas existentes utilizadas

|Tabela|Banco|Campos utilizados neste épico|
|---|---|---|
|UsuarioCliente|IpSeguranca|Id, UsuarioId, ClienteBDId, Situacao (domínio C/V/B — RN-CIU-011, em CIU-E3), RemovidoEm — `ClienteBDId` é uma coluna de chave estrangeira escalar (um único valor por linha, não uma tabela de associação N:N), o que por si só garante que cada vínculo ou convite pertence a exatamente um Ambiente — usado para saber a qual grupo Cliente/Ambiente a resposta de `accept-invite` pertence (02 - Especificação); a restrição `UNIQUE(UsuarioId, ClienteBDId)` é uma regra de negócio distinta (não permitir dois vínculos do mesmo usuário no mesmo Ambiente), não a origem do fato acima|
|ClienteBD|IpSeguranca|Id, Nome, Tipo, ClienteId — é o Ambiente de trabalho (RN-CIU-031); `Nome` é exibido no cabeçalho do container quando o Ambiente não é de produção; `ClienteId` liga o Ambiente ao Cliente contratante, usado para formar o grupo (Rótulo de Cliente); `Tipo` (`char(1)`, sem `CHECK` explícito) é o campo indicado pelo solicitante como o que diferencia produção de homologação/teste — **[PROPOSTA]** o mapeamento exato de valor de domínio para "produção"/"homologação" ainda não está catalogado na Biblioteca de Schema (DDL), pendência já registrada em `Log de Mudanças Estruturais do Banco de Dados` desde a revisão da Seção 1|
|Cliente|IpSeguranca|Id, Nome, CaminhoLogo — é o Cliente contratante (RN-CIU-031); `Nome` é o texto exibido no rótulo discreto acima de cada grupo, suprimido quando o profissional só tem vínculo com 1 Cliente; `CaminhoLogo` é a fonte do campo `clienteLogo` usado como fallback no card de convite sem clínica associada (02 - Especificação, `GET .../clinic-selection`)|
|ClienteEmpresa|IpSeguranca|Id, Nome, CaminhoLogo, ClienteBDId, RemovidoEm — exibidos na lista de clínicas e no card de convite; cada registro é uma clínica dentro de um Ambiente; a Lista de Clínicas filtra `RemovidoEm IS NULL`|
|ClientePerfilAcesso|IpSeguranca|Id, Nome, ClienteBDId — consultado na verificação de Perfil de acesso (RN-CIU-015)|
|ClientePerfilAcessoUsuario|IpSeguranca|Id, ClientePerfilAcessoId, UsuarioClienteId, ClienteEmpresaId, EmpresaPadrao — consultado na verificação de Perfil de acesso (RN-CIU-015) e na montagem da resposta de `accept-invite`/`clinic-selection` (02 - Especificação); é a partir daqui que a lista de clínicas acessíveis é composta, uma por ClienteEmpresa distinta; `EmpresaPadrao` (`char(1)`, `DEFAULT 'N'`) é o campo que determina qual clínica é a principal do profissional dentro de um Ambiente (RN-CIU-031, item 2) — **[PROPOSTA]** o domínio de valores não está catalogado explicitamente na Biblioteca de Schema, presume-se `'S'`/`'N'` pelo padrão já usado em outros campos `char(1)` de sinalização binária deste mesmo schema, a confirmar|
|UsuarioClienteConvite|IpSeguranca|Token, DataExpiracao — consultados/apagados no aceite do card (mesma tabela criada em CIU-E3, Seção 4; deleção física ao aceitar, RN-CIU-024)|

Nenhuma tabela nova. Este épico passa a consultar também `ClienteBD` e `Cliente` — ambas já existentes e já mapeadas em outros épicos deste conjunto (E1, para nome/logo do Cliente no login) — para exibir o agrupamento por Ambiente e por Cliente definido em RN-CIU-031; nenhuma estrutura de dados nova foi necessária.

### Fonte de dado candidata para a ordenação por acesso recente (RN-CIU-031, item 4)

A ordenação da lista pela clínica acessada mais recentemente pelo profissional (critério ainda **[PROPOSTA]** quanto à janela de tempo e ao desempate — ver 01 - Definição) depende de uma fonte de dado de acesso por clínica que este épico, até esta revisão, não havia precisado consultar. Foi localizada na Biblioteca de Schema (DDL) uma tabela candidata:

|Tabela|Banco|Campos candidatos|
|---|---|---|
|SessaoUsuario|IpSeguranca|`EmpresaId` (clínica acessada), `ClienteId`, `ClienteBDId` (Ambiente da sessão), `CriadoEm` (data/hora de criação da sessão), `Status`, `RemovidoEm`, `UsuarioIdCriado` (candidato a "profissional dono da sessão" — ver ressalva abaixo)|

**[PROPOSTA — a confirmar com o solicitante antes de implementar]**: `SessaoUsuario` registra cada sessão de trabalho já com a clínica (`EmpresaId`), o Cliente (`ClienteId`) e o Ambiente (`ClienteBDId`) associados, e `CriadoEm` daria a data do acesso — o candidato natural para `MAX(CriadoEm)` agrupado por `EmpresaId`, filtrado pelo profissional autenticado e por uma janela de tempo (7 dias, sugestão do solicitante na Seção 1, ainda a validar). A tabela, porém, não tem uma coluna própria de "usuário dono da sessão": tem apenas `UsuarioIdCriado`, um campo de auditoria (padrão "criado por" repetido em quase toda tabela deste schema), não uma coluna semântica de propriedade. Usar `UsuarioIdCriado` como "o profissional dessa sessão" é uma inferência razoável para uma sessão de login — mas é uma inferência, não um fato confirmado na Biblioteca de Schema nem pelo solicitante; por isso permanece como proposta, não como mapeamento definitivo, seguindo a mesma cautela já aplicada a outras inferências de schema deste conjunto de épicos (Skill Designer, Lição #21). Se confirmada, a resposta do endpoint de listagem (02 - Especificação, campo `ultimoAcesso`) viria de uma subconsulta `MAX(CriadoEm)` por `EmpresaId`, e não exigiria nenhuma tabela ou coluna nova.

### Domínio de campos ainda não catalogados

|Campo|Tabela|Situação|
|---|---|---|
|`Tipo`|ClienteBD|`char(1) NOT NULL`, sem `CHECK` no DDL — valores que distinguem produção de homologação/teste não catalogados; pendência já registrada em `Log de Mudanças Estruturais do Banco de Dados`|
|`EmpresaPadrao`|ClientePerfilAcessoUsuario|`char(1) DEFAULT 'N' NOT NULL`, sem `CHECK` no DDL — domínio presumido `'S'`/`'N'` por convenção do schema, não confirmado|

---

## Histórico de Versões

- **v1.0** (29/08/2026) — Arquivo criado pela divisão do documento único `(CIU-E6) Seleção de Clínica v1.0.md` em arquivos por seção (ver Skill Designer, "Organização Física: Pasta por Funcionalidade", Lição #18). Conteúdo sem alteração de substância em relação à v1.0 original — apenas reorganização física (o protótipo HTML já era um arquivo separado desde a v1.0 original, só foi renomeado para a convenção nova). Histórico de revisões anterior a esta divisão (v0.1 a v1.0) preservado integralmente no documento original arquivado.
- **v1.1** (14/09/2026) — trocada `Cliente` por `ClienteEmpresa` nas tabelas existentes utilizadas; `ClientePerfilAcessoUsuario` passa a listar o campo `ClienteEmpresaId`, base para compor a lista de clínicas acessíveis (RN-CIU-009, em CIU-E1). Nenhuma tabela nova — ambas já existem em produção.
- **v1.2** (14/09/2026) — atualização de referência: 01-Definição, 02-Especificação e 03-Protótipo deste épico foram revisados (v1.2, v1.2 e v1.1, respectivamente); a nota sobre `ClientePerfilAcessoUsuario` foi complementada para deixar explícito que essa tabela também é usada para montar a resposta do endpoint `accept-invite` (02 - Especificação, "Tabelas envolvidas"), lacuna apontada em revisão técnica. Nenhuma tabela nova nem alteração na lista de tabelas já mapeada na v1.1.
- **v1.3** (14/09/2026) — adicionado o campo `RemovidoEm` à tabela `ClienteEmpresa`, usado para filtrar a Lista de Clínicas às apenas ativas — consequência da confirmação do solicitante de que uma `ClienteEmpresa` desativada tira o acesso dos usuários hoje associados a ela. Nenhuma tabela nova.
- **v2.0** (18/09/2026) — adicionadas `ClienteBD` e `Cliente` às tabelas utilizadas, para exibir o agrupamento por Ambiente e por Cliente de RN-CIU-031 (01 - Definição v2.0); campo `EmpresaPadrao` (`ClientePerfilAcessoUsuario`) documentado como a marcação de clínica principal usada para ordenar dentro de um Ambiente. Confirmado na Biblioteca de Schema (DDL), `IpSeguranca.sql`: `UsuarioCliente.ClienteBDId` é uma coluna de chave estrangeira escalar, o que garante que um vínculo/convite pertence a exatamente um Ambiente — usado para simplificar a resposta de `accept-invite` (02 - Especificação); a restrição `UNIQUE(UsuarioId, ClienteBDId)`, também presente nessa tabela, é uma regra de negócio distinta (não permitir dois vínculos do mesmo usuário no mesmo Ambiente) e não a origem desse fato — atribuição corrigida nesta revisão após achado da revisão de crítico técnico (ver abaixo). Nova seção "Fonte de dado candidata para a ordenação por acesso recente": localizada a tabela `SessaoUsuario` (colunas `EmpresaId`, `ClienteId`, `ClienteBDId`, `CriadoEm`, `UsuarioIdCriado`) como candidata a fonte do critério de ordenação por acesso recente ([PROPOSTA] em RN-CIU-031, item 4) — registrada como **[PROPOSTA, não implementação definitiva]**, já que a tabela não tem uma coluna semântica de "usuário dono da sessão" (apenas o campo de auditoria `UsuarioIdCriado`), e usá-la para esse fim é uma inferência a confirmar com o solicitante, não um fato já estabelecido. Nova seção "Domínio de campos ainda não catalogados", consolidando duas pendências de domínio (`ClienteBD.Tipo`, já registrada desde a revisão da Seção 1; `ClientePerfilAcessoUsuario.EmpresaPadrao`, nova nesta revisão) — nenhuma delas exige tabela ou coluna nova, apenas confirmação de valores.

  **Revisão de crítico técnico** (Skill Designer, "Revisão por Dois Críticos") — rodada como subagente independente sobre as Seções 2, 3 e 4 revisadas nesta mesma rodada (agrupamento Cliente/Ambiente, RN-CIU-031). Cada achado foi reverificado por mim contra o schema real ou o documento-fonte antes de decidir a correção; nenhum foi aplicado sem essa verificação. 17 problemas encontrados:

  1. Contradição entre esta seção (Histórico dizia "revisão registrada ao final desta entrada") e a 02 - Especificação v2.0 (Histórico dizia "revisão pendente de execução conjunta") — nenhuma das duas de fato continha a lista de achados. **Corrigido**: ambas as entradas de Histórico reescritas nesta revisão para refletir a revisão concluída, com a lista completa registrada apenas aqui.
  2. Tabela `Cliente` acima listava apenas `Id, Nome`, omitindo `CaminhoLogo` — coluna real (confirmada na Biblioteca de Schema (DDL)) que sustenta o campo `clienteLogo` usado como fallback pela 02 - Especificação. **Corrigido**: `CaminhoLogo` adicionado à linha `Cliente` acima.
  3. No protótipo (03 - Protótipo v2.0.html), o estado inicial (`default`) exibia o rótulo de Cliente mesmo havendo apenas 1 grupo de Cliente na tela — contradiz RN-CIU-031 item 1 / CA-006.6 (rótulo suprimido com 1 único Cliente). **Corrigido**: função `updateClientLabels()` implementada no protótipo, reavaliando a contagem de grupos e aplicando a classe `single-client` (já existente em CSS) na carga inicial e após o aceite de convite criar um novo grupo.
  4. Texto de MSG-I6-02 catalogado em 02 - Especificação não coincidia literalmente com o texto exibido no protótipo. **Corrigido**: textos alinhados nos dois documentos.
  5. O toast exibido no protótipo para o caso "convite aceito com clínica" ("Convite aceito. Selecione a clínica na lista para entrar.") não tinha um MSG-ID catalogado. **Corrigido**: nova mensagem MSG-I6-03 adicionada ao catálogo de 02 - Especificação.
  6. MSG-I6-02 estava documentada em 02 - Especificação como um componente "Banner", mas implementada no protótipo como um toast transiente. **Corrigido**: decisão de manter MSG-I6-02 como banner persistente (é um estado contínuo — o profissional segue sem acesso até liberação do administrador, não uma confirmação pontual); o protótipo foi alterado para inserir um banner inline no lugar do card de convite, e o toast passou a ser exclusivamente o de MSG-I6-03 (caso "convite aceito com clínica", transiente por natureza).
  7. MSG-T6-02, catalogada como "título da lista", é na verdade o H1 da tela ("Selecione uma clínica"); a lista tem um título próprio, não catalogado. **Corrigido**: descrição de MSG-T6-02 corrigida para "Título da tela (H1)"; nova MSG-T6-03 adicionada para "Suas clínicas" (título da seção de lista).
  8. CA-006.9 estava redigido de forma incompatível com o mecanismo de remoção reativa descrito em EX-E6-05. **Corrigido**: CA-006.9 reescrito para descrever a remoção imediata do item e do container do Ambiente, referenciando EX-E6-05 diretamente.
  9. A justificativa técnica de "um vínculo/convite pertence a exatamente um Ambiente" (Card de Convite Pendente e endpoint `accept-invite`, em 02 - Especificação; tabela `UsuarioCliente` acima e o parágrafo do Histórico da v2.0 anterior a esta correção) atribuía o fato à restrição `UNIQUE(UsuarioId, ClienteBDId)` — tecnicamente incorreto: a causa é `ClienteBDId` ser uma coluna de chave estrangeira escalar (um valor por linha); a `UNIQUE` é uma regra de negócio à parte (impedir vínculo duplicado no mesmo Ambiente), não a origem da propriedade "um único Ambiente por linha". **Corrigido** nos três lugares (02 - Especificação, tabela `UsuarioCliente` acima, e nesta mesma entrada de Histórico).
  10. A tabela de "campos candidatos" de `SessaoUsuario` (seção acima) omitia `UsuarioIdCriado`, mesmo o parágrafo logo abaixo dependendo inteiramente dessa coluna para propor (com ressalva) o uso da tabela. **Corrigido**: `UsuarioIdCriado` adicionado à tabela.
  11. Falhas de contraste WCAG 2.1 AA identificadas no protótipo: (a) texto do cabeçalho do Ambiente de testes (`--color-highlight-dark` sobre `--color-highlight-light`, ≈2,1:1) — **corrigido**, trocado para `--color-neutral-darker`; (b) texto do rótulo de Cliente (`--color-neutral-light`) — **corrigido**, trocado para `--color-neutral-pure`; (c) texto de corpo geral em `--color-neutral-pure` sobre fundo claro e (d) texto branco sobre `--color-primary-pure` nos botões primários — **não corrigidos nesta revisão**: são padrões pré-existentes, herdados sem alteração do protótipo oficial já publicado (v1.1) e usados em todo o produto: corrigi-los apenas neste documento criaria inconsistência com o restante do Gemed já em produção. Registrado aqui como observação de nível Design System, a ser tratada centralmente (`Design System.md`), não como pendência deste épico.
  12. Elementos decorativos sem `aria-hidden="true"`: os 6 chevrons (`.chevron`) e as 7 iniciais de avatar (`.clinic-avatar`) do protótipo. **Corrigido**: `aria-hidden="true"` adicionado a todas as ocorrências.
  13. Os atributos `role="button"` e `tabindex="0"` das linhas de clínica (`.clinic-row`) só eram aplicados via JavaScript (`bindClinicRow()`), ficando ausentes até a execução do script. **Corrigido**: atributos movidos para HTML estático nas linhas interativas (dentro de `#clinic-groups` e no template de clínica criado pelo aceite de convite); a atribuição via JS foi removida por redundante. As linhas de exemplo do estado `blocked` (demonstração estática, sem manipulador de clique) foram deixadas sem esses atributos, por não serem de fato interativas nesse estado do protótipo.
  14. Ícones fora do padrão do projeto (lucide.dev / react-icons): o chevron (caractere `›`), o ícone de erro (`!`), o ícone de sucesso (`✓`) e o ícone do banner informativo (`i`) eram caracteres de texto/CSS, não ícones das bibliotecas aprovadas. **Corrigido**: os quatro substituídos por SVG inline dos ícones Lucide correspondentes (`chevron-right`, `alert-circle`, `check`, `info`).
  15. O atributo `data-cliente-bd-id` no protótipo, ao ser lido via `.dataset` (que converte para camelCase), pode ser confundido com um espelho literal do campo `clienteBDId` da API — hoje inofensivo (não é lido por nenhum script), mas uma fonte de confusão futura. **Corrigido**: comentário explicativo adicionado no HTML, esclarecendo que é uma anotação visual/de demonstração do mock, não um campo de resposta da API.
  16. A abertura da 03 - Protótipo v2.0.md afirmava cobrir os "touchpoints de ponta a ponta", mas os desfechos de falha do aceite de convite (EX-E6-02, EX-E6-03) não são demonstrados no protótipo. **Corrigido**: frase suavizada para "principais estados desta tela", com nota explícita de que EX-E6-02/EX-E6-03 não são demonstrados.
  17. A descrição do endpoint `GET .../clinic-selection` (02 - Especificação) não deixava explícito que `ambientes[]`, e não apenas `clinicas[]`, também segue a ordenação de RN-CIU-031 item 4. **Corrigido**: frase adicionada explicitando que o critério de ordenação se aplica tanto entre `grupos[]` (Cliente) quanto entre os itens de `ambientes[]` dentro de um mesmo grupo.
