# Lote 2026-05-20 — Usuários: import em fila, histórico, listagem, exclusão em lote e BI paginado

**Registro:** 2026-05-20 — **pendente commit** na working tree.

Documentação cruzada: [bi-dashboard.md](./bi-dashboard.md) (secção progresso paginado), [registro-entregas.md](./registro-entregas.md).

---

## 1. Import de usuários em fila

### Produto

- Upload CSV/XLSX enfileira job `ProcessUserBulkImportJob` (não bloqueia o request HTTP).
- Card na listagem de usuários com progresso (%), contadores (criados / erros) e status (Na fila, Processando, etc.).
- **Encerrar importação** — cancela importações `pending` ou `processing` (policy `cancel`).
- Planilha de resultado (coluna Status) após conclusão — download via `users.import.report`.
- Limite de linhas: `config/user_bulk_import.php` → `USER_BULK_IMPORT_MAX_ROWS` (default 5000).

### Operação (obrigatório em dev/produção)

```bash
php artisan migrate
php artisan queue:work
```

Sem worker ativo, a importação permanece **Na fila**.

### Camadas

```
UserImportController
  → UserBulkImportService::enqueueImport / progressPayload / historyPayload / requestCancel
  → UserBulkImportRepository
  → ProcessUserBulkImportJob (fila)
```

### Rotas

| Método | URL | Nome |
|--------|-----|------|
| GET | `/users/import/template` | `users.import.template` |
| POST | `/users/import` | `users.import.store` |
| GET | `/users/import/historico` | `users.import.history` (JSON) |
| GET | `/users/import/{id}/progress` | `users.import.progress` (JSON) |
| POST | `/users/import/{id}/cancel` | `users.import.cancel` |
| GET | `/users/import/relatorio/{id}` | `users.import.report` (XLSX) |

### Modelo e migrations

- `user_bulk_imports` — `2026_05_20_142536_create_user_bulk_imports_table.php`
- Progresso e cancelamento — `2026_05_20_150000_add_progress_and_cancel_to_user_bulk_imports_table.php`
- Enum `UserBulkImportStatus`: `pending`, `processing`, `completed`, `failed`, `cancelled`
- Policy `UserBulkImportPolicy` (`viewAny`, `view`, `downloadReport`, `cancel`)

### Views

- `resources/views/users/_import-progress.blade.php` — polling a cada 2s
- `resources/views/users/_import-modal.blade.php`
- `resources/views/users/_import-history-button.blade.php`
- `resources/views/users/_import-history-modal.blade.php`

### Testes

```bash
php artisan test --filter=UserBulkImportTest
```

---

## 2. Histórico de importações

### Produto

- Botão **Histórico de importações** (cabeçalho da listagem, card de progresso e card pós-importação).
- Modal com tabela: **data/hora**, **quem importou** (nome + e-mail), arquivo, tipo (Portal/Equipe), status, resultado, link **Relatório** quando existir.
- Paginação no modal (25 por página; API aceita `page`, `per_page` 10|25|50).
- Escopo: apenas importações da `company_id` do utilizador autenticado.

### API

`GET /users/import/historico` → JSON `{ data: [...], meta: { current_page, last_page, total, ... } }`

Autorização: `viewAny` em `UserBulkImport`.

---

## 3. Listagem de usuários (filtros, busca, ordenação, paginação)

### Produto

- Formulário de filtros: busca (nome/e-mail), área, grupo, tipo de conta, situação (ativo/inativo), itens por página (10/20/50/100).
- Cabeçalhos da tabela ordenáveis: nome, e-mail, área, grupo, status.
- Contador «Exibindo X–Y de Z usuário(s)».

### Camadas

```
UserController::index(IndexUsersRequest)
  → UserService::paginateUsers
  → UserRepository::paginateByCompany
```

### Request

`App\Http\Requests\Users\IndexUsersRequest` — `listFilters()`, `filterFormValues()`.

### Views

- `resources/views/users/_filters.blade.php`
- `resources/views/users/index.blade.php` (datatable + `{{ $users->links() }}`)

### Testes

```bash
php artisan test --filter=UserIndexListingTest
```

---

## 4. Exclusão de usuários em lote

### Produto

- Botão **Excluir em lote** (policy `bulkDelete` em `UserPolicy`).
- Modal: escopo por **área (setor)** ou **grupo de treinamento**; pré-visualização da quantidade (JSON).
- Não remove o utilizador autenticado nem quem tem role de admin global legado.

### Rotas

| Método | URL | Nome |
|--------|-----|------|
| GET | `/users/bulk-delete/preview` | `users.bulk-delete.preview` |
| DELETE | `/users/bulk-delete` | `users.bulk-delete.destroy` |

### Camadas

`UserBulkDeleteController` → `UserBulkDeleteService` → `UserRepository` (queries de exclusão por setor/grupo).

### Testes

```bash
php artisan test --filter=UserBulkDeleteTest
```

---

## 5. Dashboard — progresso por participante (busca, ordenação, paginação)

Ver detalhes em [bi-dashboard.md](./bi-dashboard.md#progresso-por-participante-8).

Resumo:

- Busca por nome ou e-mail na secção (query `search`).
- Ordenação por cabeçalho: participante, área, grupo, bateria, status, pontos, última atividade (`sort`, `direction`).
- Paginação (`per_page` 10|20|50|100, `page`).
- Export Excel continua exportando **todos** os registros com os filtros do dashboard (sem paginação da tabela).

Enum: `TrainingDashboardParticipantProgressSort`.

Método: `TrainingDashboardRepository::paginateParticipantsWithProgress` + `TrainingDashboardService::paginateParticipantsWithProgress`.

---

## 5b. Dashboard — Ranking / Pódio (gestão)

Ver [bi-dashboard.md](./bi-dashboard.md#ranking--pódio-gestão).

Resumo:

- Página `/dashboard/ranking` com abas **Geral**, **Por área**, **Por grupo**; nomes dos participantes no pódio e na lista.
- Reutiliza `x-portal.battery-ranking` (`variant="management"`).
- `TrainingDashboardRepository::participantRanking` (melhor sessão por user; SQL compatível com MySQL 5.7).
- Após deploy: `npm run build` (novo bundle `dashboard-ranking.css`).

---

## 6. Inventário principal (novos)

```
app/Enums/TrainingDashboardParticipantProgressSort.php
app/Enums/TrainingDashboardRankingScope.php
app/Enums/UserBulkDeleteScope.php
app/Enums/UserBulkImportStatus.php
app/Enums/UserListActiveStatusFilter.php
app/Http/Controllers/UserBulkDeleteController.php
app/Http/Requests/Users/DestroyUsersBulkRequest.php
app/Http/Requests/Users/IndexUsersRequest.php
app/Jobs/ProcessUserBulkImportJob.php
app/Models/UserBulkImport.php
app/Policies/UserBulkImportPolicy.php
app/Repositories/Contracts/UserBulkImportRepositoryInterface.php
app/Repositories/Eloquent/UserBulkImportRepository.php
app/Services/UserBulkDeleteService.php
app/Support/NormalizedName.php
app/Support/SpreadsheetChunkReadFilter.php
app/Support/UserBulkImportProgress.php
config/user_bulk_import.php
database/migrations/2026_05_20_142536_create_user_bulk_imports_table.php
database/migrations/2026_05_20_150000_add_progress_and_cancel_to_user_bulk_imports_table.php
resources/views/users/_bulk-delete-modal.blade.php
resources/views/users/_filters.blade.php
resources/views/users/_import-history-button.blade.php
resources/views/users/_import-history-modal.blade.php
resources/views/users/_import-progress.blade.php
tests/Feature/Users/UserBulkDeleteTest.php
tests/Feature/Users/UserIndexListingTest.php
```

## 7. Inventário principal (alterados)

```
app/Http/Controllers/DashboardController.php
app/Http/Controllers/UserController.php
app/Http/Controllers/UserImportController.php
app/Http/Requests/Dashboard/DashboardRequest.php
app/Policies/UserPolicy.php
app/Providers/AppServiceProvider.php
app/Providers/AuthServiceProvider.php
app/Repositories/Contracts/TrainingDashboardRepositoryInterface.php
app/Repositories/Eloquent/TrainingDashboardRepository.php
app/Repositories/Eloquent/UserRepository.php
app/Services/TrainingDashboardService.php
app/Services/UserBulkImportService.php
app/Services/UserService.php
resources/views/dashboard/_participants-progress.blade.php
resources/views/dashboard/_ranking-tabs.blade.php
resources/views/dashboard/ranking.blade.php
resources/views/dashboard.blade.php
resources/css/dashboard-ranking.css
resources/views/users/_import-modal.blade.php
resources/views/users/index.blade.php
routes/web.php
tests/Feature/Dashboard/TrainingDashboardTest.php
tests/Feature/Users/UserBulkImportTest.php
```

---

## 8. Verificação antes do commit

```bash
php artisan migrate
npm run build
php artisan test --filter='UserBulkImportTest|UserIndexListingTest|UserBulkDeleteTest|TrainingDashboardTest'
# Em ambiente com import real:
php artisan queue:work
```

---

## 9. Mensagem de commit sugerida

```
feat(usuarios): import em fila com histórico, listagem filtrada e exclusão em lote

feat(dashboard): busca, ordenação e paginação no progresso por participante

feat(dashboard): ranking/pódio gestão (geral, por área e por grupo)

docs: lote usuários import fila, histórico e BI paginado (2026-05-20)
```
