# Ramais > Movido do `CLAUDE.md` da raiz em 2026-08-26 para reduzir conflito de edição entre aplicações. Ver `CLAUDE.md` na raiz para arquitetura geral/transversal do Portal (modelo de permissões, API, CSS, etc.). Este arquivo não é auto-carregado pelo Claude Code (não há pacote Python dedicado a Ramais, o código vive em `portal_api/models.py`/`views.py`/`serializers.py` junto com o resto) — leia manualmente ao mexer nesta aplicação. O diretório de `ramais.html` é **automático**: `RamalViewSet.list()` (não o `RamalSerializer` — esse serializer só cobre as linhas avulsas via CRUD normal) mescla, a cada `GET /api/ramais/`, duas fontes numa lista só, ordenada por nome: 1. Todo `Usuario` ativo — a linha é montada direto do cadastro (`nome`, `Usuario.departamentos` juntados por vírgula, `Usuario.ramal`); se o colaborador ainda não tem ramal preenchido, `numero_exibicao` vem vazio e o frontend mostra um badge "Pendente" em vez de reclamar de campo faltando. 2. As linhas avulsas de `Ramal` (sem `Usuario` por trás — telefone de sala, recepção etc.), cadastradas pelo modal "Adicionar Ramal". Cada item da lista mesclada tem um `id` sintético (`"usuario-"` ou `"avulso-"`) e um campo `tipo` (`"usuario"`/`"avulso"`) que o frontend usa pra decidir qual endpoint chamar ao editar/excluir — não existe mais um model unificando os dois casos com uma FK opcional (essa foi a primeira versão da tela; revertida a pedido do usuário pra eliminar o passo manual de "adicionar" alguém que já tem cadastro). Segue o mesmo padrão visualizar/editar de Links & Ferramentas (ver `CLAUDE.md` na raiz, seção "Padrão visualizar/editar" dentro de "Modelo de permissões"): leitura exige `apps.visualizar` (liberado a todo perfil, já que `ramais` está em `BASE_KEYS`), escrita exige `apps.editar` — por ora só `True` pra "Integração e Inovação" no `seed_portal.py`, exatamente como pedido; liberar outro perfil não pede código novo, só marcar o app na árvore de Perfis de Acesso. - **Editar o ramal de um colaborador de verdade**: não existe "criar" — a linha já aparece sozinha. O lápis na linha abre o mesmo modal de Ramal, mas com Nome/Departamento desabilitados (só leitura do cadastro) e só o campo Ramal editável; salvar chama `PATCH /api/ramais/usuarios/{usuario_id}/` (`RamalViewSet.atualizar_ramal_usuario`), que grava direto em `Usuario.ramal` — é assim que a tela demonstra a alteração refletindo no cadastro do usuário. - **Linha avulsa**: "Adicionar Ramal" sempre cria uma linha avulsa (`POST /api/ramais/`, `nome`/`departamento`/`numero` livres — só `nome` é obrigatório, o resto pode ficar pendente igual a um colaborador de verdade). Editar/excluir uma linha avulsa usa `PATCH`/`DELETE /api/ramais/{avulso_id}/` normalmente; excluir só existe pra esse tipo (não dá pra "excluir" um colaborador daqui — isso é na tela de Usuários). - **Lista de usuários do modal de Ausência**: `RamalViewSet.usuarios_disponiveis` (`GET /api/ramais/usuarios/`) devolve só `id`/`nome` de usuários ativos, pra alimentar o `` mostra a data/hora formatada mesmo `disabled`, sem precisar formatar manualmente), com "Editar Ausência"/"Deletar Ausência" visíveis só pra quem tem `apps.editar`. "Editar" habilita os mesmos campos in-place (sem modal novo) e troca os botões por "Cancelar"/"Salvar Ausência" (`PATCH /api/ramais-ausencias/{id}/`); "Deletar" remove o registro (`DELETE`) — não existe mais um botão de "encerrar antes do previsto" separado (a rodada anterior tinha isso via `encerrada_manualmente`; substituído por editar/excluir de verdade, mais simples e é o que foi pedido). O campo `encerrada_manualmente` continua no model (histórico/uso futuro via admin), só não tem mais UI própria. - **Aniversariante**: comparação de `Usuario.data_aniversario` (mês/dia) com `timezone.localdate()`, feita no mesmo `list()` — mesmo campo que já existia no cadastro de Usuários, sem nada novo ali. - **Selos de ausente/aniversariante**: `.ram-badge--ausente`/`.ram-badge--aniversario` (`ramais.css`) são selos (pill) com cor de texto/fundo ajustada por tema via `:root[data-theme="light"] .ram-badge--*` — não reaproveitam `--danger`/`--gold` crus porque esses tokens não foram pensados pra texto pequeno sobre um selo (contraste insuficiente). A linha inteira também é tingida (`.ram-row--ausente`/`.ram-row--aniversario` td, aplicado via classe no `` em `ramais.js`) com a mesma cor do selo, também ajustada por tema — pedido explícito do usuário pra facilitar notar a linha antes mesmo de ler o selo (a versão anterior sem tingimento de linha foi revertida). - **Férias**: a aba existe (navegação por abas, ver abaixo) mas está **vazia de propósito** — o conteúdo foi adiado pra uma rodada futura; a limitação original ("depende de integração futura com outro banco") continua valendo, só a decisão de já reservar o espaço na navegação é nova. - **Novo Chamado**: botão que abre um modal com um `