128 Commits

Author SHA1 Message Date
gitea-actions 98e3990fa5 chore: bump version to v0.4.45
Auto Tag Develop / tag (push) Successful in 8s
Build & Push Docker Image / build (push) Successful in 3m27s
2026-06-26 14:21:43 +00:00
matthieu f221976573 Merge branch 'develop' into fix/user-soft-delete-orphan-references
Pull Request — Quality gate / Frontend (build) (pull_request) Successful in 41s
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m0s
2026-06-26 14:17:09 +00:00
Matthieu d8d755d4c5 fix(user) : archivage au lieu de suppression + réparation des références orphelines
Pull Request — Quality gate / Frontend (build) (pull_request) Successful in 39s
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m1s
Un user supprimé physiquement laissait des références orphelines (task.assignee,
time entries, notifications) car les FK vers "user" ont été créées NOT VALID lors
du refactor modular-monolith : elles n'ont jamais nettoyé les orphelins legacy. La
sérialisation API Platform d'une tâche embarquant un assignee inexistant levait une
EntityNotFoundException non rattrapable (HTTP 500 sur tout PATCH/GET de ces tickets).

- User::$archived (bool) + migration (soft delete)
- Delete de User -> UserArchiveProcessor : archive (archived=true, apiToken vidé)
  au lieu de supprimer, préservant l'intégrité référentielle
- ArchivedUserChecker : login bloqué pour un user archivé (firewalls login + api)
- ExcludeArchivedUserExtension : archivés exclus de GET /api/users (assignation),
  les références existantes restent sérialisées normalement
- Commande app:restore-missing-users : recrée (en archivés) les users encore
  référencés mais supprimés, restaurant l'intégrité sans perte de données.
  Idempotente, option --dry-run. À lancer une fois en prod après déploiement.
2026-06-26 15:51:27 +02:00
gitea-actions 3ea1a31784 chore: bump version to v0.4.44
Auto Tag Develop / tag (push) Successful in 9s
Build & Push Docker Image / build (push) Successful in 1m42s
2026-06-25 20:53:41 +00:00
gitea-actions d55a088e41 chore: bump version to v0.4.43
Auto Tag Develop / tag (push) Successful in 10s
Build & Push Docker Image / build (push) Successful in 23s
2026-06-25 20:22:20 +00:00
matthieu 6fc6eee5b9 chore : bump version to v0.4.42
Auto Tag Develop / tag (push) Successful in 8s
Build & Push Docker Image / build (push) Successful in 2m30s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:42:23 +02:00
matthieu a7bf3101c5 chore : bump version to v0.4.41
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:15:08 +02:00
matthieu 1dd7053ebd feat(observability) : error tracking GlitchTip back + front (INFRA #146)
Backend : sentry/sentry-symfony branché en prod uniquement (bundle prod-only,
exceptions seules, 4xx ignorés, release = app.version), DSN via SENTRY_DSN
(runtime, infra/prod/.env).
Frontend : @sentry/nuxt chargé seulement si NUXT_PUBLIC_SENTRY_DSN présent
(donc au build prod), upload des source maps gated sur les secrets. DSN front
et secrets passés en build-args (Dockerfile) depuis les secrets Gitea (CI).
Doc README (section Error tracking) + .env.example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:14:53 +02:00
gitea-actions 6d95f9e782 chore: bump version to v0.4.40
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 2m50s
2026-06-25 15:30:33 +00:00
tristan c766e76624 feat(sidebar) : migration vers MalioSidebar — 3 groupes, footer timer+version, logo (LST-71) (#26)
Auto Tag Develop / tag (push) Successful in 8s
## Objectif
Remplacer la sidebar maison par le composant `MalioSidebar` de `@malio/layer-ui` (alignement avec Starseed).

## Changements
- **Backend** : `config/sidebar.php` re-catégorisé en **3 groupes** (Général / Outils / Administration). Tous les gates permission/rôle/module **préservés côté serveur** (rien déplacé côté client).
- **Frontend** : `app/layouts/default.vue` migré vers `<MalioSidebar>`. Un computed `mergedSections` mappe les sections backend et y fusionne les items contextuels (Kanban/Groupes/Archives sous « Projets », Mes absences, Messagerie avec compteur `(N)`, Documents).
- **Footer** : timer (`SidebarTimer`) + version de l'app (masquée en mode replié).
- **Logo** : logos Malio repris de Starseed (`LOGO_MALIO.png` / `LOGO_MALIO_COLLAPSED.png`).
- **Mobile** : `MalioSidebar` étant toujours visible (pas de tiroir off-canvas), le hamburger pilote désormais le repli ; suppression du code de tiroir mobile mort (`sidebarOpen`/`openMobileSidebar`/`closeMobileSidebar`).
- **Nettoyage** : suppression de `SidebarLink.vue` et `LOGO_CARRE.png` (obsolètes). `malio.png` conservé (utilisé par la page login).
- **i18n** : nouvelles clés `sidebar.tools.section`, `sidebar.general.myAbsences`, `sidebar.project.kanban|groups|archives` ; `sidebar.general.section` → « Général ».

## Compromis (limites du composant, lib non modifiée)
- Pas d'icône par item (uniquement icône de section) — design malioUI, comme Starseed.
- Badge mail → suffixe `(N)` dans le libellé.

## Vérifications
- Build Nuxt OK (` Build complete!`, exit 0).
- Revue par task + revue finale whole-branch : aucun Critical/Important.
- Sécurité : filtrage des permissions inchangé (côté serveur).

Specs/plan : `docs/superpowers/specs/2026-06-25-malio-sidebar-migration-design.md`, `docs/superpowers/plans/2026-06-25-malio-sidebar-migration.md`.

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

Reviewed-on: #26
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-25 15:30:23 +00:00
gitea-actions 267cea76da chore: bump version to v0.4.39
Auto Tag Develop / tag (push) Successful in 10s
Build & Push Docker Image / build (push) Successful in 1m34s
2026-06-25 12:07:40 +00:00
gitea-actions 386242c84d chore: bump version to v0.4.38
Auto Tag Develop / tag (push) Successful in 8s
Build & Push Docker Image / build (push) Successful in 3m5s
2026-06-24 19:12:19 +00:00
matthieu ad029f5c7d chore(directory) : ferme contrats Repository (findBy) + bindings DI MCP Directory
Pull Request — Quality gate / Frontend (build) (pull_request) Successful in 1m15s
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m34s
Plumbing complementaire des outils MCP ajoutes en 99626b8 :
- declare findBy() sur Address/Contact/CommercialReport RepositoryInterface
  (Prestataire l'avait deja) pour exposer la methode au contrat DDD
- bindings explicites des 4 repos dans services.yaml (cohrence avec
  Client/Prospect, meme si Symfony auto-alias l'interface vers l'unique
  implementation)
2026-06-24 20:53:17 +02:00
gitea-actions 94e6abcbaa chore: bump version to v0.4.37
Auto Tag Develop / tag (push) Successful in 17s
Build & Push Docker Image / build (push) Successful in 40s
2026-06-24 16:07:56 +00:00
gitea-actions 052ef55c79 chore: bump version to v0.4.36
Auto Tag Develop / tag (push) Successful in 8s
Build & Push Docker Image / build (push) Successful in 23s
2026-06-24 08:57:34 +00:00
gitea-actions b467dbc584 chore: bump version to v0.4.35
Auto Tag Develop / tag (push) Successful in 9s
Build & Push Docker Image / build (push) Successful in 1m48s
2026-06-24 08:13:40 +00:00
gitea-actions 6710c3015e chore: bump version to v0.4.34
Auto Tag Develop / tag (push) Successful in 9s
Build & Push Docker Image / build (push) Successful in 53s
2026-06-23 15:46:57 +00:00
gitea-actions 3294b0c361 chore: bump version to v0.4.33
Auto Tag Develop / tag (push) Successful in 9s
Build & Push Docker Image / build (push) Successful in 35s
2026-06-23 15:15:20 +00:00
Matthieu 9705b335ef fix(rbac) : enforce granular permissions on business resources
Les ressources métier (ProjectManagement, Directory, TimeTracking) étaient
gardées par is_granted('ROLE_USER')/'ROLE_ADMIN', ignorant les permissions
RBAC granulaires déclarées par les modules : un utilisateur sans permission
voyait quand même projets, tâches, clients, etc.

- PermissionVoter : le regex excluait les tirets, donc project-management.* et
  time-tracking.* n'étaient supportées par aucun voter (refus pour tous, admin
  compris car le bypass ROLE_ADMIN est interne au voter). Ajout du tiret.
- Câblage des permissions *.view (lecture) / *.manage (écriture) sur les 17
  ressources métier. Métadonnées tâches lisibles via projects.view OR tasks.view.
  Directory partagé client/prospect via clients.* OR prospects.*. TimeEntry
  conserve le self-service (object.getUser() == user).
- Sidebar : gating par permission effective des onglets Projets / Mes tâches /
  Suivi du temps (config/sidebar.php).
- Test fonctionnel ProjectAccessControlTest (0 perm -> 403, view -> 200,
  view ne donne pas l'écriture -> 403).
2026-06-23 17:05:33 +02:00
gitea-actions 903030afbc chore: bump version to v0.4.32
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 1m58s
2026-06-23 14:25:40 +00:00
gitea-actions 932fccf75f chore: bump version to v0.4.31
Auto Tag Develop / tag (push) Successful in 8s
Build & Push Docker Image / build (push) Successful in 2m48s
2026-06-23 13:50:52 +00:00
matthieu 8313c759c6 Migration modular monolith DDD (0.1 → 3.3) (#17)
Auto Tag Develop / tag (push) Successful in 9s
## Migration modular monolith DDD — Lesstime (0.1 → 3.3)

Cette MR regroupe l'intégralité de la refonte en monolithe modulaire (strangler progressif, additif). Elle remplace les MR stackées de Phase 1 (#12–#16), désormais incluses ici.

**Ne pas merger avant validation fonctionnelle** : branche destinée à être testée telle quelle.

### Périmètre — 9 modules sous `src/Module/`
| Phase | Module | Contenu |
|------|--------|---------|
| 0.1 | (socle) | infrastructure modulaire, `ModuleInterface`, mapping Doctrine par module |
| 0.2 | (socle front) | auto-détection des layers Nuxt sous `frontend/modules/*` |
| 1.1 | **Core** | Identité (User/Auth), Notifications, Notifier |
| 1.2 | Core | RBAC fin (permissions `module.resource.action`, sidebar gated) |
| 1.3 | Core | Audit log (`#[Auditable]`, listener, provider DBAL) |
| 2.1 | **TimeTracking** | TimeEntry + MCP + export |
| 2.2 | **ProjectManagement** | cœur métier Projets/Tâches + 38 MCP tools |
| 2.3 | **Absence** | demandes, soldes, policies, justificatifs |
| 2.4 | **Directory** | Clients (migrés) + **Prospects** (nouveau, conversion → Client) |
| 2.5 | **Mail** | intégration IMAP OVH + liens tâches |
| 2.6 | **Integration** | Gitea / BookStack / Zimbra / Share |
| 3.1 | **Reporting** | rapports transverses (DBAL read-only, 0 import inter-module) |
| 3.2 | **ClientPortal** | portail client (ROLE_CLIENT cloisonné, tickets, notifications) |
| 3.3 | (finition) | nettoyage legacy — `src/Entity` vide, app 100% modulaire |

### Architecture
- Découplage inter-modules par **contrats** (`UserInterface`, `ProjectInterface`, `TaskInterface`, `TaskTagInterface`, `ClientInterface`, `ClientTicketInterface`, `LeaveProfileInterface`) + `resolve_target_entities` 100% modulaire (aucune cible legacy).
- Repositories : interface `Domain/Repository` + implémentation `Infrastructure/Doctrine`, bindées.
- Reporting en DBAL read-only pur (aucun import d'entité d'un autre module).
- Chaque migration de module : déplacement à comportement préservé (API publique et noms d'outils MCP inchangés), migrations **additives** uniquement (zéro destructif).

### Sécurité
- ROLE_CLIENT cloisonné : un utilisateur client n'accède qu'à `/portal` et à ses propres tickets (filtrés par `allowedProjects`), interdit sur toute l'API interne.
- Correctif : interdiction pour un client de créer un lien vers le partage SMB (upload uniquement).

### QA non-régression (branche reconstruite from scratch)
- Migrations from scratch + fixtures : OK.
- Compilation dev + prod : OK.
- **180 tests PHPUnit verts**, php-cs-fixer clean, ~96 routes, **66 outils MCP** tous sous `App\Module\*`.
- Smoke test runtime multi-rôles (admin / ROLE_USER / ROLE_CLIENT) : 44 vérifications HTTP, **0 écart**, cloisonnement client étanche.
- Build Nuxt OK, 9 layers, 0 import legacy résiduel.

### Points à arbitrer (hors périmètre de cette migration)
- Durcissement MCP/IDOR pré-existant (`userId` explicite sans scoping sur certains tools TimeTracking/Absence/TaskDocument) — ticket dédié recommandé.
- Validation fonctionnelle de **Prospect** et **ClientPortal** (conçus depuis les specs disque).
- **Harmonisation visuelle Malio finale** (3.3) — finition esthétique inter-modules laissée au PO.

---

## ⚠️ Déploiement / migration des données — à ne pas oublier

### 1. Resynchroniser les séquences PostgreSQL après tout import/restore de dump
Si la prod (ou tout environnement) est **montée depuis un dump** (`pg_restore` / `COPY`), les lignes sont chargées avec leurs `id` explicites **sans avancer les séquences** → au premier `INSERT` : `duplicate key value violates unique constraint "..._pkey"` (constaté en local sur `notification`, `task`, `time_entry`…).

À lancer **juste après chaque restore/import** :

```sql
DO $$
DECLARE r RECORD; maxid BIGINT; seq TEXT;
BEGIN
  FOR r IN SELECT table_name, column_name FROM information_schema.columns WHERE table_schema='public'
  LOOP
    seq := pg_get_serial_sequence(quote_ident(r.table_name), r.column_name);
    IF seq IS NOT NULL THEN
      EXECUTE format('SELECT COALESCE(MAX(%I),0) FROM %I', r.column_name, r.table_name) INTO maxid;
      PERFORM setval(seq, GREATEST(maxid,1), maxid > 0);
    END IF;
  END LOOP;
END $$;
```

> Ne concerne **pas** une prod qui tourne déjà (séquences avancées organiquement) — uniquement le cas restore/import. Idempotent, sans risque.

### 2. Fix dénormalisation des collections typées-contrat (code, inclus dans la branche)
Les relations **to-many** typées par une interface `Shared\Domain\Contract\*` (`TimeEntry::tags` → `TaskTagInterface`, `Task::collaborators` → `UserInterface`) étaient **indénormalisables par API Platform** (mono-valué OK via IRI, collection KO) → **tout POST/PATCH portant une telle collection renvoyait 400/500**. Corrigé par un dénormaliseur générique `ContractRelationDenormalizer` (réutilise `resolve_target_entities`, zéro couplage par-entité) + test fonctionnel de non-régression.

---------

Co-authored-by: Matthieu <contact@malio.fr>
Reviewed-on: #17
2026-06-23 13:50:42 +00:00
gitea-actions d0a49322e1 chore: bump version to v0.4.30
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 2m21s
2026-06-19 07:21:59 +00:00
gitea-actions da8beb2b2d chore: bump version to v0.4.29
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 28s
2026-06-15 09:52:11 +00:00
gitea-actions 7d87af6774 chore: bump version to v0.4.28
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 1m13s
2026-06-15 09:24:14 +00:00
gitea-actions 4e430cca43 chore: bump version to v0.4.27
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 3m2s
2026-06-12 13:52:47 +00:00
matthieu 0dd253e483 Merge branch 'develop' into feat/share-explorer-impl 2026-06-12 13:52:34 +00:00
gitea-actions f8acdd9817 chore: bump version to v0.4.26
Auto Tag Develop / tag (push) Successful in 5s
Build & Push Docker Image / build (push) Successful in 1m7s
2026-06-08 13:59:09 +00:00
gitea-actions 5014dd063e chore: bump version to v0.4.25
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 1m5s
2026-06-04 14:45:35 +00:00
Matthieu f9428f5c5d feat(share) : source de fichiers SMB (FileSource + SmbFileSource) 2026-06-03 17:05:08 +02:00
gitea-actions 8475f9604c chore: bump version to v0.4.24
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 23s
2026-06-02 07:51:11 +00:00
Matthieu 226ab8ea84 feat(mcp) : tools update et delete des documents de tâche
Auto Tag Develop / tag (push) Successful in 7s
Ajoute deux tools MCP sur le modèle de add-task-document :
- update-task-document : remplace le contenu et/ou renomme un document (MIME ré-inféré, taille rafraîchie, garde-fous vide/5 Mo)
- delete-task-document : supprime le document en base, le fichier disque étant retiré par le PreRemove listener

Met aussi à jour le compteur de tools MCP dans le CLAUDE.md (60).
2026-06-02 09:50:03 +02:00
gitea-actions d48ee8eae5 chore: bump version to v0.4.23
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 49s
2026-06-01 21:26:44 +00:00
gitea-actions cdd7ca7626 chore: bump version to v0.4.22
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 49s
2026-06-01 20:52:47 +00:00
gitea-actions 85897708ec chore: bump version to v0.4.21
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 55s
2026-06-01 20:45:31 +00:00
gitea-actions 7f79bdf236 chore: bump version to v0.4.20
Auto Tag Develop / tag (push) Successful in 12s
Build & Push Docker Image / build (push) Successful in 1m6s
2026-06-01 20:33:07 +00:00
Matthieu e87c474672 feat(mcp) : ajout du tool add-task-document pour attacher des documents Markdown à un ticket
Auto Tag Develop / tag (push) Successful in 10s
Nouveau tool MCP recevant le contenu texte brut (pas de base64), optimisé pour le Markdown. MIME inféré depuis l'extension du fileName (text/markdown par défaut). Persiste un TaskDocument avec uploadedBy = utilisateur du token MCP.
2026-06-01 22:32:44 +02:00
gitea-actions 8cfa048e5a chore: bump version to v0.4.19
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 51s
2026-05-29 14:46:18 +00:00
gitea-actions 81d905257a chore: bump version to v0.4.18
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 1m0s
2026-05-28 08:51:21 +00:00
gitea-actions 8f75e2e310 chore: bump version to v0.4.17
Auto Tag Develop / tag (push) Successful in 8s
Build & Push Docker Image / build (push) Successful in 22s
2026-05-27 08:53:52 +00:00
gitea-actions 77e1017d09 chore: bump version to v0.4.16
Auto Tag Develop / tag (push) Successful in 9s
Build & Push Docker Image / build (push) Successful in 37s
2026-05-27 08:36:22 +00:00
gitea-actions 433032701e chore: bump version to v0.4.15
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 28s
2026-05-27 08:11:38 +00:00
gitea-actions 7e32e4c013 chore: bump version to v0.4.14
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 52s
2026-05-26 09:36:14 +00:00
gitea-actions 96e25c2390 chore: bump version to v0.4.13
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 48s
2026-05-26 09:33:27 +00:00
gitea-actions 1991c43f8c chore: bump version to v0.4.12
Auto Tag Develop / tag (push) Successful in 8s
Build & Push Docker Image / build (push) Successful in 57s
2026-05-26 09:08:30 +00:00
gitea-actions b13ba41674 chore: bump version to v0.4.11
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 44s
2026-05-26 09:02:57 +00:00
gitea-actions f8322f8b1e chore: bump version to v0.4.10
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 45s
2026-05-26 08:49:58 +00:00
gitea-actions 2feba57cb6 chore: bump version to v0.4.9
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 20s
2026-05-26 08:42:59 +00:00
gitea-actions 6db6d13e76 chore: bump version to v0.4.8
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 1m21s
2026-05-26 08:08:06 +00:00
Matthieu f9773b3a5e feat(absences) : mise en conformité légale (événements familiaux, demi-journée, CCN)
Périmètre 1-6 du design 2026-05-22-absence-legal-compliance-fixes (points
lourds — ancienneté, CP pendant maladie, rétention — reportés en backlog).

- Événements familiaux sans solde : AbsenceType::decrementsBalance() ne vaut
  true que pour les CP. Mariage/PACS, naissance, décès = droits par événement ;
  congé parental = suspension ; maladie = Sécu. Plus de solde fantôme.
- Décès : daysPerEvent = null (selon lien de parenté) + motif obligatoire à la
  création (REST + MCP), les minimums légaux étant rappelés dans l'aide.
- Ajout du congé naissance (type, policy 3 j, justificatif, libellés/couleur front).
- Garde-fou demi-journée : -0,5 appliqué uniquement si le jour-borne est
  réellement décompté (corrige un sous-décompte week-end/férié) — TDD.
- CCN documentée : paramètre app.absence.convention = "Syntec (IDCC 1486)",
  rappelée en sous-titre admin et dans l'aide /help.

Tests : AbsenceDayCalculatorTest (garde-fou demi-journée), AbsenceRequestLifecycle
(motif décès obligatoire + aucun solde touché). make test 52/52, build Nuxt OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 16:00:28 +02:00