# 04 — Fluxo de Alterações de Colaborador

> O coração da integração de perfil é a tabela/model `CoreCollabPendingChange`. Ela registra **toda**
> alteração de perfil — vinda do Space ou do Nexos — e controla o ciclo de aprovação.

---

## 1. Model `CoreCollabPendingChange`

[app/Models/Core/CoreCollabPendingChange.php](../../app/Models/Core/CoreCollabPendingChange.php)

| Campo | Descrição |
|-------|-----------|
| `collab_id` | FK para `CoreCollaborator` |
| `space_id` | ID do colaborador no Space (snapshot) |
| `origin` | `exent_space` (veio do app) ou `nexos` (editado internamente) |
| `type` | rótulo: `Informações pessoais`, `Documentos`, `Dados bancários` (ou combinação) |
| `old_info` | snapshot dos valores **antes** (cast `array`) |
| `new_info` | valores **novos** (cast `array`) |
| `status` | `pending`, `approved` ou `rejected` |
| `rejected_reason` | motivo, quando rejeitado |

**Helpers:** `isPending()`, `isApproved()`, `isRejected()`.
**Relação:** `collaborator()` → `belongsTo(CoreCollaborator, 'collab_id')`.

---

## 2. Origem Space — `CollabController::sync()`

[CollabController::sync()](../../app/Http/Controllers/Integrations/CollabController.php#L77)

```
Space POST /integration/collaborators/sync
   │
   ├─ identifica colaborador por (nexos_id + exent_space_id)         → 404 se não achar
   ├─ se já há pendência pending para o colaborador                  → 409
   │
   ├─ coleta newInfo: dados pessoais, localização, contato emergência,
   │  conta bancária (ISPB → bank_ispb) e documentos
   │     · documentos enviados sobem para  collaborator/staging/{nome}/documents  no GCS
   │
   ├─ snapshot oldInfo (mesmos campos) e calcula DIFF REAL
   │     · compara valores string-a-string → evita "pendências fantasma"
   │       (o Space pode reenviar todos os campos sempre)
   │     · sem diferença real → { "Nenhuma alteração detectada." }
   │
   ├─ classifica os campos alterados:
   │     SENSÍVEIS  = name, cpf_number, birthday_date, documentos, dados bancários
   │     NÃO-SENS.  = email, phone, shirt_size, endereço, contato de emergência
   │
   ├─ CASO SENSÍVEL  → cria registro status = 'pending'
   │     · notifyPendingChange(): e-mail (template collab_change_pending) + alerta Slack
   │     · resposta: { pending_approval: true }
   │     · aguarda aprovação manual no Nexos (ver seção 4)
   │
   └─ CASO NÃO-SENSÍVEL → cria registro status = 'approved'
         · aplica direto no colaborador (update)
         · confirma de volta ao Space via syncProfileToSpace(accepted)
           usando app()->terminating()+sleep(2)  (ver 03-sync-outbound.md)
         · resposta: { pending_approval: false }
```

> **Por que staging?** Documentos sensíveis sobem para uma pasta `staging/` e só são movidos para o
> caminho definitivo na **aprovação**. Na rejeição, são apagados.

---

## 3. Origem Nexos — `CollaboratorController::update()`

[CollaboratorController::update()](../../app/Http/Controllers/Core/CollaboratorController.php#L696)

Quando um operador edita o colaborador pela tela do Nexos:

1. Tira um `snapshotCollaborator()` **antes** das mudanças.
2. Salva colaborador, contrato e contas bancárias.
3. Recalcula o diff (`TRACKED_COLLAB_FIELDS` + `TRACKED_BANK_FIELDS`).
4. Se houve diff real **e** o colaborador tem `space_id`, grava um `CoreCollabPendingChange` com
   `origin = 'nexos'` e `status = 'approved'` — registro de **auditoria/histórico**.

Esse fluxo **não** chama `syncProfileToSpace()` diretamente (ver nota em
[03-sync-outbound.md](03-sync-outbound.md#1-detalhe-edição-manual-update-não-chama-o-space-diretamente)).

---

## 4. Aprovação e Rejeição manual (no Nexos)

### Aprovar — `changes_approve()`

[CollaboratorController::changes_approve()](../../app/Http/Controllers/Core/CollaboratorController.php#L1022)

```
1. Move documentos de  staging/  →  collaborator/{nome}/documents  (renameFile no GCS)
   · remove documento antigo órfão se o path mudou
2. Atualiza os campos do colaborador a partir de new_info
3. Atualiza/cria a conta bancária principal (bank_account_data)
4. Marca o registro como 'approved'
5. syncProfileToSpace(collaborator, new_info, 'accepted', type)   → POST /nexos/profile-sync
      · se falhar → HTTP 502 (alteração salva, Space dessincronizado)
6. E-mail best-effort  (template collab_change_approved)
```

### Rejeitar — `changes_reject()`

[CollaboratorController::changes_reject()](../../app/Http/Controllers/Core/CollaboratorController.php#L1257)

```
Body obrigatório: { "reason": "<motivo>" }
1. Deleta documentos staged do GCS
2. Marca o registro como 'rejected' + rejected_reason
3. E-mail (template collab_change_rejected) — se falhar, faz rollback e retorna 500
4. syncProfileToSpace(collaborator, new_info, 'rejected', type)   → POST /nexos/profile-sync
      · se falhar → HTTP 502
```

---

## 5. Visão consolidada dos estados

```
                      ┌─────────────── origin = exent_space ───────────────┐
Space sync ──────────▶│  sensível?                                         │
                      │    sim → status=pending ──(aprovar)──▶ approved ───┼─▶ /nexos/profile-sync (accepted)
                      │                          └─(rejeitar)─▶ rejected ──┼─▶ /nexos/profile-sync (rejected)
                      │    não → status=approved (auto) ───────────────────┼─▶ /nexos/profile-sync (accepted, terminating)
                      └────────────────────────────────────────────────────┘

Edição no Nexos ─────▶ origin = nexos, status = approved (somente histórico/auditoria)

Ativar/Desativar ────▶ syncStatusToSpace ─▶ /nexos/user-status
```

Referências cruzadas: [02-rotas-inbound.md](02-rotas-inbound.md) (contrato do `sync`) e
[03-sync-outbound.md](03-sync-outbound.md) (gatilhos e payloads de saída).
