Merge pull request 'feat(help) : centre d'aide in-app /help avec 9 sections' (#4) from feat/in-app-help-doc into develop
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Reviewed-on: #4
This commit was merged in pull request #4.
This commit is contained in:
@@ -13,6 +13,14 @@
|
||||
<h1 class="text-lg font-bold tracking-tight">Lesstime</h1>
|
||||
</div>
|
||||
<div class="ml-auto flex items-center gap-4 text-xl text-white sm:gap-8">
|
||||
<MalioButtonIcon
|
||||
icon="mdi:help-circle-outline"
|
||||
aria-label="Centre d'aide"
|
||||
variant="ghost"
|
||||
icon-size="22"
|
||||
button-class="text-white/70 hover:bg-primary-600 hover:text-white"
|
||||
@click="navigateTo('/help')"
|
||||
/>
|
||||
<MalioButtonIcon
|
||||
:icon="ui.darkMode ? 'mdi:weather-sunny' : 'mdi:weather-night'"
|
||||
:aria-label="ui.darkMode ? 'Mode clair' : 'Mode sombre'"
|
||||
|
||||
27
frontend/content/help/01-getting-started.md
Normal file
27
frontend/content/help/01-getting-started.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Bienvenue dans Lesstime
|
||||
|
||||
Lesstime est un outil de **gestion de projets** qui combine 4 grandes capacités :
|
||||
|
||||
- 🗂️ **Gestion de projets** avec kanban personnalisable (workflows)
|
||||
- ✅ **Suivi de tâches** avec assignations, priorités, efforts, deadlines, tags
|
||||
- ⏱️ **Time tracking** intégré, lié aux projets et aux tâches
|
||||
- 🎫 **Portail client** pour que tes clients déposent leurs tickets
|
||||
|
||||
## Comprendre les rôles
|
||||
|
||||
| Rôle | Accès |
|
||||
|---|---|
|
||||
| **Admin** | Tout : projets, utilisateurs, intégrations, workflows |
|
||||
| **User** | Ses tâches, time tracking, projets auxquels il a accès |
|
||||
| **Client** | Portal dédié — tickets sur ses projets uniquement |
|
||||
|
||||
## Vues principales
|
||||
|
||||
- **Dashboard** : vue d'ensemble personnelle (KPIs, tâches du jour)
|
||||
- **Mes tâches** : kanban perso groupé par catégorie, toutes projets confondus
|
||||
- **Projets** : un kanban par projet, statuts du workflow associé
|
||||
- **Time tracking** : timer, time entries, vue mois
|
||||
- **Admin** : gestion globale (visible uniquement par les admins)
|
||||
- **Portal** : interface dédiée aux utilisateurs ROLE_CLIENT
|
||||
|
||||
> 💡 **Astuce** : utilise l'avatar en haut à droite pour accéder à ton profil et y générer un **token MCP** (cf. section *Token MCP & API*) pour piloter Lesstime depuis Claude / Cursor.
|
||||
58
frontend/content/help/02-projects-workflows.md
Normal file
58
frontend/content/help/02-projects-workflows.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Projets & Workflows
|
||||
|
||||
## Qu'est-ce qu'un projet ?
|
||||
|
||||
Un projet regroupe un ensemble de **tâches**, **time entries** et éventuellement **tickets client**. Il est défini par :
|
||||
|
||||
- Un **code court** (2-10 lettres majuscules, ex: `SIRH`, `CRM`) qui préfixe les numéros de tâches
|
||||
- Un **client** optionnel (ou interne si null)
|
||||
- Une **couleur** d'identification
|
||||
- Un **workflow** (obligatoire) qui définit ses colonnes kanban
|
||||
|
||||
## Qu'est-ce qu'un workflow ?
|
||||
|
||||
Un **workflow** est un *jeu de statuts kanban* réutilisable. Au lieu d'avoir une liste globale de statuts comme dans la plupart des outils, chaque projet a son propre kanban adapté à sa façon de travailler.
|
||||
|
||||
### Exemple
|
||||
|
||||
| Workflow | Statuts |
|
||||
|---|---|
|
||||
| **Standard** (par défaut) | À faire → En cours → Bloqué → En attente de validation → Terminé |
|
||||
| **DevKanban** | Backlog → Spec → In Dev → Review PR → QA → Done |
|
||||
| **Support** | Nouveau → Diagnostic → Résolu |
|
||||
|
||||
Tu peux créer autant de workflows que tu veux depuis **Admin → Workflows**.
|
||||
|
||||
## Les 5 catégories canoniques
|
||||
|
||||
Chaque statut, peu importe son workflow, appartient à **une catégorie canonique** parmi :
|
||||
|
||||
| Catégorie | Description |
|
||||
|---|---|
|
||||
| `todo` | À faire — pas encore commencé |
|
||||
| `in_progress` | En cours — quelqu'un bosse dessus |
|
||||
| `blocked` | Bloqué — attente d'une dépendance |
|
||||
| `review` | En validation — relecture, PR, QA |
|
||||
| `done` | Terminé — close |
|
||||
|
||||
> 🎯 **Pourquoi des catégories ?** Pour que la vue *Mes tâches* puisse regrouper des tâches venant de projets avec des workflows différents (ex: une tâche "In Dev" de DevKanban et "En cours" de Standard apparaissent dans la même colonne `in_progress`).
|
||||
|
||||
## Changer le workflow d'un projet
|
||||
|
||||
1. Ouvrir le projet → **Modifier le projet** (drawer)
|
||||
2. Section **Workflow** → cliquer sur **Changer de workflow**
|
||||
3. Sélectionner le workflow cible
|
||||
4. **Mapper chaque statut source vers un statut cible** (le mapping est pré-rempli automatiquement par catégorie)
|
||||
5. **Confirmer** — toutes les tâches migrent dans une seule transaction
|
||||
|
||||
### Règles du mapping
|
||||
|
||||
- ✅ Chaque statut actuellement utilisé par une tâche **doit** être mappé (sinon erreur 422)
|
||||
- ✅ Un statut peut être mappé vers `null` → la tâche passe en backlog (sans statut)
|
||||
- ❌ Tu ne peux pas mapper vers un statut qui n'appartient pas au workflow cible
|
||||
|
||||
## Supprimer un workflow
|
||||
|
||||
Tu peux supprimer un workflow uniquement s'il n'est **lié à aucun projet** (HTTP 409 sinon). Réassigne d'abord les projets vers un autre workflow.
|
||||
|
||||
> ⚠️ Le workflow **Standard** ne peut pas être supprimé tant qu'il reste le défaut (un seul workflow peut avoir `isDefault=true` à la fois, garanti par un listener Doctrine).
|
||||
60
frontend/content/help/03-my-tasks.md
Normal file
60
frontend/content/help/03-my-tasks.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Mes tâches & Dashboard
|
||||
|
||||
## Vue *Mes tâches*
|
||||
|
||||
Accessible via la sidebar, c'est ta vue **transverse** : toutes les tâches dont tu es l'**assigné** ou un **collaborateur**, peu importe le projet.
|
||||
|
||||
### Deux modes d'affichage
|
||||
|
||||
#### 1. Kanban (par défaut)
|
||||
|
||||
Regroupé par les **5 catégories canoniques** :
|
||||
|
||||
```
|
||||
À faire → En cours → Bloqué → En validation → Terminé
|
||||
```
|
||||
|
||||
Chaque card affiche :
|
||||
- Le **code projet + numéro** (ex: `SIRH-12`) coloré selon le projet
|
||||
- Un **badge statut** (utile quand des tâches de projets différents cohabitent)
|
||||
- Priorité, tags, deadline, icônes (sync calendrier, récurrence, collaborateurs)
|
||||
- L'**avatar de l'assigné** + bouton timer (▶ / ⏹)
|
||||
|
||||
> 💡 Le **drag-to-status** est intentionnellement désactivé dans *Mes tâches* — pour changer un statut, ouvre la tâche (la valeur dépend du workflow du projet, pas de la catégorie).
|
||||
|
||||
#### 2. Liste
|
||||
|
||||
Vue tableau triable, avec **bulk actions** :
|
||||
- Cocher plusieurs tâches → barre d'actions en haut
|
||||
- Changer statut (désactivé si tâches de **projets différents**), assigné, priorité, effort, groupe
|
||||
- Supprimer en lot
|
||||
|
||||
### Filtres disponibles
|
||||
|
||||
| Filtre | Notes |
|
||||
|---|---|
|
||||
| **Projet** | Restreint à un projet précis |
|
||||
| **Groupe** | Disponible uniquement si un projet est sélectionné |
|
||||
| **Tag** | Tags globaux |
|
||||
| **Priorité / Effort** | |
|
||||
| **Assigné** | Par défaut : toi-même |
|
||||
|
||||
### Tri (vue liste uniquement)
|
||||
|
||||
- Par **deadline** (les plus proches en premier)
|
||||
- Par **scheduled start** (planification calendrier)
|
||||
|
||||
## Vue *Backlog*
|
||||
|
||||
Sous le kanban, les tâches **sans statut** apparaissent dans la section *Backlog*. Pratique pour les idées non encore qualifiées.
|
||||
|
||||
## Dashboard
|
||||
|
||||
Le **dashboard** (page d'accueil après login) affiche :
|
||||
|
||||
- 📊 **KPIs personnels** : tâches en cours / à faire / en retard
|
||||
- 📈 **Charts** : répartition par statut, par priorité, time tracking cette semaine
|
||||
- 🔔 **Notifications** : assignations, commentaires (cf. cloche en topbar)
|
||||
- ⏱ **Timer actif** s'il y en a un
|
||||
|
||||
> 💡 Tu peux changer le filtre user du dashboard via le sélecteur en haut pour voir les KPIs d'un collègue (utile pour les leads).
|
||||
59
frontend/content/help/04-time-tracking.md
Normal file
59
frontend/content/help/04-time-tracking.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Time tracking
|
||||
|
||||
## Le timer
|
||||
|
||||
Le timer **flottant** est accessible depuis la sidebar ou directement depuis une tâche.
|
||||
|
||||
### Démarrer un timer
|
||||
|
||||
Trois façons :
|
||||
|
||||
1. **Depuis une TaskCard** : clique sur l'icône ▶ à droite de la card
|
||||
2. **Depuis le détail d'une tâche** : bouton *Démarrer le timer*
|
||||
3. **Manuellement** : depuis */time-tracking*, créer une time entry sans tâche
|
||||
|
||||
### Arrêter
|
||||
|
||||
- Clique sur ⏹ sur la card de la tâche en cours
|
||||
- Ou depuis la sidebar (icône timer pulsante en orange `#F18619`)
|
||||
|
||||
> 💡 Un seul timer actif à la fois. Démarrer un nouveau timer arrête automatiquement le précédent.
|
||||
|
||||
## Time entries
|
||||
|
||||
Chaque entrée a :
|
||||
|
||||
| Champ | Description |
|
||||
|---|---|
|
||||
| **Titre** | Description courte (ex: "Réunion daily") |
|
||||
| **Projet** | Obligatoire |
|
||||
| **Tâche** | Optionnel — lie l'entrée à une tâche précise |
|
||||
| **Tags** | Pour catégoriser (ex: "Backend", "Réunion") |
|
||||
| **Début / Fin** | Datetimes — la durée est calculée |
|
||||
| **User** | Qui a fait le travail |
|
||||
|
||||
### Vue *Time tracking*
|
||||
|
||||
Disponible en deux modes :
|
||||
|
||||
- **Vue semaine** : ligne par ligne, par jour
|
||||
- **Vue mois** : agrégation mensuelle, totaux par projet et par tag
|
||||
|
||||
### Filtres
|
||||
|
||||
- **Projet** (server-side)
|
||||
- **Tag** (server-side)
|
||||
- **User** (admin uniquement)
|
||||
- **Période** (date début / date fin)
|
||||
|
||||
## Édition
|
||||
|
||||
- Clique sur une time entry → drawer d'édition
|
||||
- Tu peux modifier projet, tâche, tags, dates a posteriori
|
||||
- La suppression est libre — pense à exporter avant si nécessaire
|
||||
|
||||
## Tags
|
||||
|
||||
Les tags sont **globaux** (partagés entre tous les projets, comme les statuts l'étaient avant les workflows). Définis depuis **Admin → Tags**.
|
||||
|
||||
> 📊 **Cas d'usage typique** : créer un tag par typologie d'activité (Dev, Réunion, Support, Veille) pour pouvoir agréger ton temps en fin de mois.
|
||||
62
frontend/content/help/05-tasks-detail.md
Normal file
62
frontend/content/help/05-tasks-detail.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Détail d'une tâche
|
||||
|
||||
## Champs principaux
|
||||
|
||||
| Champ | Notes |
|
||||
|---|---|
|
||||
| **Numéro** | Auto-incrémenté **par projet** (ex: `SIRH-1`, `SIRH-2`, `CRM-1`…) |
|
||||
| **Titre** | Obligatoire |
|
||||
| **Description** | Markdown supporté (preview disponible) |
|
||||
| **Statut** | Doit appartenir au workflow du projet (sinon erreur 422) |
|
||||
| **Priorité** | Basse / Moyenne / Haute — couleurs personnalisables |
|
||||
| **Effort** | S / M / L / XL / XXL — pour estimer la charge |
|
||||
| **Assigné** | Un seul user responsable |
|
||||
| **Collaborateurs** | Multiples — visibles via icône `mdi:account-group` |
|
||||
| **Groupe** | Optionnel — regroupe des tâches au sein d'un projet |
|
||||
| **Tags** | Globaux, plusieurs par tâche |
|
||||
| **Deadline** | Date — un badge coloré apparaît sur la card |
|
||||
| **Scheduled start / end** | Planification calendrier (sync optionnelle) |
|
||||
|
||||
## Récurrence
|
||||
|
||||
Une tâche peut être **récurrente** (icône 🔁 sur la card) :
|
||||
|
||||
- **Type** : quotidien, hebdomadaire, mensuel
|
||||
- **Intervalle** : tous les N jours/semaines/mois
|
||||
- **Jours de la semaine** (pour le mode hebdomadaire) : `monday`, `tuesday`, etc.
|
||||
|
||||
Chaque occurrence est gérée séparément ; cocher une tâche récurrente comme *Terminée* peut générer l'occurrence suivante selon le pattern.
|
||||
|
||||
## Sync calendrier
|
||||
|
||||
Si Zimbra est configuré (cf. Intégrations), tu peux activer **Sync calendrier** sur une tâche planifiée pour qu'elle apparaisse dans ton calendrier Zimbra (CalDav).
|
||||
|
||||
Icônes correspondantes :
|
||||
- 🟢 `mdi:calendar-check` → sync OK
|
||||
- 🔴 `mdi:alert-circle` → erreur de sync (passe sur l'icône pour le détail)
|
||||
|
||||
## Documents
|
||||
|
||||
Chaque tâche peut avoir des **documents attachés** (PDF, images, etc.) :
|
||||
|
||||
- Drag & drop dans la tâche pour uploader
|
||||
- Validation du **MIME type côté serveur** (pas seulement l'extension)
|
||||
- Téléchargement via lien dédié
|
||||
|
||||
## Liaison Gitea (si configuré)
|
||||
|
||||
Si le projet a un repo Gitea lié, tu peux :
|
||||
|
||||
- **Créer une branche** depuis la tâche : `feature/` `fix/` `refactor/` `hotfix/` `chore/` (5 types disponibles)
|
||||
- Convention de nommage : `<type>/<CODE>-<NUMBER>-<slug>` (ex: `feature/SIRH-12-add-login`)
|
||||
- **Voir les PRs** liées (état CI inclus)
|
||||
|
||||
## Liaison ticket client
|
||||
|
||||
Si la tâche découle d'un ticket client, l'icône 👤 (`heroicons:user-circle`) bleue apparaît avec le numéro du ticket (ex: `CT-001`).
|
||||
|
||||
## Commentaires & notifications
|
||||
|
||||
- Ajouter un commentaire notifie les watchers (assigné, collaborateurs)
|
||||
- Les @mentions notifient l'utilisateur cité
|
||||
- La cloche en topbar (`NotificationBell`) liste toutes les notifications non lues
|
||||
43
frontend/content/help/06-client-portal.md
Normal file
43
frontend/content/help/06-client-portal.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Portal client
|
||||
|
||||
> 🎫 Section dédiée aux utilisateurs avec le rôle **ROLE_CLIENT**.
|
||||
|
||||
## Accès
|
||||
|
||||
Les utilisateurs *client* sont **automatiquement redirigés vers `/portal`** après login. Ils ne voient pas les vues internes (projets, time tracking, admin).
|
||||
|
||||
## Ce que voit un client
|
||||
|
||||
- 📋 La liste de ses **projets autorisés** (définis par l'admin dans le user)
|
||||
- 🎫 Sur chaque projet, la liste de ses **tickets** (ses créations uniquement)
|
||||
- ➕ Le bouton **Nouveau ticket** sur chaque projet
|
||||
|
||||
## Soumettre un ticket
|
||||
|
||||
Depuis `/portal/projects/<id>/new-ticket` :
|
||||
|
||||
| Champ | Description |
|
||||
|---|---|
|
||||
| **Type** | `bug` / `improvement` / `other` |
|
||||
| **Titre** | Court et descriptif |
|
||||
| **Description** | Détails — markdown supporté |
|
||||
| **URL** | Optionnel — page où le problème se manifeste |
|
||||
|
||||
Le ticket est automatiquement numéroté **par projet** (ex: `CT-001`).
|
||||
|
||||
## Statuts d'un ticket
|
||||
|
||||
| Statut | Visible côté client | Signification |
|
||||
|---|---|---|
|
||||
| `new` | Oui | Reçu, pas encore traité |
|
||||
| `in_progress` | Oui | Une tâche interne y est liée |
|
||||
| `done` | Oui | Résolu et clôturé |
|
||||
| `rejected` | Oui | Non retenu (avec commentaire explicatif) |
|
||||
|
||||
Le `statusComment` est visible par le client quand fourni.
|
||||
|
||||
## Côté équipe interne
|
||||
|
||||
- Les tickets apparaissent dans **Admin → Tickets client**
|
||||
- On peut **transformer un ticket en tâche** (la tâche garde une référence au ticket — icône 👤 bleue sur la card)
|
||||
- Le client voit l'avancement passer en `in_progress` automatiquement quand une tâche est liée
|
||||
66
frontend/content/help/07-admin.md
Normal file
66
frontend/content/help/07-admin.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Administration
|
||||
|
||||
> 🛡️ Section visible uniquement par les utilisateurs **ROLE_ADMIN**.
|
||||
|
||||
L'admin (`/admin`) est divisé en plusieurs onglets, chacun gérant une ressource globale ou une intégration.
|
||||
|
||||
## Onglet *Clients*
|
||||
|
||||
- Liste des clients (entreprise / organisation)
|
||||
- Champs : nom, email, téléphone, adresse
|
||||
- Lier un client à des projets
|
||||
|
||||
## Onglet *Workflows*
|
||||
|
||||
⭐ **Nouveau** — remplace l'ancien onglet *Statuts*.
|
||||
|
||||
- Lister les workflows existants
|
||||
- **Créer un workflow** : nom, isDefault (un seul à la fois), liste de statuts éditables inline
|
||||
- Chaque statut : libellé, couleur, position, **catégorie** (5 valeurs canoniques), isFinal
|
||||
- **Éditer** un workflow modifie les statuts (sync intelligent : create / update / delete par diff)
|
||||
|
||||
> ⚠️ Supprimer un workflow lié à un projet renvoie une erreur **409**. Réassigne d'abord les projets.
|
||||
|
||||
## Onglet *Efforts*
|
||||
|
||||
- Tailles d'effort (S, M, L, XL, XXL)
|
||||
- Globales (partagées entre tous les projets)
|
||||
|
||||
## Onglet *Priorités*
|
||||
|
||||
- Niveaux de priorité (Basse, Moyenne, Haute) + couleur
|
||||
- Une priorité "Haute" affiche un drapeau rouge `mdi:flag-variant` sur la card
|
||||
|
||||
## Onglet *Tags*
|
||||
|
||||
- Tags globaux (tâches **et** time entries)
|
||||
- Couleur personnalisable
|
||||
- Pas de hiérarchie (flat list)
|
||||
|
||||
## Onglet *Utilisateurs*
|
||||
|
||||
- Créer / éditer / désactiver
|
||||
- Rôles : `ROLE_ADMIN`, `ROLE_USER`, `ROLE_CLIENT`
|
||||
- **ROLE_CLIENT** : associer un *client* et une liste de *projets autorisés*
|
||||
- Reset password depuis l'admin
|
||||
|
||||
> 🔐 Un user *admin+client* (les deux rôles) **n'est pas bloqué** par le middleware portal — le check est sur `ROLE_CLIENT && !ROLE_ADMIN`.
|
||||
|
||||
## Onglet *Gitea*
|
||||
|
||||
- URL serveur + token API
|
||||
- Lier un projet à un repo : `giteaOwner` + `giteaRepo`
|
||||
- Active les fonctionnalités branches / PRs sur les tâches
|
||||
|
||||
## Onglet *BookStack*
|
||||
|
||||
- URL + token API
|
||||
- Lier un projet à un **shelf** BookStack (`bookstackShelfId`)
|
||||
- Les tâches peuvent être liées à des pages BookStack (cf. `TaskBookStackLink`)
|
||||
|
||||
## Onglet *Zimbra*
|
||||
|
||||
- URL serveur + credentials (chiffrés via libsodium)
|
||||
- Configure le calendrier CalDav par défaut
|
||||
- Test de connexion intégré
|
||||
- Active la **sync calendrier** sur les tâches planifiées
|
||||
66
frontend/content/help/08-integrations.md
Normal file
66
frontend/content/help/08-integrations.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Intégrations
|
||||
|
||||
Lesstime s'intègre avec **3 outils externes** pour fluidifier le workflow dev.
|
||||
|
||||
## 🌳 Gitea
|
||||
|
||||
Lesstime parle à un serveur Gitea pour automatiser les conventions de branches et suivre les PRs.
|
||||
|
||||
### Configuration
|
||||
|
||||
1. **Admin → Gitea** : URL serveur + token API
|
||||
2. Sur un projet : définir `giteaOwner` (org/user) et `giteaRepo` (nom du repo)
|
||||
|
||||
### Utilisation
|
||||
|
||||
Sur une tâche, le panneau Gitea propose :
|
||||
|
||||
- **Créer une branche** : choisir un type (`feature` / `fix` / `refactor` / `hotfix` / `chore`)
|
||||
- La branche est nommée automatiquement : `<type>/<PROJECT_CODE>-<NUMBER>-<slug-du-titre>`
|
||||
- **Lister les PRs liées** : par convention, toute PR qui contient `<PROJECT_CODE>-<NUMBER>` dans son nom ou sa description est reliée
|
||||
- **État CI** : ✅ ou ❌ affiché si le repo a des Actions/Workflows configurées
|
||||
|
||||
> 💡 La convention `<PROJECT_CODE>-<NUMBER>` permet à Gitea et Lesstime de se synchroniser **sans webhook** — juste par parsing des noms.
|
||||
|
||||
## 📚 BookStack
|
||||
|
||||
Lien tâche → documentation.
|
||||
|
||||
### Configuration
|
||||
|
||||
1. **Admin → BookStack** : URL + token (token ID + token secret, chiffrés via libsodium)
|
||||
2. Sur un projet : définir `bookstackShelfId` + `bookstackShelfName`
|
||||
|
||||
### Utilisation
|
||||
|
||||
- Depuis une tâche : bouton **Lier à une page BookStack**
|
||||
- Sélectionner la page dans le shelf du projet
|
||||
- Le lien est bidirectionnel (BookStack peut afficher les tâches liées)
|
||||
|
||||
## 📅 Zimbra (CalDav)
|
||||
|
||||
Sync calendrier pour les tâches planifiées.
|
||||
|
||||
### Configuration
|
||||
|
||||
1. **Admin → Zimbra** :
|
||||
- URL serveur (ex: `https://mail.ovh.com`)
|
||||
- Username (ex: `lesstime@ovh.fr`)
|
||||
- Password (chiffré côté serveur)
|
||||
- Calendar path (ex: `/dav/lesstime@ovh.fr/Calendar/`)
|
||||
- **Test de connexion** intégré
|
||||
2. Active la config (toggle `enabled`)
|
||||
|
||||
### Utilisation
|
||||
|
||||
Sur une tâche avec **scheduled start + end** :
|
||||
|
||||
1. Cocher **Sync calendrier**
|
||||
2. Au save, Lesstime crée/met à jour l'événement CalDav
|
||||
3. L'icône `mdi:calendar-check` (verte) apparaît sur la card si succès
|
||||
4. L'icône `mdi:alert-circle` (rouge) apparaît si erreur — passe dessus pour voir le détail
|
||||
|
||||
### Limites
|
||||
|
||||
- **Pas de retour Zimbra → Lesstime** : si tu modifies l'événement dans Zimbra, Lesstime ne le voit pas
|
||||
- **Récurrences** : les patterns RRULE basiques sont supportés (daily, weekly avec jours, monthly)
|
||||
97
frontend/content/help/09-mcp-api.md
Normal file
97
frontend/content/help/09-mcp-api.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Token MCP & API
|
||||
|
||||
Lesstime expose un serveur **MCP** (Model Context Protocol) qui permet à un assistant IA (Claude, Cursor, etc.) de piloter ton instance Lesstime — créer des tâches, lire des projets, démarrer un timer, etc.
|
||||
|
||||
## Générer ton token
|
||||
|
||||
1. Va sur **Profil** (avatar → Profil)
|
||||
2. Section **Token MCP** → **Générer un token**
|
||||
3. **Copie le token immédiatement** — il ne sera plus affiché ensuite
|
||||
|
||||
> 🔐 **Sécurité** : Le token donne accès à toutes les actions de ton compte. Ne le partage jamais. Tu peux le régénérer à tout moment (l'ancien sera révoqué).
|
||||
|
||||
## Configurer Claude Code
|
||||
|
||||
Dans `.mcp.json` (à la racine de ton projet) :
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"lesstime": {
|
||||
"type": "http",
|
||||
"url": "https://ton-instance-lesstime/_mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer TON_TOKEN_ICI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Pour une instance locale :
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"lesstime-local": {
|
||||
"command": "docker",
|
||||
"args": ["exec", "-i", "php-lesstime-fpm", "php", "bin/console", "mcp:server"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Tools disponibles (27 au total)
|
||||
|
||||
### Projets
|
||||
|
||||
- `list-projects`, `get-project`, `create-project`, `update-project`
|
||||
|
||||
### Tâches
|
||||
|
||||
- `list-tasks` (avec filtres : projet, assigné, statut, archived…)
|
||||
- `get-task`, `create-task`, `update-task`, `delete-task`
|
||||
|
||||
### Métadonnées
|
||||
|
||||
- `list-statuses` (param **`projectId`** optionnel — sans : tous les statuts ; avec : statuts du workflow du projet)
|
||||
- `list-priorities`, `list-efforts`, `list-tags`
|
||||
|
||||
### Workflows ⭐ Nouveau
|
||||
|
||||
- `list-workflows` — liste tous les workflows avec leurs statuts groupés
|
||||
- `switch-project-workflow` (ROLE_ADMIN) — change le workflow d'un projet avec mapping
|
||||
|
||||
### Time tracking
|
||||
|
||||
- `list-time-entries`, `create-time-entry`, `update-time-entry`, `delete-time-entry`
|
||||
|
||||
### Récurrence
|
||||
|
||||
- `create-task-recurrence`, `update-task-recurrence`, `delete-task-recurrence`
|
||||
|
||||
### Groupes / Users / Clients
|
||||
|
||||
- `list-groups`, `create-group`, `update-group`
|
||||
- `list-users`, `list-clients`
|
||||
|
||||
## Règles importantes
|
||||
|
||||
> ⚠️ **Statut hors workflow rejeté** : si tu appelles `create-task` ou `update-task` avec un `status` qui n'appartient pas au workflow du projet, l'appel est rejeté avec **422 Validation error**. Utilise `list-statuses(projectId)` pour découvrir les statuts valides du projet.
|
||||
|
||||
## Exemples de prompts
|
||||
|
||||
```
|
||||
"Crée une tâche dans Lesstime sur le projet SIRH avec le titre
|
||||
'Ajouter l'export PDF' et la priorité Haute, assignée à alice"
|
||||
```
|
||||
|
||||
```
|
||||
"Liste mes tâches en cours dans le projet CRM"
|
||||
```
|
||||
|
||||
```
|
||||
"Démarre un timer sur la tâche SIRH-12 avec le tag Backend"
|
||||
```
|
||||
|
||||
L'agent appelle les bons tools tout seul si la description est claire.
|
||||
168
frontend/pages/help.vue
Normal file
168
frontend/pages/help.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<script setup lang="ts">
|
||||
import { marked } from 'marked'
|
||||
|
||||
useHead({ title: 'Aide' })
|
||||
|
||||
type Section = {
|
||||
id: string
|
||||
title: string
|
||||
icon: string
|
||||
accent: string
|
||||
roles: ('admin' | 'user' | 'client')[]
|
||||
content: string
|
||||
}
|
||||
|
||||
const rawModules = import.meta.glob('~/content/help/*.md', { eager: true, query: '?raw', import: 'default' }) as Record<string, string>
|
||||
|
||||
const META: Record<string, { title: string, icon: string, accent: string, roles: ('admin' | 'user' | 'client')[] }> = {
|
||||
'01-getting-started': { title: 'Bienvenue', icon: 'mdi:hand-wave', accent: 'from-amber-400 to-rose-500', roles: ['admin', 'user', 'client'] },
|
||||
'02-projects-workflows': { title: 'Projets & Workflows', icon: 'mdi:view-column-outline', accent: 'from-indigo-500 to-fuchsia-500', roles: ['admin', 'user'] },
|
||||
'03-my-tasks': { title: 'Mes tâches', icon: 'mdi:checkbox-marked-circle-outline', accent: 'from-sky-500 to-cyan-500', roles: ['admin', 'user'] },
|
||||
'04-time-tracking': { title: 'Time tracking', icon: 'mdi:timer-outline', accent: 'from-emerald-500 to-teal-500', roles: ['admin', 'user'] },
|
||||
'05-tasks-detail': { title: 'Tâches en détail', icon: 'mdi:file-document-edit-outline', accent: 'from-violet-500 to-purple-600', roles: ['admin', 'user'] },
|
||||
'06-client-portal': { title: 'Portal client', icon: 'mdi:account-tie-outline', accent: 'from-orange-500 to-amber-500', roles: ['admin', 'client'] },
|
||||
'07-admin': { title: 'Administration', icon: 'mdi:shield-crown-outline', accent: 'from-rose-500 to-pink-600', roles: ['admin'] },
|
||||
'08-integrations': { title: 'Intégrations', icon: 'mdi:puzzle-outline', accent: 'from-blue-500 to-indigo-500', roles: ['admin', 'user'] },
|
||||
'09-mcp-api': { title: 'Token MCP & API', icon: 'mdi:robot-outline', accent: 'from-slate-700 to-slate-900', roles: ['admin', 'user'] },
|
||||
}
|
||||
|
||||
const sections = computed<Section[]>(() => {
|
||||
return Object.entries(rawModules).map(([path, raw]) => {
|
||||
const id = path.split('/').pop()!.replace(/\.md$/, '')
|
||||
const meta = META[id] ?? { title: id, icon: 'mdi:file-document-outline', accent: 'from-neutral-500 to-neutral-700', roles: ['admin', 'user', 'client'] as ('admin' | 'user' | 'client')[] }
|
||||
return { id, ...meta, content: raw }
|
||||
}).sort((a, b) => a.id.localeCompare(b.id))
|
||||
})
|
||||
|
||||
const auth = useAuthStore()
|
||||
|
||||
const userRole = computed<'admin' | 'user' | 'client'>(() => {
|
||||
const roles = auth.user?.roles ?? []
|
||||
if (roles.includes('ROLE_ADMIN')) return 'admin'
|
||||
if (roles.includes('ROLE_CLIENT')) return 'client'
|
||||
return 'user'
|
||||
})
|
||||
|
||||
const visibleSections = computed(() =>
|
||||
sections.value.filter(s => s.roles.includes(userRole.value)),
|
||||
)
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const activeId = ref(visibleSections.value[0]?.id ?? '')
|
||||
|
||||
onMounted(() => {
|
||||
const hash = (route.query.section as string) ?? route.hash.replace('#', '')
|
||||
if (hash && visibleSections.value.some(s => s.id === hash)) {
|
||||
activeId.value = hash
|
||||
}
|
||||
})
|
||||
|
||||
watch(activeId, (id) => {
|
||||
router.replace({ query: { ...route.query, section: id } })
|
||||
})
|
||||
|
||||
const activeSection = computed(() => visibleSections.value.find(s => s.id === activeId.value) ?? visibleSections.value[0])
|
||||
|
||||
const renderedHtml = computed(() => {
|
||||
if (!activeSection.value) return ''
|
||||
return marked.parse(activeSection.value.content, { async: false }) as string
|
||||
})
|
||||
|
||||
const prevSection = computed(() => {
|
||||
const idx = visibleSections.value.findIndex(s => s.id === activeId.value)
|
||||
return idx > 0 ? visibleSections.value[idx - 1] : null
|
||||
})
|
||||
|
||||
const nextSection = computed(() => {
|
||||
const idx = visibleSections.value.findIndex(s => s.id === activeId.value)
|
||||
return idx >= 0 && idx < visibleSections.value.length - 1 ? visibleSections.value[idx + 1] : null
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex min-h-[calc(100vh-60px)] flex-col lg:flex-row">
|
||||
<!-- Sidebar -->
|
||||
<aside class="shrink-0 border-b border-neutral-200 bg-gradient-to-b from-white to-neutral-50 px-3 py-4 lg:w-72 lg:border-b-0 lg:border-r lg:px-4 lg:py-6">
|
||||
<div class="mb-4 flex items-center gap-2 lg:mb-6">
|
||||
<div class="flex h-9 w-9 items-center justify-center rounded-xl bg-gradient-to-br from-primary-500 to-primary-700 text-white shadow-sm">
|
||||
<Icon name="mdi:lifebuoy" size="20" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-base font-bold text-neutral-900">Centre d'aide</h1>
|
||||
<p class="text-xs text-neutral-500">Lesstime — Guide utilisateur</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="flex flex-row gap-1 overflow-x-auto pb-1 lg:flex-col lg:overflow-visible lg:pb-0">
|
||||
<button
|
||||
v-for="section in visibleSections"
|
||||
:key="section.id"
|
||||
type="button"
|
||||
class="group flex shrink-0 items-center gap-3 rounded-lg px-3 py-2.5 text-left text-sm font-medium transition-all lg:shrink"
|
||||
:class="activeId === section.id
|
||||
? 'bg-white text-neutral-900 shadow-sm ring-1 ring-neutral-200'
|
||||
: 'text-neutral-600 hover:bg-white hover:text-neutral-900'"
|
||||
@click="activeId = section.id"
|
||||
>
|
||||
<span
|
||||
class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br text-white shadow-sm"
|
||||
:class="section.accent"
|
||||
>
|
||||
<Icon :name="section.icon" size="16" />
|
||||
</span>
|
||||
<span class="whitespace-nowrap lg:whitespace-normal">{{ section.title }}</span>
|
||||
</button>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- Content -->
|
||||
<main class="flex-1 px-4 py-6 sm:px-8 lg:px-12 lg:py-10">
|
||||
<div v-if="activeSection" class="mx-auto max-w-3xl">
|
||||
<!-- Hero header -->
|
||||
<div
|
||||
class="mb-8 overflow-hidden rounded-2xl bg-gradient-to-br p-6 text-white shadow-lg sm:p-8"
|
||||
:class="activeSection.accent"
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-white/20 backdrop-blur-sm">
|
||||
<Icon :name="activeSection.icon" size="28" />
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-white/80">Section</p>
|
||||
<h2 class="text-2xl font-bold tracking-tight sm:text-3xl">{{ activeSection.title }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Markdown content -->
|
||||
<article
|
||||
class="prose prose-neutral max-w-none prose-headings:font-bold prose-headings:tracking-tight prose-h1:hidden prose-h2:mt-10 prose-h2:border-b prose-h2:border-neutral-200 prose-h2:pb-2 prose-h3:text-neutral-800 prose-a:text-primary-600 prose-strong:text-neutral-900 prose-code:rounded prose-code:bg-neutral-100 prose-code:px-1.5 prose-code:py-0.5 prose-code:text-sm prose-code:font-medium prose-code:text-rose-600 prose-code:before:content-none prose-code:after:content-none prose-pre:rounded-xl prose-pre:bg-slate-900 prose-table:border prose-table:border-neutral-200 prose-th:bg-neutral-50 prose-th:px-3 prose-th:py-2 prose-td:px-3 prose-td:py-2 prose-blockquote:rounded-r-lg prose-blockquote:border-l-4 prose-blockquote:border-amber-400 prose-blockquote:bg-amber-50 prose-blockquote:px-4 prose-blockquote:py-2 prose-blockquote:not-italic prose-blockquote:text-amber-900"
|
||||
v-html="renderedHtml"
|
||||
/>
|
||||
|
||||
<!-- Footer nav -->
|
||||
<div class="mt-12 flex items-center justify-between border-t border-neutral-200 pt-6">
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center gap-2 rounded-lg px-3 py-2 text-sm text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-neutral-900 disabled:invisible"
|
||||
:disabled="!prevSection"
|
||||
@click="prevSection && (activeId = prevSection.id)"
|
||||
>
|
||||
<Icon name="mdi:arrow-left" size="18" />
|
||||
<span>{{ prevSection?.title ?? '' }}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center gap-2 rounded-lg px-3 py-2 text-sm text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-neutral-900 disabled:invisible"
|
||||
:disabled="!nextSection"
|
||||
@click="nextSection && (activeId = nextSection.id)"
|
||||
>
|
||||
<span>{{ nextSection?.title ?? '' }}</span>
|
||||
<Icon name="mdi:arrow-right" size="18" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user