---
suivi: 1425
date: 2026-09-03
sujet: Widget Aktor sur le tableau de bord
chantier: dashboard
type: feat
statut: poussé
hash: d17e644c
fichiers:
  - config/dashboard_widgets.php
  - app/Services/Dashboard/WidgetCatalogService.php
  - app/Services/Dashboard/WidgetDataService.php
  - app/Services/Dashboard/DashboardDefaultLayoutService.php
  - resources/js/Components/Dashboard/AktorWidget.vue
  - resources/js/Components/Dashboard/WidgetBody.vue
  - resources/js/Components/Dashboard/WidgetWrapper.vue
  - tests/Unit/WidgetAktorCatalogTest.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - public/build/
  - docs/suivi/SUIVI_1425_widget_aktor.md
---

## PROMPT ENVOYÉ

SUIVI #1425 — widget Aktor dashboard (question/réponse sans historique UI),
réutilise routes `/aktor`, GS_GROUPE via m365GroupNames() brut, prérequis #1424
sur origin/main. Ne pas toucher prompt, quota service, AideVisibilite, prune,
hauteur #1396, widgets existants.

## FICHES LUES

- `#1424` — concision Aktor sur main (`CONCISION (#1424)` confirmé).
- `#1396` LEÇON — pas de plancher hauteur en lecture (respecté).
- `#1352` — pattern widget interactif (DepotFactureWidgetUpload) + opt-in catalogue.
- `#1333` / `#1329` — hauteurs catalogue ; URLs en dur.

## SYNTHÈSE

### Prérequis
`origin/main` contient #1424 (`9465a066` / `b18e68fa`, bloc CONCISION présent).

### Tailles catalogue
- `default_width` = **6** (moitié de grille, comme depot / factures)
- `default_height` = **7** (~408 px : saisie + zone réponse défilante ; même ordre
  que `factures_a_valider` / `factures_bloquees`, sous le dropzone depot à 9)

### Route réutilisée
- `POST /aktor/conversations` → `assistant.conversations.store`
- `POST /aktor/conversations/{id}/messages` → `assistant.conversations.messages.store`
  (identique à `Assistant/Index.vue` `API_BASE='/aktor'`)

### Persistance conversation
Une conversation est créée au premier envoi du montage widget, réutilisée pour
les questions suivantes de la session. Les messages sont en base → visibles dans
l’historique de la page `/aktor`. Le widget UI n’affiche que le dernier échange
(remplacement). Quota : −1 par message, même compteur 25/jour. Pas d’affichage
du reste.

### Droits
Catalogue + `widgetData` + `saveLayout` : `required_m365_groups => ['GS_GROUPE']`
via `User::m365GroupNames()` brut. Envoi : middleware existant `m365.groups:GS_GROUPE`
sur les routes Aktor (403 si non membre ; admin ERP court-circuité côté middleware
historique — le catalogue masque déjà sans GS_GROUPE brut).
Test sans GS_GROUPE : compte non-admin sans ce groupe (pas Robin / GS_ADMIN_ERP).

### Bundle
`resources/js/Pages/Dashboard/Index.vue` → `Index-DM01yWoz2.js` (+ app-CE5StE5-.js).
Rebuild < 50 fichiers public/build.

## DÉPLOIEMENT / TEST

```bash
git pull origin main
php artisan view:clear
php artisan journal:sync
```

Pas de migrate. Pas de route:clear. Ne pas lancer prune.

1. Ajouter widget Aktor → taille 6×7.
2. Question → spinner + bouton disabled → réponse.
3. Double-clic Envoyer → un seul message.
4. Réponse longue → scroll vertical, pas de coupe, pas d’overflow-x-hidden.
5. Hauteur 1 → saisie + lien utilisables.
6. Redim + F5 → tient (#1396).
7. 2e question remplace la 1re.
8. Lien « Ouvrir dans Aktor ».
9. Quota avant/après (−1).
10. User sans GS_GROUPE : absent catalogue ; POST messages → 403.
11. Non-régression depot / bloquées / à valider.

## LEÇON

Pour un droit M365 « vrai », filtrer le catalogue avec `m365GroupNames()` brut :
`hasAnyM365Group` / `isAdminERP` / Gate::before faussent le test (Robin seul
GS_ADMIN_ERP). L’envoi reste protégé par les routes Aktor existantes.
