SGEProduto · Domínio · Desenvolvimento
Repositório

migration-reference · implemented

Migration 04 — affiliations

Fundação dos vínculos institucionais e do contexto de acesso.

Schema PostgreSQL

CampoTipo e regra
idbigint, chave primária.
user_idbigint obrigatório, FK para users.id com ON DELETE RESTRICT.
campus_idbigint nullable, FK para campuses.id com ON DELETE RESTRICT. Nulo somente em vínculo de SystemAdministrator.
typevarchar(255), convertido pelo cast PHP AffiliationType e validado antes de persistir.
registration_numbervarchar(255) nullable; obrigatório nos tipos diferentes de Supervisor.
emailvarchar(255) obrigatório; e-mail de contato do contexto.
deactivated_attimestamp(0) nullable; nulo significa vínculo ativo.
last_used_attimestamp(0) nullable; último vínculo explicitamente selecionado.
created_at, updated_attimestamps convencionais do Laravel.

Esta migration inicial não contém course_id nem deleted_at. A ausência de curso aqui é intencional: a Migration 10, já implementada, adiciona a FK após a criação de courses na Migration 09. O schema final exige curso para vínculos de discente por validação do Model. Affiliation não usa SoftDeletes: o ciclo de vida do vínculo usa deactivated_at.

FKs e índices

  • A exclusão física de um usuário ou campus referenciado é restringida. A exclusão lógica de Campus não remove nem altera a FK.
  • A migration cria somente a chave primária e as FKs; índices secundários ficam para quando as consultas reais indicarem necessidade.
  • As regras de tipo, campus obrigatório, matrícula e unicidade de matrícula discente são validadas pelo model em PHP. O cast de AffiliationType converte os valores para o enum e rejeita valores desconhecidos ao acessar o atributo.
  • Matrículas de servidores podem se repetir entre funções. Não há unicidade global de e-mail, matrícula de servidor ou combinação usuário/tipo/campus.

Model, relações e validação

Affiliation usa o cast AffiliationType e casts datetime para deactivated_at e last_used_at. As relações iniciais são Affiliation → User, Affiliation → Campus, User → affiliations e Campus → affiliations. A Migration 10 acrescenta Affiliation → Course e a relação inversa de discentes; a Migration 09 acrescenta as relações dos cursos com seus vínculos coordenadores.

AffiliationValidationRules é executado ao salvar e centraliza:

  • enum válido, usuário existente, e-mail obrigatório válido e datas opcionais válidas;
  • campus obrigatório por tipo, campus existente e campus ativo/não excluído ao criar, trocar campus ou reativar;
  • preservação de vínculos existentes quando o campus é posteriormente desativado;
  • matrícula obrigatória para tipos diferentes de supervisor, proibida para supervisor e única somente para discente.

Uma pessoa pode ter vários vínculos, inclusive de tipos ou campi distintos. Na gestão administrativa, a criação e a reativação bloqueiam outro vínculo ativo da mesma pessoa, tipo e campus; a regra é aplicada na transação, sem limpar duplicidades históricas. O campus é um atributo do vínculo e não muda por seleção de contexto.

O scope active() filtra deactivated_at IS NULL. orderByLastUsedAt() ordena por last_used_at DESC NULLS LAST e desempata por id ASC, evitando a ordenação padrão de nulos do PostgreSQL.

Último contexto usado

last_used_at é memória operacional do último vínculo selecionado ou usado numa troca explícita de contexto. markAsUsed() atualiza o timestamp somente quando chamado para um vínculo persistido e ativo. Leituras e requisições comuns não o atualizam.

O campo não é auditado pelo Activity Log e não representa login, logout ou trilha de autenticação. ActiveAffiliationContext restaura o vínculo ativo mais recentemente usado; vínculo desativado nunca é elegível. Se houver um único vínculo ativo, ele é selecionado automaticamente. Com múltiplos vínculos e nenhum uso anterior, a pessoa escolhe em affiliations/select, sem seleção baseada no desempate técnico. Somente a seleção ou troca explícita atualiza last_used_at.

Factory e auditoria

AffiliationFactory fornece os estados global(), onCampus(), server(), student(), supervisor(), deactivated() e recentlyUsed(). Após a Migration 10, student() também cria ou recebe um curso do mesmo campus.

O Spatie Activity Log registra criação e alterações relevantes nos dados fillable, incluindo tipo, campus, matrícula, e-mail e desativação/reativação. last_used_at não é fillable nem auditado; uma alteração isolada não cria atividade.

Na consulta administrativa, o Administrador do Sistema pode ver atividades de vínculos dos tipos Administrador do Sistema e Administrador do Campus, além dos vínculos administrativos associados às contas elegíveis. A seleção ou troca de vínculo atualiza apenas a memória operacional de last_used_at e não é registrada como atividade. O histórico de e-mails mantém um snapshot separado do contexto afetado em email_delivery_attempts.scope_context; esse campo não guarda a seleção de vínculo.

Testes verificados

tests/Feature/AffiliationTest.php cobre schema, rollback/reaplicação em ordem de dependência, FKs, relações, validação PHP e cast enum, curso obrigatório para discente, factory, ativação, ordenação e Activity Log. As alterações das Migrations 09 e 10 foram verificadas no PostgreSQL por Sail junto com tests/Feature/CourseTest.php. A tela de seleção, sessão e middleware são cobertos separadamente por ActiveAffiliationContextTest, DashboardTest e os testes da Fase 02.

Dependências