Files
Lesstime/CLAUDE.md
THOLOT DECHENE Matthieu d7af8ee138
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Correctifs UI workflow — specs + implémentation (8 chantiers) (#6)
Suite à l'arrivée des workflows, correction des régressions UI et améliorations UX mail/modales (reviews Lucile Schnödt, Tristan Schnödtin).

**Specs & décisions :** `docs/superpowers/specs/2026-05-20-workflow-ui-fixes-design.md`
**Plan d'implémentation :** `docs/superpowers/plans/2026-05-21-workflow-ui-fixes.md`

Cette PR contient désormais **les specs ET l'implémentation complète**.

## Chantiers livrés

| # | Chantier | Détail |
|---|----------|--------|
| 2 | Sélecteur de statut filtré par workflow | `statusOptions` dérivé de `project.workflow.statuses`, statut courant conservé s'il est hors workflow |
| 1 | Drag & drop « Mes tâches » | handlers `@dragover/@drop` ; résolution par workflow/catégorie (0→refus, 1→PATCH, ≥2→popover `StatusPickerPopover`) |
| 4 | Couleurs | (a) migration Doctrine remettant les hex classiques sur le workflow Standard ; (b) entêtes kanban teintées via `STATUS_CATEGORY_COLOR` + contraste auto ; (c) couleur par défaut par catégorie dans `WorkflowDrawer` |
| 5 | Suppression du bouton « Lier un mail » | + retrait de `MailPickerModal` et i18n associée |
| 6 | Création de tâche depuis un mail | back : `assigneeId` + `statusId` (défaut = 1er statut du workflow), priorité retirée (TDD) ; front : `MailCreateTaskModal` sur `AppModal` + sélecteurs user/statut |
| 7 | Modale réutilisable | nouveau `components/ui/AppModal.vue` (footer sticky) ; footer de `TaskModal` sorti du form scrollable |
| 3 | Cartes responsive | badges en `flex-wrap` pleine taille (plus aucun débordement) |
| 8 | (dette) Sélecteur de catégorie en `MalioSelect` | la lib supporte les valeurs `string` ; note CLAUDE.md corrigée |

## Vérifications
- Build frontend OK ; PHPUnit **34 tests verts** (nouveau test fonctionnel TDD sur `create-task`).
- Vérif navigateur (Chrome MCP) sur **données prod importées en local** : #2, #3, #4, #5, #6, #7 confirmés.
- Revue de code finale : **APPROVED_WITH_NITS**.

## À noter
- ⚠️ **#1 (D&D)** : le drag & drop HTML5 natif n'est pas auto-testable → **test manuel requis**.
- 🗄️ **#4 (migration)** : `migrations/Version20260521094948.php` s'appliquera en **prod au prochain `make migration-migrate`**.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Matthieu <mtholot19@gmail.com>
Reviewed-on: #6
2026-05-21 08:48:31 +00:00

154 lines
9.5 KiB
Markdown

# Lesstime
Application de gestion de projet. Monorepo Symfony 8 (API Platform 4) + Nuxt 4.
> **WIP — Intégration Mail (branche `feat/mail-integration`)** : client mail OVH IMAP. Avant de toucher au mail, lire `docs/mail-integration.md` (section « Statut & reprise » = bugs déjà corrigés, points en suspens, commandes). Code : `src/Mail/`, `src/Service/MailSyncService.php`, `src/Controller/Mail/`, `frontend/{services,stores,components}/mail*`.
## Stack
- **Backend** : PHP 8.4, Symfony 8.0, API Platform 4, Doctrine ORM, PostgreSQL 16
- **Frontend** : Nuxt 4 (SSR off / SPA), Vue 3, Pinia, Tailwind CSS, @malio/layer-ui, nuxt-toast, @nuxtjs/i18n, @nuxt/icon
- **Auth** : JWT HTTP-only cookie (lexik/jwt-authentication-bundle), login à `/login_check`, cookie `BEARER`
- **Docker** : PHP-FPM + Node 24, Nginx (port 8082), PostgreSQL (port 5435)
## Structure
```
src/Entity/ # Entités Doctrine (User, Client, Project, Task, TaskStatus, TaskEffort, TaskPriority, TaskTag, TaskGroup, TimeEntry, GiteaConfiguration, ClientTicket, Notification, TaskDocument, BookStackConfiguration, TaskBookStackLink, TaskRecurrence, ZimbraConfiguration)
src/ApiResource/ # Ressources API Platform (si découplées des entités) (ZimbraSettings, ZimbraTestConnection)
src/Enum/ # PHP enums (RecurrenceType)
src/State/ # Providers et Processors API Platform (MeProvider, AppVersionProvider, ActiveTimeEntryProvider, UserPasswordHasherProcessor, TaskNumberProcessor, ClientTicket*Provider/Processor, NotificationProvider, Gitea*Provider, Gitea*Processor, ZimbraSettingsProvider/Processor, ZimbraTestConnectionProvider, TaskCalendarProcessor, RecurrenceHandler)
src/Service/ # Services métier (NotificationService, CalDavService, RecurrenceCalculator)
src/Controller/ # Controllers custom Symfony (NotificationUnreadCountController, MarkAllReadController, UserAvatarController, TaskDocumentDownloadController)
src/Mcp/Tool/ # MCP tools organisés par domaine (Project/, Task/, TaskMeta/, TimeEntry/, Reference/)
src/Security/ # Authenticators custom (ApiTokenAuthenticator pour MCP HTTP)
src/Command/ # Commandes console (GenerateApiTokenCommand)
src/Repository/ # Repositories Doctrine
src/DataFixtures/ # Fixtures
config/ # Config Symfony (security, api_platform, lexik_jwt, nelmio_cors, doctrine)
config/jwt/ # Clés JWT (private.pem, public.pem)
migrations/ # Migrations Doctrine
docs/plans/ # Plans d'implémentation
docs/superpowers/ # Plans et specs superpowers
frontend/ # App Nuxt 4
frontend/pages/ # Pages (index, login, my-tasks, profile, projects, projects/[id], projects/[id]/groups, projects/[id]/archives, time-tracking, admin, portal/, portal/projects/[id], portal/projects/[id]/new-ticket)
frontend/layouts/ # Layouts (default, portal)
frontend/components/ # Composants Vue organisés en sous-dossiers (ui/, client/, project/, task/, user/, admin/, time-tracking/, client-ticket/, notification/) — inclut admin/AdminZimbraTab
frontend/composables/# Composables (useApi, useAppVersion, useNotifications, useClientTicketHelpers, useAvatarService)
frontend/stores/ # Stores Pinia (auth, ui, timer)
frontend/services/ # Services API (auth, clients, gitea, projects, tasks, task-statuses, task-efforts, task-groups, task-priorities, task-tags, users, time-entries, client-tickets, notifications, task-documents, zimbra, task-recurrences)
frontend/services/dto/ # Types TypeScript
frontend/i18n/locales/ # Fichiers de traduction (langDir résolu depuis i18n/)
```
## Commandes
```bash
make start # Démarrer les containers
make stop # Arrêter les containers
make restart # Redémarrer les containers
make install # Install complet (composer, migrations, fixtures, build Nuxt)
make reset # Tout supprimer et réinstaller (supprime la BDD)
make dev-nuxt # Dev server Nuxt (hot reload, port 3002)
make shell # Shell dans le container PHP
make shell-root # Shell root dans le container PHP
make cache-clear # Vider le cache Symfony
make migration-migrate # Lancer les migrations
make fixtures # Charger les fixtures
make db-reset # Reset BDD + migrations + fixtures
make test # PHPUnit
make php-cs-fixer-allow-risky # Fix code style PHP
make logs-dev # Tail logs Symfony
```
## Conventions
### Commits
Format : `<type>(<scope optionnel>) : <message>` (espace avant et après `:`)
Types autorisés (minuscules) : `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`
Exemples : `feat : add login page`, `fix(auth) : prevent null token crash`
### Tags & Versioning
- La version de l'app est dans `config/version.yaml` (paramètre `app.version`)
- À chaque création de tag, **toujours** mettre à jour `config/version.yaml` avec la même version
- Faire un commit séparé de bump : `chore : bump version to v<X.Y.Z>`
- Puis créer le tag et pusher : `git tag v<X.Y.Z> && git push origin develop --tags`
### Backend
- Toujours `declare(strict_types=1)` en haut des fichiers PHP
- API Platform : utiliser ApiResource, Providers (`src/State/`), Processors — pas de controllers
- Routes API préfixées `/api` (via `config/routes/api_platform.yaml`)
- Le login (`/login_check`) est hors prefix `/api`, nginx réécrit `REQUEST_URI` vers `/login_check`
- PHP CS Fixer : règles Symfony + PSR-12 + strict types
- Rôles : `ROLE_ADMIN`, `ROLE_USER`, `ROLE_CLIENT` — hiérarchie dans `security.yaml`
- `User::getRoles()` n'ajoute PAS `ROLE_USER` si l'user a `ROLE_CLIENT` (isolation)
- PostgreSQL : `LIKE` sur colonne JSON ne marche pas → utiliser `roles::text LIKE` via native SQL
- Controllers custom sous `/api/` : ajouter `priority: 1` sur `#[Route]` pour éviter le conflit avec API Platform `{id}`
- Serialization : pour embarquer une relation (pas IRI), ajouter le groupe du parent aux propriétés de l'entité cible
- Upload fichiers : utiliser `$file->getMimeType()` (pas `getClientMimeType()`) pour valider côté serveur — nécessite `symfony/mime`
- Auth endpoints mixtes (ROLE_USER + ROLE_CLIENT) : utiliser `#[IsGranted('IS_AUTHENTICATED_FULLY')]` au lieu d'un rôle spécifique
### Frontend
- TypeScript strict
- Composable `useApi()` pour tous les appels API (gère cookies, erreurs, toasts, i18n)
- Stores Pinia : `useAuthStore` (auth), `useUiStore` (ui), `useTimerStore` (timer)
- Middleware global `auth.global.ts` protège les routes
- Traductions dans `frontend/i18n/locales/` (le module résout `langDir` depuis `i18n/`)
- 4 espaces d'indentation
- MalioSelect : options `{ label: string, value: string | number | null }` — supporte les valeurs `string` (donc les enums string comme `StatusCategory`), pas seulement `number`. Vérifié dans la source `@malio/layer-ui` (`Select.vue` : `modelValue: string | number | null`). L'option vide `null` n'est ajoutée que si `empty-option-label` est passé (ne pas le passer pour un champ requis)
- Portal client : pages sous `/portal/`, layout `portal.vue`, middleware redirige `ROLE_CLIENT` (sans `ROLE_ADMIN`) vers `/portal`
- Users admin+client : ne pas bloquer — vérifier `ROLE_CLIENT && !ROLE_ADMIN` pour les restrictions
### Composants UI
La librairie `@malio/layer-ui` fournit les composants de formulaire et d'action. La documentation complète des props, events et exemples d'utilisation se trouve dans `frontend/node_modules/@malio/layer-ui/COMPONENTS.md`. Toujours s'y référer avant d'utiliser un composant Malio.
### MCP Server
- 25 tools MCP exposant projets, tâches, métadonnées, time tracking, et récurrences
- Transport STDIO (local) : `docker exec -i php-lesstime-fpm php bin/console mcp:server`
- Transport HTTP (réseau) : `POST /_mcp` avec header `Authorization: Bearer <token>`
- Auth HTTP : `ApiTokenAuthenticator` vérifie le champ `apiToken` de l'entité `User`
- Générer un token : `php bin/console app:generate-api-token <username>`
- Config : `config/packages/mcp.yaml`, firewall dans `config/packages/security.yaml`
- Attribut `#[McpTool]` doit être sur la **classe** (pas la méthode `__invoke`) pour la discovery SDK
### Nginx
- `/_mcp` → Symfony (MCP HTTP transport)
- `/api/*` → Symfony (via try_files + index.php)
- `/api/login_check` → location exact match, fastcgi direct avec REQUEST_URI réécrit en `/login_check`
- `/` → SPA frontend (`frontend/dist/`)
## Docker
- Container PHP : `php-lesstime-fpm`
- Container Nginx : `nginx-lesstime`
- Container DB : PostgreSQL sur port **5435** (interne et externe)
- Config Docker : `infra/dev/.env.docker` (override local : `infra/dev/.env.docker.local`)
- Après modif nginx : `docker restart nginx-lesstime`
## Fixtures
- User admin : `admin` / `admin` (ROLE_ADMIN)
- Users internes : `alice` / `alice`, `bob` / `bob`, `charlie` / `charlie` (ROLE_USER)
- Users client : `client-liot` / `client` (ROLE_CLIENT, client LIOT → SIRH), `client-acme` / `client` (ROLE_CLIENT, client ACME → CRM)
- API token admin (dev) : `dev-mcp-token-for-testing-only-do-not-use-in-production`
- ZimbraConfiguration : serverUrl `https://mail.ovh.com`, username `lesstime@ovh.fr`, enabled false
- TaskRecurrence (hebdomadaire lun/mer/ven) attachée à la tâche "Réunion de suivi hebdomadaire" (SIRH)
## Delegation Codex
Pour les taches mecaniques (tests, boilerplate, renommages, refacto repetitif), delegue a Codex via le plugin `codex`. Garde Claude pour la reflexion, l'architecture et la verification.
- **Codex** = junior dev rapide et pas cher (executions mecaniques)
- **Claude** = senior dev qui verifie et reflechit (design, review, decisions)
C'est le meilleur ratio qualite/credits.