Ce document permet de reprendre le projet rapidement entre deux sessions Claude.
Outil Next.js 16 + TypeScript remplaçant les consoles M365 (Entra, Exchange, Admin Center). Auth SSO Microsoft (NextAuth v4 + Azure AD). Appels Microsoft Graph API. Audit log PostgreSQL. Échéance : 31/03/2026.
Voir CHANGELOG.md pour le détail des modifications.
| Phase | Statut | Notes |
|---|---|---|
| Cadrage | Terminé | |
| Documentation | Terminé | README, CLAUDE.md, Architecture.md, Reprise.md, CHANGELOG.md |
| Initialisation du projet | Terminé | Next.js 16, Prisma v7, shadcn/ui v4 |
| Infrastructure Docker | Terminé | 3 services : postgres, migrate, app |
| Authentification MSAL | Terminé | NextAuth v4 + JWT pur (sans PrismaAdapter) |
| Validation droits admin au login | Terminé | signIn callback → rôles AD via Graph, AccessDenied/RoleCheckFailed |
| Tableau de bord principal | Terminé | Stats cliquables, anomalies, SKUs, audit récent, précisions types + Actifs/Invités |
| Liste utilisateurs | Terminé | Filtres URL, colonnes persistées, tri, scrollbar horizontale |
| Panneau utilisateur (sheet) | Terminé | Groupes, licences, réinit MDP, désactiver/activer, rôles AD, absence |
| Réinitialisation MDP | Terminé | Dialog + API route + audit |
| Gestion groupes | Terminé | Liste avec filtres URL, tri, création de groupe |
| Gestion membres/owners | Terminé | Page detail : liste unifiée membre+owner, ajout avec rôle, tri |
| Gestion licences | Terminé | Cartes SKU + panneau bénéficiaires avec ajout/retrait |
| Audit log | Terminé | Page historique + PostgreSQL, tri, nouveaux labels d'action |
| Interface responsive | Terminé | Sidebar collapsible sur mobile, DashboardShell |
| Accessibilité visuelle | Terminé | 6 modes (monochrome, contraste, daltonisme), localStorage |
| Administration | Terminé | Paramètres locaux, contrôle actions sensibles, mots-clés types, export/import JSON |
| Export CSV connexions | Terminé | 50 entrées + bouton export dans fiche user |
| Noms produits licences | Terminé | skuPartNumber retiré des cartes SKU, EMS mappés |
| Accessibilité contraste | Terminé | CSS variables overrides + règles !important ciblées sur main |
| Export CSV historique | Terminé | Bouton dans onglet Historique |
| Rétention historique | Terminé | Administration → 30/60/90/180/365/illimité |
| Noms licences officiels | Terminé | 609 entrées depuis référence Microsoft officielle |
| Propriétaires groupes | Terminé | Sheet glissant, tri alpha, notice DL (limitation Graph API) |
| Audit paramètres admin | Terminé | POST /api/audit, ADMIN_SETTINGS_UPDATE journalisé |
| Pont Exchange — socle | Terminé | Sidecar exo-bridge (pwsh + Pode, app-only cert), /health + /diag/dl validés |
| Pont Exchange — membres DL | Terminé | Add/Remove via bridge, garde isExchangeAdmin, audit DL_MEMBER_ADD/REMOVE |
| Pont Exchange — owners DL + création DL | Terminé | ManagedBy (lecture+écriture), New-DistributionGroup, audit DL_OWNER_ADD/REMOVE, DL_CREATE |
| Pont Exchange — boîtes partagées | Terminé | Page dédiée, création New-Mailbox -Shared, délégations FullAccess/SendAs/SendOnBehalf, audit SHARED_MAILBOX_CREATE, MAILBOX_PERMISSION_ADD/REMOVE |
| Écran Accès conditionnel & connexions à risque | Terminé | Stratégies CA (Policy.Read.All) + détections Identity Protection (IdentityRiskEvent.Read.All, licence P2), best-effort |
| Pagination d'affichage | Terminé | Hook usePagination + composant Pagination, écrans Utilisateurs/Groupes/Accès conditionnel — recherche/tri/sélection/export restent sur tout le jeu filtré |
| Menu utilisateur (sidebar) | Terminé | Administration, Accessibilité, Thème, Accent, Déconnexion regroupés dans un menu déroulant (clic sur le nom/email) |
| Écran Journaux de connexion | Terminé | Analyse /auditLogs/signIns (24h/7j) : succès/échec, timeline, top apps/pays/IP, MFA, auth legacy — plafonné à 2000 événements, AuditLog.Read.All |
| Écran Postes de travail | Terminé | Vue unifiée Entra/Intune/Autopilot (corrélation deviceId + n° série), « Supprimer partout » (audit DEVICE_DELETE, irréversible), badge propriétaire désactivé, tri par colonne, surbrillance doublons de nom — permissions Device.ReadWrite.All, DeviceManagementManagedDevices.ReadWrite.All, DeviceManagementServiceConfig.ReadWrite.All |
| Écran Rapports | Terminé | Générateur d'exports Excel (consolidé + 1 feuille/entité) : membres DL, membres groupes, groupes par utilisateur, propriétaires groupes/DL, utilisateurs & licences. Routes /api/reports/{members,owners,user-groups}, helper listGroupMembersDetailed. Lecture seule, aucune nouvelle permission |
| Rollback UI | À faire | payloadBefore présent, bouton UI manquant |
- Prisma v7 : connexion via
prisma.config.ts+ adaptateurPrismaPg. Pas d'urldansschema.prisma. - shadcn/ui v4 : base
@base-ui/react.ButtonsansasChild. Links wrappés avec<Link>natif. - Next.js 16 :
paramsest unePromise<{...}>dans les routes dynamiques —await paramsobligatoire. - Toast : composant supprimé du registry shadcn v4, remplacé par Sonner + hook
src/hooks/use-toast.ts. - JWT pur :
PrismaAdapterretiré — boucle auth infinie causée par conflit DB sessions + stratégie JWT. - listUsers : filtre
userType eq 'Member'retiré — retourne tout le répertoire. Filtrage côté client. - ConsistencyLevel : header
eventual+$count=truerequis sur/userspour éviter "Sorting not supported". - prisma db push : utilisé à la place de
migrate deploy(pas de fichiers de migration générés).
src/
app/
dashboard/page.tsx # Stats + SKUs + audit récent, précisions types comptes
auth/error/page.tsx # Page erreur auth (AccessDenied, RoleCheckFailed)
api/
users/route.ts # GET tous comptes
users/[id]/route.ts # PATCH accountEnabled (désactiver/réactiver)
users/[id]/groups/route.ts # GET groupes d'un user
users/[id]/mailbox-settings/route.ts# GET/PATCH absence mail (OOO)
users/[id]/teams-presence/route.ts # POST statut Teams
users/[id]/roles/route.ts # GET/POST rôles AD d'un user
roles/route.ts # GET tous les rôles AD du tenant
security/
conditional-access-policies/route.ts # GET stratégies CA (Policy.Read.All)
risky-sign-ins/route.ts # GET détections Identity Protection (IdentityRiskEvent.Read.All, licence P2)
sign-ins/route.ts # GET analyse journaux de connexion (AuditLog.Read.All, plafonné à 2000 events)
groups/route.ts # GET liste + POST création
groups/[id]/members/route.ts
groups/[id]/owners/route.ts
licenses/[userId]/route.ts
audit/route.ts
dashboard/
users/page.tsx # Filtres type compte, tri colonnes
groups/page.tsx # Tri colonnes, bouton créer groupe
groups/[id]/page.tsx # Owners + membres fusionnés, tri
licenses/page.tsx
audit/page.tsx # Tri, labels actions v1.2.0
admin/page.tsx # Paramètres locaux
conditional-access/page.tsx # Onglets stratégies CA / connexions à risque
sign-in-logs/page.tsx # Analyse journaux de connexion (stats, timeline, top N, tableau)
components/
users/
user-groups-sheet.tsx # + désactiver/activer, onglet Rôles, onglet Absence
reset-password-dialog.tsx
groups/
add-member-dialog.tsx
create-group-dialog.tsx
services/exchange/ # Pont Exchange Online (sidecar) — non couvert par Graph
client.ts # bridgeFetch (X-Bridge-Secret, EXO_BRIDGE_URL)
distribution-groups.ts # membres + owners + création DL
shared-mailboxes.ts # boîtes partagées : liste, création, délégations
app/dashboard/mailboxes/page.tsx # Liste boîtes partagées + création + délégations
app/api/mailboxes/ # GET/POST liste+création, [id]/permissions GET/POST
components/mailboxes/ # create-shared-mailbox, mailbox-delegations-sheet, add-delegation
services/graph/
users.ts # + updateUserEnabled, getMailboxSettings, updateMailboxSettings, setTeamsStatusMessage
groups.ts # + isExchangeManagedGroup
licenses.ts
roles.ts # listDirectoryRoles, listUserRoles, assignRole, removeRole
security.ts # listConditionalAccessPolicies, listRiskyDetections
signins.ts # listTenantSignIns (plafonné), computeSignInStats
lib/
account-types.ts # detectAccountType, ACCOUNT_TYPE_CONFIG
license-names.ts
auth.ts # + signIn callback rôles AD, scopes Policy.Read.All / IdentityRiskEvent.Read.All
exchange-guard.ts # isExchangeAdmin — garde du canal app-only
admin-settings.ts # + showDisableUser, showUserRoles
use-sort.ts # Hook générique tri colonnes
use-pagination.ts # Hook générique pagination d'affichage
components/ui/
sortable-head.tsx # Composant en-tête de colonne triable
pagination.tsx # Composant pagination (page/taille de page)
services/audit.ts # + ACCOUNT_DISABLE/ENABLE, ROLE_ASSIGN/REMOVE, OOO_UPDATE, TEAMS_STATUS_UPDATE
- Rollback UI — ajouter bouton "Annuler" sur les lignes d'audit rollbackables (membres, licences)
- Gestion erreurs Graph — affichage lisible des erreurs 403 / throttling Microsoft
- Types de compte améliorés — utiliser
/places/microsoft.graph.roomet/places/microsoft.graph.equipmentpour détecter salles/équipements de façon fiable - Tests — API routes avec MSW pour mocker Graph API
- Admin SSO — déplacer la config Azure AD dans l'onglet Administration
- Administrateur local — compte sans accès Graph, uniquement gestion de l'application
# Développement local
docker compose up -d postgres
npx prisma db push
npm run dev
# Build et déploiement
docker compose up -d --build
# Logs
docker compose logs -f app
# Vérification TypeScript
npx tsc --noEmit- Hébergement cible : on-premise Docker. Accès par domaine HTTPS via Caddy (
tls internal) — voir Deploiement-domaine.md. Reste à trancher : domaine définitif + distribution de la CA interne (GPO) ou bascule DNS-01 pour des certificats publiquement reconnus. - Pont Exchange Online (DL, groupes mail-enabled, boîtes partagées) : cadré dans ADR-001-pont-exchange.md. Décision : sidecar PowerShell Docker on-premise, livraison par étapes (DL membres en premier). En attente du provisionnement tenant (app reg + certificat + rôle Exchange Admin).
Pagination côté serveur pour les tenants de très grande taille (> 999 utilisateurs) ?→ l'API gérait déjà la boucle@odata.nextLink(graphFetchAll) ; ajout d'une pagination d'affichage côté client (v1.28.0) pour le rendu. Une vraie pagination serveur (page/curseur sur l'API + recherche/tri serveur) resterait à évaluer si le rendu redevenait un problème sur un tenant réellement massif.