# Migration de la sidebar vers `MalioSidebar` (@malio/layer-ui)

**Date** : 2026-06-25
**Statut** : Design validé
**Scope** : Frontend (layout) + backend (config sidebar) + assets

## Contexte

La sidebar actuelle de Lesstime est un `<aside>` fait main dans
`frontend/app/layouts/default.vue`, qui itère sur les sections renvoyées par
`/api/sidebar` et rend chaque item via le composant maison `SidebarLink`. Le
timer et la version sont empilés en bas du `<aside>`, le toggle collapse et
l'overlay mobile sont gérés manuellement.

La librairie `@malio/layer-ui` (mise à jour) fournit désormais un composant
`MalioSidebar`. Le projet **Starseed** a déjà effectué cette migration sur une
architecture identique (`config/sidebar.php` → `SidebarProvider` → composable
`useSidebar` → layout). Cette spec applique la même migration à Lesstime, avec
trois spécificités Lesstime : footer (timer + version), re-catégorisation des
onglets, et plusieurs items contextuels rendus côté client.

On **ne modifie pas** la lib `@malio/layer-ui` (règle CLAUDE.md).

## Objectifs

1. Remplacer le `<aside>` maison par `<MalioSidebar>`.
2. Préserver le filtrage des permissions/rôles/modules **côté serveur**.
3. Re-catégoriser la navigation en 3 groupes : **Général / Outils / Administration**.
4. Mettre le timer et la version dans le **footer** du composant.
5. Reprendre le **logo Malio** de Starseed.

## Décisions validées

- **Catégorisation** : 3 groupes (option B).
- **Badge mail** : le compteur de non-lus devient un **suffixe sur le label**
  (`Messagerie (3)`), faute de slot badge/icône par item dans `MalioSidebar`.

## Contraintes du composant `MalioSidebar`

Source : `frontend/node_modules/@malio/layer-ui/app/components/malio/sidebar/Sidebar.vue`.

- **Props** : `sections` (requis), `modelValue` (v-model collapse, bool),
  `id`, `sidebarClass`, `toggleClass`.
- **Types** :
  - `SidebarItem = { label: string; to: string; exact?: boolean }`
  - `SidebarSection = { label?: string; icon?: string; items: SidebarItem[] }`
- **Slots** : `#logo`, `#logo-collapsed`, `#footer`, `#footer-collapsed`.
- **Events** : `update:modelValue(boolean)`.
- **Item** : pas d'icône par item ni de badge — uniquement l'icône de section.
  Route active = match exact ou par préfixe (`exact: true` pour exact strict).
- Largeurs fixes : 232px (déplié) / 72px (replié). Toggle interne.

### Conséquences (compromis assumés)

- Perte de l'**icône par item** (design malioUI = texte + icône de section).
  Starseed fonctionne ainsi.
- Le **badge mail** ne peut pas être une pastille → suffixe `(N)` dans le label.

## Architecture cible

Modèle **backend-driven** conservé (sécurité serveur intacte). Le frontend
mappe les sections renvoyées par `/api/sidebar` vers le format `MalioSidebar`
et **fusionne** les items contextuels (qui dépendent d'un état runtime non
connu du backend).

### 1. Backend — `config/sidebar.php`

Re-catégorisation en 3 sections (gates inchangés, juste réorganisés) :

```
GÉNÉRAL  (sidebar.general.section, icon mdi:view-dashboard-outline)
  Tableau de bord   /              —
  Mes tâches        /my-tasks      module project-management, perm tasks.view
  Projets           /projects      module project-management, perm projects.view
  Suivi de temps    /time-tracking module time-tracking,      perm entries.view

OUTILS   (sidebar.tools.section, icon mdi:tools)
  Messagerie        /mail          module mail
                    (filtré du rendu backend côté front, ré-injecté avec badge)

ADMINISTRATION (sidebar.admin.section, icon mdi:cog-outline, roles [ROLE_ADMIN])
  Absences équipe   /team-absences module absence
  Répertoire        /directory     module directory
  Rapports          /reporting     module reporting, perm reporting.view
  Administration    /admin         perm core.users.view
```

> `/mail` reste déclaré pour le gating module (`disabledRoutes`), mais est
> filtré des sections rendues et ré-injecté côté client avec son badge, comme
> aujourd'hui.

### 2. i18n — `frontend/i18n/locales/fr.json`

- Renommer `sidebar.general.section` : « Gestion de projet » → « Général ».
- Ajouter `sidebar.tools.section` : « Outils ».
- Conserver les clés d'items existantes. Items client : réutiliser les clés
  existantes quand elles existent (`sharedFiles.sidebar.title` pour Documents,
  `mail.sidebar.title`/`sidebar.general.mail` pour Messagerie) ; ajouter une
  clé pour « Mes absences » (aujourd'hui en dur) et pour les contextuels
  (Kanban/Groupes/Archives, aujourd'hui en dur) si on souhaite les traduire,
  sinon conserver les libellés en dur actuels.

### 3. Frontend — `frontend/app/layouts/default.vue`

Réécriture du template autour de `<MalioSidebar>` :

```vue
<MalioSidebar v-model="ui.sidebarCollapsed" :sections="mergedSections"
              :sidebar-class="ui.sidebarCollapsed ? '' : 'w-[232px]'">
  <template #logo>           <img src="/LOGO_MALIO.png" alt="Malio"/></template>
  <template #logo-collapsed> <img src="/LOGO_MALIO_COLLAPSED.png" alt="Malio"/></template>
  <template #footer>
    <SidebarTimer :collapsed="false" />
    <p class="font-bold">v {{ version }}</p>
  </template>
  <template #footer-collapsed>
    <SidebarTimer :collapsed="true" />
  </template>
</MalioSidebar>
```

**Computed `mergedSections`** : construit les sections finales dans l'ordre
canonique `[général, outils, administration]`.

Logique de fusion :
1. Partir des sections backend (déjà filtrées), mappées en
   `{ label: t(label), icon, items: items.filter(to !== '/mail').map({label: t, to}) }`.
2. Définir une table `clientItems` indexée par clé de section :
   - `sidebar.general.section` → (si `currentProjectId`) Kanban (`exact`),
     Groupes, Archives ; puis (si `isEmployee`) Mes absences.
   - `sidebar.tools.section` → (si `isMailVisible`) Messagerie avec label
     `Messagerie` + suffixe `(N)` quand `mailStore.globalUnreadCount > 0`
     (`99+` au-delà) ; puis (si `shareEnabled`) Documents.
3. Pour chaque section backend, **append** ses items client.
4. Si une clé de `clientItems` produit des items mais que la section
   correspondante n'est **pas** présente dans la réponse backend (ex. module
   mail off mais partage on → pas de section « Outils » côté backend), **créer**
   la section côté front (label + icône depuis une table locale).
5. **Supprimer** les sections finales sans items.
6. Trier selon l'ordre canonique des clés.

Le reste du `<script>` (timer title watchers, `refData`/`TimeEntryDrawer`,
polling mail, `ensureShareStatus`, `currentProjectId`, `isEmployee`,
`isMailVisible`, `shareEnabled`) est **conservé tel quel**.

### 4. Mobile

Starseed a **supprimé l'overlay mobile custom** et ne garde que
`watch(route) → ui.closeMobileSidebar()`. On s'aligne : suppression du markup
overlay (`ui.sidebarOpen`, `.sidebar-overlay`) si `MalioSidebar` gère le
responsive. **À vérifier à l'implémentation** : comportement mobile réel du
composant ; si l'ouverture mobile n'est pas couverte, adapter a minima sans
modifier la lib.

### 5. Assets — logo

Copier depuis Starseed vers `frontend/public/` :
- `LOGO_MALIO.png` (128×44)
- `LOGO_MALIO_COLLAPSED.png` (34×40)

Les anciens `/malio.png` et `/LOGO_CARRE.png` ne sont plus référencés par le
layout (les laisser ou les retirer si plus aucun usage — à vérifier).

## Composants / éléments réutilisés

- `SidebarTimer` (`components/ui/SidebarTimer.vue`) : inchangé, déjà piloté par
  `:collapsed`.
- `useAppVersion()` : inchangé.
- `useSidebar()` : inchangé.
- `usePermissions()` : inchangé (le filtrage permission reste backend ; les
  flags client `isEmployee`/`isMailVisible`/`shareEnabled` restent locaux).

## Éléments supprimés

- Le `<aside>` manuel et son markup (logo, nav, toggle, overlay) dans
  `default.vue`.
- L'usage de `SidebarLink` dans le layout (le composant peut rester s'il est
  utilisé ailleurs — à vérifier ; sinon suppression possible).

## Critères d'acceptation

1. La sidebar est rendue par `<MalioSidebar>`.
2. 3 groupes : Général, Outils, Administration (Administration visible
   uniquement pour `ROLE_ADMIN` / permissions, comme avant).
3. Toutes les permissions/rôles/modules sont respectés à l'identique (aucune
   régression de visibilité pour user/admin).
4. Items contextuels présents : Kanban/Groupes/Archives (dans un projet),
   Documents (partage activé), Mes absences (employé).
5. Messagerie affiche `(N)` quand il y a des non-lus.
6. Footer : timer fonctionnel + version (version masquée en replié).
7. Logo Malio de Starseed affiché (déplié + replié).
8. Collapse/expand et route active fonctionnent.
9. Pas de doublon `/mail`. Pas de section vide affichée.
10. Build Nuxt OK, pas d'erreur TS.

## Hors scope

- Refonte du `SiteSelector` (n'existe pas dans Lesstime).
- Modification de la lib `@malio/layer-ui`.
- Changement du modèle de permissions backend.
