{
  "id": "model-user",
  "title": "Model — User",
  "description": "Conta autenticável, relações, notificações de senha, autoria no Activity Log e identificação administrável.",
  "type": "technical-reference",
  "status": "in-progress",
  "visibility": "public",
  "tags": [
    "sge/models",
    "sge/autenticacao",
    "sge/dados-pessoais"
  ],
  "related": [
    "cast-cpfcast",
    "migration-02-user-personal-data",
    "migration-04-affiliations",
    "concern-profilevalidationrules"
  ],
  "sourceRefs": [
    "https://github.com/sge-suite/sge/blob/master/app/Models/User.php",
    "https://github.com/sge-suite/sge/blob/master/app/Notifications/QueuedPasswordReset.php",
    "https://github.com/sge-suite/sge/blob/master/app/Support/AdministrativeActivityScope.php",
    "https://github.com/sge-suite/sge/blob/master/app/Support/AdministrativeEmailLogScope.php",
    "https://github.com/sge-suite/sge/blob/master/tests/Feature/Auth/PasswordResetTest.php",
    "https://github.com/sge-suite/sge/blob/master/tests/Feature/DatabaseAuditTest.php",
    "https://github.com/sge-suite/sge/blob/master/tests/Feature/AuditInterfaceTest.php",
    "https://github.com/sge-suite/sge/blob/master/tests/Feature/EmailLogInterfaceTest.php"
  ],
  "authors": [],
  "updated": null,
  "diagram": null,
  "body": "## Responsabilidade atual\n\nModel autenticável do Laravel. Usa `HasFactory`, `LogsActivity` e `Notifiable`, representa a conta de login e fornece as iniciais para a interface.\n\n| Elemento           | Estado atual                                                                   |\n| ------------------ | ------------------------------------------------------------------------------ |\n| atributos fillable | `name`, `cpf`, `email`, `password`, via `#[Fillable]`.                         |\n| atributos ocultos  | `password`, `remember_token`, via `#[Hidden]`.                                 |\n| casts              | `cpf` → [Cast — CpfCast](doc:cast-cpfcast) (`CpfCast`); `password` → `hashed`.           |\n| `initials()`       | Usa `Str::initials()` e retorna primeira/última inicial quando há mais de uma. |\n| relações           | `personalData()` é um perfil opcional um-para-um; `affiliations()` retorna os vínculos institucionais; notificações nativas são fornecidas por `Notifiable`. |\n\n## Auditoria e e-mail\n\n`LogsActivity` registra alterações dos campos fillable, exceto `password`. A mudança de senha gera `password_changed` sem valor anterior, senha nova ou hash. `sendPasswordResetNotification()` usa `QueuedPasswordReset`, enfileirada após o commit e criptografada; recuperação não cria linhas em `email_messages` ou `email_delivery_attempts`.\n\nA consulta administrativa do Activity Log inclui uma conta somente quando ela possui vínculos administrativos, e mostra atividades elegíveis da própria conta e dos vínculos relacionados. O histórico de e-mails usa o snapshot do registro afetado em `scope_context`; não infere autorização pelo e-mail do destinatário nem pelo último vínculo selecionado. Ambas as telas exigem o vínculo ativo e selecionado de Administrador do Sistema.\n\n`UserPersonalData` registra seus atributos fillable (`user_id`, dados pessoais/profissionais e `address_id`) e também `emancipation_verified_at`, que não é fillable porque representa estado controlado pela aplicação. Esse campo é incluído explicitamente no Activity Log com valores anteriores e novos. `id`, `created_at` e `updated_at` ficam fora do registro. A cobertura é verificada por `DatabaseAuditTest`.\n\n## Delimitação de responsabilidade\n\n`users` mantém autenticação, CPF e e-mail de login. O Administrador do Sistema pode editar nome, CPF e e-mail pela interface administrativa; a alteração do endereço de login envia avisos ao endereço anterior e ao novo. [`user_personal_data`](doc:migration-02-user-personal-data) guarda dados pessoais atuais e campos profissionais opcionais do supervisor em um perfil compartilhado pela conta. Cadastro e login não exigem esse perfil; o supervisor preencherá ou confirmará seus dados profissionais no futuro formulário, com edição autorizada pelo tipo de vínculo.\n\n## Checklist\n\n- [x] Configurar autenticação Eloquent para `User`.\n- [x] Ocultar senha e remember token.\n- [x] Aplicar cast de senha com hash automático.\n- [x] Aplicar `CpfCast` no estado atual.\n- [x] Criar relações com `Affiliation` e `UserPersonalData` e habilitar notificações nativas do Laravel. A conta não possui relação direta com `EmailMessage`; seu histórico é separado.\n- [x] Manter CPF em `$fillable`, docblock e casts de `User`.\n- [x] Testar conta sem dados pessoais completos.\n- [x] Testar conta com múltiplos vínculos em PostgreSQL.\n- [x] Permitir a administração de nome, CPF e e-mail de login por `UserController`, preservando as notificações de troca de e-mail e a auditoria sem senha.\n- [x] Testar recuperação enfileirada sem persistir token ou corpo nas tabelas próprias de e-mail.\n- [x] Registrar no Activity Log os campos pessoais e profissionais alterados de `UserPersonalData`, com valores anteriores/novos e autoria do vínculo ativo.\n\n## Relacionamentos\n\n- [user_personal_data](doc:migration-02-user-personal-data)\n- [CpfCast](doc:cast-cpfcast)\n- [ProfileValidationRules](doc:concern-profilevalidationrules)\n- [Painel de desenvolvimento](doc:painel-de-desenvolvimento)",
  "sections": [
    {
      "id": "responsabilidade-atual",
      "level": 2,
      "title": "Responsabilidade atual",
      "text": "Model autenticável do Laravel. Usa `HasFactory`, `LogsActivity` e `Notifiable`, representa a conta de login e fornece as iniciais para a interface.  | Elemento           | Estado atual                                                                   | | ------------------ | ------------------------------------------------------------------------------ | | atributos fillable | `name`, `cpf`, `email`, `password`, via `#[Fillable]`.                         | | atributos ocultos  | `password`, `remember_token`, via `#[Hidden]`.                                 | | casts              | `cpf` → [Cast — CpfCast](doc:cast-cpfcast) (`CpfCast`); `password` → `hashed`.           | | `initials()`       | Usa `Str::initials()` e retorna primeira/última inicial quando há mais de uma. | | relações           | `personalData()` é um perfil opcional um-para-um; `affiliations()` retorna os vínculos institucionais; notificações nativas são fornecidas por `Notifiable`. |",
      "line": 1
    },
    {
      "id": "auditoria-e-e-mail",
      "level": 2,
      "title": "Auditoria e e-mail",
      "text": "`LogsActivity` registra alterações dos campos fillable, exceto `password`. A mudança de senha gera `password_changed` sem valor anterior, senha nova ou hash. `sendPasswordResetNotification()` usa `QueuedPasswordReset`, enfileirada após o commit e criptografada; recuperação não cria linhas em `email_messages` ou `email_delivery_attempts`.  A consulta administrativa do Activity Log inclui uma conta somente quando ela possui vínculos administrativos, e mostra atividades elegíveis da própria conta e dos vínculos relacionados. O histórico de e-mails usa o snapshot do registro afetado em `scope_context`; não infere autorização pelo e-mail do destinatário nem pelo último vínculo selecionado. Ambas as telas exigem o vínculo ativo e selecionado de Administrador do Sistema.  `UserPersonalData` registra seus atributos fillable (`user_id`, dados pessoais/profissionais e `address_id`) e também `emancipation_verified_at`, que não é fillable porque representa estado controlado pela aplicação. Esse campo é incluído explicitamente no Activity Log com valores anteriores e novos. `id`, `created_at` e `updated_at` ficam fora do registro. A cobertura é verificada por `DatabaseAuditTest`.",
      "line": 13
    },
    {
      "id": "delimitacao-de-responsabilidade",
      "level": 2,
      "title": "Delimitação de responsabilidade",
      "text": "`users` mantém autenticação, CPF e e-mail de login. O Administrador do Sistema pode editar nome, CPF e e-mail pela interface administrativa; a alteração do endereço de login envia avisos ao endereço anterior e ao novo. [`user_personal_data`](doc:migration-02-user-personal-data) guarda dados pessoais atuais e campos profissionais opcionais do supervisor em um perfil compartilhado pela conta. Cadastro e login não exigem esse perfil; o supervisor preencherá ou confirmará seus dados profissionais no futuro formulário, com edição autorizada pelo tipo de vínculo.",
      "line": 21
    },
    {
      "id": "checklist",
      "level": 2,
      "title": "Checklist",
      "text": "- [x] Configurar autenticação Eloquent para `User`. - [x] Ocultar senha e remember token. - [x] Aplicar cast de senha com hash automático. - [x] Aplicar `CpfCast` no estado atual. - [x] Criar relações com `Affiliation` e `UserPersonalData` e habilitar notificações nativas do Laravel. A conta não possui relação direta com `EmailMessage`; seu histórico é separado. - [x] Manter CPF em `$fillable`, docblock e casts de `User`. - [x] Testar conta sem dados pessoais completos. - [x] Testar conta com múltiplos vínculos em PostgreSQL. - [x] Permitir a administração de nome, CPF e e-mail de login por `UserController`, preservando as notificações de troca de e-mail e a auditoria sem senha. - [x] Testar recuperação enfileirada sem persistir token ou corpo nas tabelas próprias de e-mail. - [x] Registrar no Activity Log os campos pessoais e profissionais alterados de `UserPersonalData`, com valores anteriores/novos e autoria do vínculo ativo.",
      "line": 25
    },
    {
      "id": "relacionamentos",
      "level": 2,
      "title": "Relacionamentos",
      "text": "- [user_personal_data](doc:migration-02-user-personal-data) - [CpfCast](doc:cast-cpfcast) - [ProfileValidationRules](doc:concern-profilevalidationrules) - [Painel de desenvolvimento](doc:painel-de-desenvolvimento)",
      "line": 39
    }
  ],
  "sourcePath": "content/model-user.md",
  "visuals": [],
  "apiVersion": 1
}
