Files
Lesstime/docs/superpowers/plans/2026-06-20-lst-58-directory-prospect.md
T
Matthieu 57ccd9a740 feat(directory) : add Clients/Prospects repertoire front layer
LST-58 (2.4) front. Completes the Directory module.

- New frontend/modules/directory/ layer (auto-detected): /directory page with
  Clients and Prospects tabs.
- Client front moved into the layer (clients service + client DTO +
  ClientDrawer). New prospects service, prospect DTO and ProspectDrawer (with
  a "Convert to client" action calling POST /prospects/{id}/convert).
- Consumers repointed to ~/modules/directory/... (admin client tab, PM project
  drawer + project pages + project DTO, time-tracking page + export drawer).
- Sidebar admin item /directory gated by the directory module; /directory
  protected by the admin middleware. i18n keys added (directory.*, prospects.*).

nuxt build passes; routes preserved.

Adds the 2.4 plan doc.
2026-06-20 19:18:09 +02:00

4.8 KiB

LST-58 (2.4) — Module Directory : Prospect + front répertoire (plan)

Suite de la migration Directory. Client (back) déjà livré (c5738d2). Reste : entité Prospect (nouvelle) + front répertoire (Clients + Prospects). Spec produit non fournie → design défini ici de façon raisonnable, à valider au test. Additif, sans régression. Branche integration/modular-monolith-0.1-1.3.

Design Prospect (décidé, à valider)

Aligné sur Client (même module Directory), enrichi des concepts de prospection commerciale.

Entité App\Module\Directory\Domain\Entity\Prospect (table prospect) :

  • id int PK
  • name string(255) NOT NULL — contact ou société
  • company string(255) nullable
  • email string(255) nullable
  • phone string(50) nullable
  • street string(255) nullable / city string(255) nullable / postalCode string(20) nullable (alignés Client)
  • status enum ProspectStatus NOT NULL (default New)
  • source string(255) nullable — origine (recommandation, salon, site web…)
  • notes text nullable
  • convertedClient ManyToOne ClientInterface nullable, JoinColumn ON DELETE SET NULL — rempli à la conversion
  • Timestampable/Blamable (trait) + #[Auditable]
  • Groupes : prospect:read / prospect:write

Enum App\Module\Directory\Domain\Enum\ProspectStatus : New (nouveau), Contacted (contacté), Qualified (qualifié), Won (gagné/converti), Lost (perdu). Méthode label(): string (FR), comme les autres enums.

API Platform (aligné Client) :

  • GetCollection paginationEnabled:false, is_granted('ROLE_USER')
  • Get ROLE_USER ; Post/Patch/Delete ROLE_ADMIN
  • Opération custom Post /prospects/{id}/convert (processor ConvertProspectProcessor) : crée un Client à partir du Prospect (name/company→name, email, phone, adresse), lie convertedClient, passe status=Won. Sécurité ROLE_ADMIN. Renvoie le Prospect mis à jour. Idempotent si déjà converti (renvoie l'existant).
  • #[ApiFilter] SearchFilter sur status (filtre répertoire).

Repo : ProspectRepositoryInterface (Domain) + DoctrineProspectRepository (Infra) + binding.

MCP (cohérent avec clients, sous Infrastructure/Mcp/Tool/) : list-prospects, get-prospect, create-prospect, update-prospect, delete-prospect, convert-prospect. Serializer : ajouter prospect() dans src/Mcp/Tool/Serializer.php.

DirectoryModule.permissions() : ajouter directory.prospects.view, directory.prospects.manage (additif).

Migration additive : CREATE TABLE prospect (colonnes + FK converted_client→client ON DELETE SET NULL + created_by/updated_by FK user + index + COMMENT). Down = DROP TABLE.

Fixtures : 2-3 prospects de démo (statuts variés), dont un converti.

Front répertoire (frontend/modules/directory/)

Aujourd'hui : pas de page client dédiée (AdminClientTab + picker ProjectDrawer). On crée un vrai répertoire.

  • nuxt.config.ts vide.
  • services/ : clients.ts (move depuis racine), prospects.ts (nouveau) + dto/{client,prospect}.ts.
  • pages/directory.vue : page à 2 onglets (Clients / Prospects), tableaux paginés côté client (paginationEnabled:false back), recherche/filtre statut pour prospects.
  • components/ : ClientDrawer.vue (move depuis components/client/), ProspectDrawer.vue (nouveau, create/edit + bouton « Convertir en client »).
  • Sidebar : ajouter item sidebar.general.directory/directory, 'module' => 'directory', gate ROLE_ADMIN (gestion référentiel).
  • Réécrire imports consommateurs de ~/services/clients / ~/services/dto/client (AdminClientTab, ProjectDrawer, pages projects) → ~/modules/directory/services/.... AdminClientTab : soit le retirer de /admin au profit de /directory, soit le laisser pointer le nouveau service. Décision : garder AdminClientTab fonctionnel (repoint service) ET ajouter la page /directory (les deux coexistent ; /directory = vue dédiée).
  • i18n global : ajouter clés directory.*, prospects.*, sidebar.general.directory.

Vagues d'exécution

  1. Back Prospect : enum + entité + repo + API (CRUD + convert) + MCP (6 tools) + Serializer + permissions module + fixtures + migration. Vérif cache:clear/migrate/phpunit/cs-fixer → commit.
  2. Front Directory : layer (move client front + page répertoire + ProspectDrawer + prospects service/dto) + sidebar + imports + i18n. Vérif nuxt build → commit.

Critères d'acceptation (ticket #58)

  • Clients en module (fait, c5738d2)
  • Prospects en module + front répertoire fonctionnel
  • resolve_target_entities → Directory\Client
  • make test vert, aucune migration destructive
  • toggle module directory (sidebar + route /directory)

Suite phase 2 (après 2.4)

  • 2.5 (#67) Module Mail — WIP docs/mail-integration.md, à traiter avec précaution.
  • 2.6 (#68) Module Integration (Gitea/BookStack/Zimbra/Share).