---
suivi: 1238
date: 2026-08-07
sujet: derniere_connexion_activite
chantier: admin / adoption / rgpd
type: feature
statut: poussé
hash: 4cc0b022
fichiers:
  - database/migrations/2026_08_07_123800_add_derniere_connexion_et_activite_to_users_table.php
  - app/Support/UserActivityTracker.php
  - app/Listeners/RecordUserLoginTimestamp.php
  - app/Http/Middleware/TrackUserActivity.php
  - app/Providers/AppServiceProvider.php
  - bootstrap/app.php
  - app/Services/ImpersonationService.php
  - app/Models/User.php
  - app/Http/Controllers/Admin/AdminController.php
  - resources/js/Pages/Admin/Index.vue
  - tests/Unit/UserActivityTrackerTest.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - docs/suivi/SUIVI_1238_derniere_connexion.md
  - public/build/
---

# SUIVI #1238 — Dernière connexion / activité (adoption)

## PROMPT ENVOYÉ

Traçage `derniere_connexion_at` (auth) + `derniere_activite_at` (requêtes auth,
throttlé). Affichage admin + compteurs adoption. RGPD : dernière valeur seule,
pas d'historique / IP / page. Pas de backfill. Middleware hors routes publiques.

## FICHES LUES

- `#1234` — diag : colonnes last_login absentes ; `updated_at` inutilisable pour
  l'adoption. LEÇON : mesurer l'usage réel, pas le bruit schéma.

## OBJET 1 — Migration

Fichier : `2026_08_07_123800_add_derniere_connexion_et_activite_to_users_table.php`

Colonnes nullable + index nommés. `down()` drop index puis colonnes. Aucun backfill.

Compte fichiers migrations repo local : **404 → 405** (+1). Prod annoncé 272→273 :
même delta (+1) ; le total absolu dépend de l'état du dépôt déployé.

## OBJET 2 — Écriture

| Signal | Accroche | Méthode |
|--------|----------|---------|
| Connexion | Événement Laravel `Illuminate\Auth\Events\Login` (après `Auth::login` SSO dans `MicrosoftAuthController`) | `RecordUserLoginTimestamp` → `UserActivityTracker::touchConnexion` |
| Activité | Middleware web `TrackUserActivity` | `touchActivite` si auth et **pas** d'impersonation |

Fréquence activité : **N = 5 minutes** (`UserActivityTracker::ACTIVITE_THROTTLE_MINUTES`).
Justification : une navigation = plusieurs requêtes ; 5 min conserve une fraîcheur
utile pour l'adoption sans UPDATE à chaque clic. Écriture via
`User::query()->update([...])` (pas d'observers, pas de `updated_at`, pas d'audit
`AuditsFieldChanges` — le modèle `User` n'utilise pas ce trait).

Impersonation : `UserActivityTracker::$suppressLoginTouch` autour des `Auth::login`
de `ImpersonationService` ; middleware ignore l'activité pendant impersonation.

## OBJET 3 — Affichage

`Admin/Index` onglet Utilisateurs : compteurs total / 7j / 30j / 90j / jamais
connectés ; table complète triable (nom, e-mail, connexion, activité) avec libellés
relatifs (« il y a 3 jours »).

## OBJET 4 — RGPD

**Finalité** : pilotage de l'adoption de l'ERP et support (« qui utilise l'outil ? »),
pas la surveillance individuelle des salariés.

**Donnée conservée** : uniquement deux horodatages courants sur `users`
(`derniere_connexion_at`, `derniere_activite_at`) — la dernière valeur écrase la
précédente. Aucune table d'historique, aucune page consultée, aucune IP, aucun
journal de navigation nominatif lié à ces colonnes.

**Traces existantes ailleurs (non modifiées)** :
- `api_logs` : appels HTTP sortants (Graph, Intacct…) avec `user_id` éventuel —
  finalité technique / debug API, rétention via purge (#853).
- `impersonation_logs` : bascules DSI (déjà dédié support).
- Audits métier (`AuditsFieldChanges` sur fiches foncier, etc.) : changements de
  champs métier, pas de parcours de navigation.
- Logs applicatifs Laravel : peuvent contenir e-mail à la connexion M365 (existant).

## SYNTHÈSE

Mesure d'adoption réelle sans journaliser le parcours.

## DÉPLOIEMENT-TEST

OVH : `git pull` → `php artisan migrate --force` → `view:clear` → `journal:sync`.
Pas de npm sur le serveur.

## LEÇON

Ne pas confondre `users.updated_at` (profil / sync groupes) avec une connexion.
Séparer horodatage d'auth et d'activité ; throttler l'écriture d'activité ;
exclure l'impersonation pour ne pas fausser l'adoption.
