# kView INVESTOR — Baseline de migration frontend

> Statut : baseline historique conservée — phase 7.12 terminée et validée
>
> Relevé initial : 17 juillet 2026 — dernier checkpoint documentaire : 20 juillet 2026
>
> Révision Git observée : `017a3c6f6985bfb84513dbf0f42fe61632c81391`
>
> Les mesures initiales restent volontairement figées avant Inertia. Les
> checkpoints postérieurs sont documentés ici et dans
> `dev_guide/frontend-inertia-foundation.md`.

## 1. Rôle de cette baseline

Ce document fixe l'état de départ mesurable de la migration décrite dans
`dev_guide/frontend-stack-migration-roadmap.md`.

Il ne décrit pas une cible théorique. Il enregistre les routes, les moteurs de
rendu, les modules JavaScript, les composants partagés, les parcours critiques
et la dette qualité réellement présents avant l'introduction d'Inertia et Vue.

Les changements locaux du Component Lab étaient déjà en cours lors du relevé.
Ils font partie du contexte observé et ne doivent pas être écrasés par la
migration.

## 2. Résumé du point de départ

| Sujet | Baseline |
| --- | --- |
| PHP | 8.4.23 |
| Laravel | 11.54.0 |
| Rendu applicatif | Blade |
| Navigation riche | JavaScript vanilla et navigation partielle kView |
| Vue / TypeScript / Inertia | absents du build actif |
| Routes Laravel | 185 au total |
| Routes avec middleware `web` | 109 |
| Routes `web` acceptant GET | 65, pages et endpoints confondus |
| Vues Blade applicatives | 88 sous `resources/views` |
| Composants Blade kView packagés | 49 : core 28, data 15, visualization 6 |
| JavaScript applicatif | 17 modules, 3 874 lignes |
| JavaScript packagé kView | 19 modules, 4 997 lignes |
| Tests PHP | 104 réussis, 726 assertions avant le correctif d'accessibilité navigateur |
| Build Vite | réussi |
| PHPStan | 137 erreurs dans 26 fichiers |
| Pint | 134 fichiers non conformes |
| Composer | configuration valide |

La dette PHPStan et Pint est antérieure à la migration. Elle n'est pas masquée
par une baseline de suppression : chaque chantier doit éviter d'ajouter de
nouvelles erreurs et corriger en priorité les fichiers qu'il modifie.

## 3. Inventaire des routes visibles

Le statut utilise le vocabulaire de la roadmap : `Blade`, `pilote`, `Inertia`
ou `migrée`. L'inventaire est vivant même si les mesures initiales restent
figées : `/search` est la première route produit Inertia historique et
`/activity` la deuxième ; les fiches et formulaires métier des lots 6.2 à 6.5
sont maintenant Inertia. Les sept index métier ont rejoint le même root dans
les lots 7.11–7.12 ; leur gate agrégé de clôture est enregistré au checkpoint
22.

| Surface | Routes GET visibles | Rendu ou réponse actuelle | Statut | Cible indicative |
| --- | --- | --- | --- | --- |
| Authentification | `/login` | `auth.login` | Blade | phase 6, après validation Passport |
| Accueil | `/` | `home` | Blade | phase 8 |
| Activité | `/activity` | `Activity/Index` dans `AuthenticatedLayout` | Inertia, shell Vue persistant | phase 6.1 terminée |
| Dashboard | `/dashboard` | `dashboard.index` | Blade | phase 8 |
| Recherche | `/search` | `Search/Index` dans `AuthenticatedLayout` | Inertia, shell Vue persistant | phase 5 terminée |
| Import Flex | `/imports` | `flex_import.index` | Blade | phase 6 avancée |
| Import Raydocs | `/imports/raydocs` | `raydocs.imports.index` | Blade | phase 6 avancée |
| Paramètres | `/settings`, `/preferences` | un contexte Laravel ; Blade sur routes historiques ou payload JSON pour le dialog Vue | Blade conservé + Vue dans le shell Inertia | comparaison maintenue pendant la phase 6 |
| Fonds | `/funds` puis `/funds/create`, `/funds/{fund}`, `/funds/{fund}/edit` | `Business/Index`, `Funds/Form`, `Funds/Show` | Inertia, shell Vue persistant | phase 7.12 validée |
| General Partners | `/gps` puis `/gps/create`, `/gps/{gp}`, `/gps/{gp}/edit` | `Business/Index`, `Gps/Form`, `Gps/Show` | Inertia, shell Vue persistant | pilote 7.11 validé |
| Investisseurs | `/investors` puis `/investors/create`, `/investors/{investor}`, `/investors/{investor}/edit` | `Business/Index`, `Investors/Form`, `Investors/Show` | Inertia, shell Vue persistant | phase 7.12 validée |
| Investissements | `/investments` puis Create/Show/Edit et créations imbriquées Investor/Fund | `Business/Index`, `Investments/Form`, `Investments/Show` | Inertia, shell Vue persistant | phase 7.12 validée |
| Calls / distributions | `/call-distribs` puis Create/Show/Edit | `Business/Index`, `CallDistribs/Form`, `CallDistribs/Show` | Inertia, shell Vue persistant | phase 7.12 validée |
| Capital accounts | `/capital-accounts` puis Create/Show/Edit | `Business/Index`, `CapitalAccounts/Form`, `CapitalAccounts/Show` | Inertia, shell Vue persistant | phase 7.12 validée |
| Taux de change | `/exchange-rates` puis Create/Show/Edit | `ExchangeRates/Index`, `ExchangeRates/Form`, `ExchangeRates/Show` | Inertia, shell Vue persistant, admin | phase 7.12 validée |
| Taux de change — détail | `/exchange-rates/{exchange_rate}` | `ExchangeRates/Show` dans `AuthenticatedLayout`, admin | Inertia, shell Vue persistant | phase 6.2 validée |
| Validation des comptes | `/admin/validate-capital-accounts` | `admin.validate-capital-accounts` | Blade | phase 8 |
| Listes administrables | `/admin/dropdowns`, `/admin/dropdowns/{filename}/edit` | vues Blade `lncshared::*` | Blade | hors premier lot ; propriétaire partagé |
| Component Lab | `/__kview`, `/__kview/inertia/*`, local et test seulement | composants Blade/Vue réels et spécimens du layout persistant produit | Inertia (technique) | contrat phase 5 validé |

### Redirections à ne pas prendre pour des pages pilotes

| Route | Destination actuelle |
| --- | --- |
| `/status` | `/settings?tab=system` |
| `/admin` | `/settings?tab=admin` |
| `/logout` | action `POST` de session ; `GET` refusé, pas un écran |

La page Status mentionnée initialement dans la roadmap n'était donc pas un bon
pilote de production : sa route est une redirection. Après le prototype du
Component Lab, `/search` est devenue la première vraie route produit Inertia.
Son contrôleur renvoie `Search/Index`; les liens de résultats vers les écrans
Blade restent natifs et le retour navigateur est couvert. Depuis la clôture de
phase 5, la page compose `AuthenticatedLayout` dans la racine Inertia standard :
la sidebar, la topbar, la recherche globale, Excel, le compte, les toasts et
Settings appartiennent au shell Vue persistant.

Le checkpoint 5.3 a ajouté dans le banc technique les toasts globaux, Excel
Login et le menu utilisateur complet en Vue. À ce checkpoint historique, il ne
modifiait pas encore la propriété du shell produit.

Le checkpoint 5.4 a ensuite ajouté Settings au shell technique. Le clic
ordinaire ouvre `ApplicationSettingsDialog`, tandis que `/preferences?tab=...`
conserve la version Blade explicite pour comparaison et fallback. La clôture de
phase 5 a rendu ce même shell actif sur `/search` ; les autres routes métier
restaient Blade jusqu'à leur portage incrémental. Le checkpoint 6.1 y a ajouté
`/activity` sans remonter de shell. Les lots 6.2 à 6.5 ont ensuite porté les
fiches et formulaires définis par la roadmap ; les lots 7.11–7.12 ont depuis
porté leurs index ERP sans remonter de second shell.

### Endpoints web auxiliaires à préserver

Ces routes ne sont pas des pages Vue, mais plusieurs écrans en dépendent :

- `/dashboard/export` et `/dashboard/quarterly` ;
- `/search/suggest` ;
- `/lookups/funds`, `/lookups/gps`, `/lookups/investors` ;
- `/smart-tables/*` pour les six ressources actuelles ;
- `/api/dropdowns`, `/api/dropdown/{filename}` et le token protocole ;
- `/settings/avatar` ;
- les routes Passport `/oauth/*` ;
- les routes d'écriture, d'import, d'export et de CRUD.

Inertia ne doit pas transformer automatiquement ces endpoints en pages. Ils
restent des contrats serveur jusqu'à ce qu'un écran migré définisse précisément
comment il les consomme ou les remplace.

## 4. Inventaire JavaScript

### Modules les plus sensibles

| Propriétaire | Module | Lignes | Responsabilité actuelle | Traitement cible |
| --- | --- | ---: | --- | --- |
| Application | `ui-page-loading.js` | 1 220 | navigation complète et partielle, historique, scroll, focus, remplacement DOM, replay des initializers | gel immédiat ; retrait route par route |
| kView data | `erp-table.js` | 1 302 | état, filtres, colonnes, sélection, export et interactions ERP Blade | moteur produit porté vers `KviewCrudTable` ; module conservé pour l'API Blade publique |
| kView core | `ui-floating-layer.js` | 822 | portails, positionnement, Escape, focus et restauration | conservé côté Blade ; équivalent Vue interne kView |
| Application | `settings-modal.js` | 746 | chargement du fragment et cycle de vie de la modale globale Blade | portage Vue adopté en phase 5 ; retrait après migration du dernier consommateur Blade |
| kView core | `ui-date-picker.js` | 615 | calendrier accessible | adapter Vue après les champs simples |
| kView data | `smart-table.js` | 561 | table historique alimentée par API | Calls/Distributions et Capital Accounts remplacés en produit ; API package conservée |
| Application | `dashboard-quarterly.js` | 439 | chargement différé et graphiques trimestriels | phase 8 |

### Initializers rejoués après navigation partielle

Le routeur historique connaît actuellement 17 initializers :

```text
kviewInitCallDistribForms
kviewInitDashboardQuarterly
kviewInitDatePickers
kviewInitDropdowns
kviewInitDynamicFields
kviewInitErpTables
kviewInitExcelLogin
kviewInitFlexImports
kviewInitGlobalSearches
kviewInitMobileHome
kviewInitRaydocsImports
kviewInitSettingsAccount
kviewInitSettingsModalHosts
kviewInitSmartTables
kviewInitTabs
kviewInitToasts
kviewInitUserMenus
```

`FrontendMigrationGuardrailTest` autorise la suppression progressive de ces
initializers, mais échoue si une nouvelle responsabilité est ajoutée à
`ui-page-loading.js`. Une exception exige une décision documentée dans cette
baseline et dans la roadmap.

## 5. Inventaire kView à protéger

Les 49 composants Blade packagés restent une API supportée pendant la
migration :

| Package | Composants Blade | Rôle |
| --- | ---: | --- |
| `kview/ui-core` | 28 | primitives, formulaires, navigation, feedback, accessibilité et surfaces flottantes |
| `kview/ui-data` | 15 | façade ERP, tables, cellules typées, filtres, pagination et drawers |
| `kview/visualization` | 6 | formatage financier, métriques et graphiques |

L'application possède encore 22 composants Blade spécifiques sous
`resources/views/components`, ainsi que le shell, les pages et les compositions
métier.

Le contrat de migration est un double adaptateur :

```text
contrats kView, tokens et sémantique
├── API Blade existante : x-ui.* et x-erp.*
└── API Vue progressive : Kview*
```

Une page métier Vue ne doit importer ni Reka directement, ni une implémentation
physique sous `packages/`. Elle consomme uniquement l'API publique kView.

## 6. Matrice des parcours critiques

| Parcours | Risque | Couverture actuelle | Porte UAT / déploiement | Couverture avant migration de l'écran |
| --- | --- | --- | --- | --- |
| Login, logout et redirection invité | critique | logout `POST`, redirections native/Inertia et session expirée testés | succès/échec login et verrouillage | Playwright clavier + erreurs + focus |
| Passport et `ProtocolGrant` | critique | émission, hash et consommation unique du token protocole, password grant, refresh et révocation du refresh précédent testés | exécuter `kview_investor:verify-uat` avec le client réel de préproduction | conserver des tests backend dédiés |
| CRUD Fund / GP / Investor / Investment | critique | contrats et métriques partiels | index, création valide/invalide, édition, suppression et permissions | backend + Vue + Playwright par famille |
| Tableau ERP | critique | tests de rendu et contrats JS/Blade | fixture stable de colonnes et cellules | tri, filtre, pagination, sélection, export, clavier et mobile |
| Import Flex | critique | tests service et web présents | preview, apply, erreurs, nettoyage et stockage | Playwright fichier valide/invalide |
| Import Raydocs | critique | dépôt PDF testé | UUID, stockage privé, statut, erreur et permissions | Playwright upload et feedback |
| Dashboard | élevé | valeurs sans taux de change testées | filtres, périodes, export et endpoints trimestriels | performance, graphiques, retour et responsive |
| Paramètres | élevé | profil, mot de passe, admin et fragment testés | toutes préférences et permissions | modale, focus, Escape, erreurs et persistance |
| Recherche | moyen | pas de parcours navigateur dédié | résultats et suggestions backend | pilote Inertia avec historique et clavier |
| Responsive et accessibilité | élevé | contrats unitaires ciblés | premier smoke navigateur | axe, clavier, desktop contraint, tablette et mobile |

## 7. Baseline qualité et build

Commandes exécutées depuis la racine :

| Commande | Résultat initial |
| --- | --- |
| `php artisan test` | réussi : 100 tests, 700 assertions, 4,53 s |
| `./vendor/bin/pint --test` | échec : 134 fichiers |
| `./vendor/bin/phpstan analyse --no-progress` | échec : 137 erreurs dans 26 fichiers |
| `npm run build` | réussi : 90 modules, 1,62 s |
| `composer validate --no-check-publish` | réussi |

### Assets de production initiaux

| Asset | Taille | Gzip |
| --- | ---: | ---: |
| CSS application | 203,43 kB | 34,32 kB |
| JavaScript application | 112,01 kB | 35,76 kB |
| Drawer ERP découpé | 88,15 kB | 26,22 kB |
| CSS Component Lab | 112,08 kB | 18,28 kB |
| JavaScript Component Lab | 3,57 kB | 1,51 kB |

Ces tailles constituent la baseline de bundle. Le scénario navigateur ci-dessous
complète cette mesure avec un serveur, des données et un compte de test
reproductibles.

### État du harness navigateur

Le navigateur intégré a été sollicité le 17 juillet 2026, mais aucun moteur
n'était exposé à la tâche d'automatisation malgré l'ouverture de l'onglet. Le
fallback Playwright explicitement autorisé est donc devenu le harness
reproductible du dépôt :

- Chromium desktop, viewport 1 440 × 1 000 ;
- Chromium avec émulation iPhone 13 ;
- compte local non-administrateur dédié ;
- scénario invité : rendu du login, focus initial et erreur d'identifiants ;
- scénario authentifié : login, accueil puis navigation chaude vers Fonds ;
- collecte des timings Navigation API, poids des ressources, LCP, INP et longues
  tâches ;
- détection des erreurs console, débordements horizontaux racine et règles axe
  WCAG 2 A/AA.

La commande `npm run test:e2e` exécute quatre scénarios. Le relevé après
Laravel 13 est réussi en 10,0 s sur l'hôte de développement, sans erreur
JavaScript pertinente, sans débordement horizontal de page et sans violation
axe.

### Mesures navigateur initiales

Ces mesures de laboratoire sont un point de comparaison, pas une promesse de
production. Elles varient avec la machine, le réseau, le cache et les données.

| Scénario | DCL | Load | Réponse | Ressources transférées | Longues tâches |
| --- | ---: | ---: | ---: | ---: | ---: |
| Login desktop | 120 ms | 180 ms | 41 ms | 416 255 octets | 0 |
| Accueil authentifié desktop | 422 ms | 495 ms | 404 ms | 405 493 octets | 0 |
| Login mobile émulé | 135 ms | 290 ms | 34 ms | 416 255 octets | 0 |
| Accueil authentifié mobile émulé | 407 ms | 451 ms | 391 ms | 484 975 octets | 0 |

La navigation chaude Accueil → Fonds prenait 218 ms sur desktop et 268 ms sur
mobile émulé dans la baseline initiale.

Le harness observe désormais `largest-contentful-paint` et les interactions de
l'Event Timing API. Il applique les seuils Web Vitals de 2 500 ms pour LCP et
200 ms pour INP. Ce sont des garde-fous de laboratoire ; la décision produit
finale devra aussi utiliser le 75e centile de données terrain, séparé entre
desktop et mobile.

| Scénario Laravel 13 | LCP | INP observé | Navigation chaude |
| --- | ---: | ---: | ---: |
| Login desktop | 624 ms | non applicable, aucune interaction mesurable avant lecture | — |
| Accueil desktop | 540 ms | — | — |
| Fonds desktop | même document, LCP 540 ms | 24 ms | 352 ms |
| Login mobile émulé | 144 ms | non applicable | — |
| Accueil mobile émulé | 484 ms | — | — |
| Fonds mobile émulé | même document, LCP 484 ms | 32 ms | 321 ms |

La navigation partielle conserve le même document : le LCP de Fonds reste donc
celui de l'accueil. L'INP mesure l'interaction de navigation et non la durée
totale de la requête réseau.

### Baseline accessibilité navigateur

Le premier passage a révélé une violation critique sur mobile : le bouton du
menu compte perdait son nom accessible lorsque son texte visuel était masqué.
Le shell fournit désormais un `aria-label` stable et le contrat est couvert par
un test PHP.

La dette axe de contraste a été corrigée à sa source dans les tokens kView :

- `--text-secondary` devient `#45669a` ;
- `--text-muted` devient `#5c7291` ;
- `--accent-600` et `--info-fg` deviennent `#0b659f` ;
- le dernier littéral de texte atténué consomme maintenant le token partagé.

`TokenAccessibilityTest` calcule les ratios des couples texte/fond critiques et
impose WCAG AA à 4,5:1. Les quatre rapports axe du parcours Laravel 13 — login
et Fonds, desktop et mobile — contiennent zéro violation.

## 8. Décisions de phase 0

### D0-01 — Architecture adoptée

La roadmap Laravel + Inertia + Vue + TypeScript + kView est adoptée comme
direction. Il s'agit d'une migration route par route, pas d'une réécriture.

### D0-02 — Blade reste supporté

Blade reste la racine serveur d'Inertia, la technologie des écrans non migrés
et une API publique kView tant que des consommateurs Blade existent.

### D0-03 — Gel du routeur partiel historique

`ui-page-loading.js` peut recevoir des corrections de sécurité, accessibilité,
compatibilité ou régression. Il ne reçoit plus de nouvelle fonctionnalité
produit ni de nouvel initializer sans décision d'architecture explicite.

### D0-04 — UUID de `RayDocImport`

Les nouveaux `RayDocImport` ciblent UUIDv7 à partir du jalon Laravel 12.

Raisons : les imports sont naturellement chronologiques, UUIDv7 est triable et
devient le comportement de `HasUuids` dans Laravel 12. Les UUIDv4 déjà stockés
restent valides et ne seront pas réécrits. Le passage sera couvert par un test
de version d'UUID pendant la phase 1. Les autres modèles utilisant le trait
historique `LncShared\\...\\Uuids` ne changent pas dans ce chantier frontend.

### D0-05 — Premier pilote

Le Component Lab a reçu d'abord le montage technique Vue/kView. `/search`, et
non `/status` qui est une redirection, a ensuite été retenue comme première
route produit. Les phases 3 et 3.5 ont confirmé sa faisabilité avec un shell
local, un adaptateur de liens explicite, `SearchResultGroup` et une baseline
Blade testée. La phase 4 a réalisé la migration et la mesure avant/après.

### D0-06 — Pas de suppression par anticipation

Une vue Blade, un module vanilla ou un composant kView n'est supprimé qu'après
parité fonctionnelle, visuelle, accessible et mesurée de son remplaçant.

### D0-07 — Seuils de non-régression du pilote

À environnement comparable, une migration de page est bloquée si elle :

- introduit une violation axe critique ou une erreur console pertinente ;
- introduit un débordement horizontal de la page ;
- augmente les octets transférés de plus de 10 % sans justification ;
- augmente un temps de chargement ou de navigation de plus du maximum entre
  20 % et 100 ms sans justification ;
- introduit une longue tâche d'au moins 50 ms là où la baseline n'en avait pas ;
- perd un comportement clavier, focus, retour navigateur ou responsive couvert.

Une variation justifiée est documentée dans la pull request avec la mesure avant
et après. Le harness bloque aussi un LCP supérieur à 2 500 ms et un INP
supérieur à 200 ms ; ces limites locales complètent, sans remplacer, une future
collecte au 75e centile en production.

## 9. Critères de sortie de la phase 0

- [x] adopter la décision d'architecture ;
- [x] inventorier les routes, moteurs de rendu, modules et composants ;
- [x] consigner la baseline tests, Pint, PHPStan et build ;
- [x] consigner les parcours critiques ;
- [x] décider UUIDv7 pour les nouveaux `RayDocImport` à partir de Laravel 12 ;
- [x] geler automatiquement l'extension de `ui-page-loading.js` ;
- [x] utiliser Playwright lorsque le navigateur intégré n'est pas exposé ;
- [x] créer les premiers smokes login/navigation desktop et mobile ;
- [x] préparer des données et un compte navigateur reproductibles ;
- [x] capturer les timings de chargement, la navigation chaude, les longues
  tâches et le responsive ;
- [x] couvrir le token protocole, le password grant, le refresh et sa révocation Passport ;
- [x] définir les seuils locaux de non-régression ;
- [ ] exécuter le smoke avec un client Passport réel sur la préproduction avant
  de promouvoir Laravel 13 en production ;
- [x] ajouter LCP et INP au harness local avec les seuils Web Vitals.

La phase 1 locale est terminée : les tests backend critiques, la montée Laravel
13 et la baseline navigateur sont reproductibles. La validation d'un client
Passport réel reste une porte de promotion UAT vers production. Elle est
automatisée et documentée, mais elle nécessite les secrets externes au dépôt.

## 10. Vérification après les premiers garde-fous

Après l'ajout du gel du routeur historique et des tests Passport :

| Contrôle | Résultat |
| --- | --- |
| Suite PHP complète | 104 tests réussis, 726 assertions, 4,22 s |
| Garde-fou navigation partielle | réussi |
| Token protocole et Passport | 3 tests réussis, 24 assertions |
| Pint sur les nouveaux tests | réussi |
| Composer | configuration valide |
| Diff | aucune erreur d'espace détectée |

## 11. Checkpoint de phase 1 — Laravel 12

Le 17 juillet 2026, le premier palier backend de la roadmap a été appliqué sans
introduire Vue, Inertia ni changement de moteur frontend.

| Contrôle | Résultat Laravel 12 |
| --- | --- |
| Framework | Laravel 12.64.0 |
| Suite PHP complète | 105 tests réussis, 731 assertions, 5,96 s |
| Passport et `ProtocolGrant` | réussis |
| UUID `RayDocImport` | UUIDv7 vérifié pour les nouveaux enregistrements |
| Routes nommées | uniques ; API sous `api.v1.*` |
| Cache de routes | création et suppression réussies |
| Packages kView | consommateurs propres Laravel 11.55 et 12.64 réussis |
| PHPStan | 137 erreurs, identique à la baseline |
| Build Vite | réussi ; JS stable, CSS applicatif 204,17 kB |
| Playwright | 4 scénarios réussis en 8,0 s |
| Audit Composer | aucune vulnérabilité connue |

Les mesures après upgrade restent sous les seuils définis :

| Scénario | Load après upgrade | Écart | Navigation chaude après upgrade | Écart |
| --- | ---: | ---: | ---: | ---: |
| Desktop | login 224 ms ; accueil 503 ms | +44 ms ; +8 ms | 235 ms | +17 ms |
| Mobile émulé | login 181 ms ; accueil 472 ms | -109 ms ; +21 ms | 300 ms | +32 ms |

Le contrôle large a révélé une particularité de déploiement : les vues
compilées par Laravel 11 conservent l'ancien hash des namespaces de composants
Blade anonymes. `php artisan view:clear` a restauré immédiatement les rendus et
doit faire partie du déploiement de l'upgrade. Les fichiers source kView n'ont
pas nécessité d'adaptation.

Ce palier reste le checkpoint de retour intermédiaire entre Laravel 11 et 13.

## 12. Checkpoint de phase 1 — Laravel 13

Le 17 juillet 2026, le second palier backend a été validé localement sans
modifier le moteur frontend.

| Contrôle | Résultat Laravel 13 |
| --- | --- |
| Framework | Laravel 13.20.0 |
| Outillage PHP | Tinker 3.0.2 et PHPUnit 12.5.31 |
| Suite PHP complète | 111 tests réussis, 748 assertions, 4,99 s |
| Passport et `ProtocolGrant` | réussis, y compris password grant et refresh |
| Smoke UAT | commande et test automatisé prêts ; exécution réelle en attente des secrets UAT |
| PostgreSQL local | 16.14 ; toutes les migrations appliquées |
| Cache Laravel | routes, vues et configuration construits puis supprimés avec succès |
| Protection du cache | `serializable_classes=false` |
| Packages kView | consommateurs propres Laravel 11.55, 12.64 et 13.20 réussis |
| Pint | fichiers modifiés réussis ; dette globale historique ramenée à 133 fichiers |
| PHPStan | 137 erreurs, identique à la baseline |
| Build Vite | réussi ; CSS 198,57 kB, JS 112,01 kB |
| Playwright | 4 scénarios desktop/mobile réussis en 10,0 s |
| Accessibilité | zéro violation axe sur les quatre rapports ; tokens WCAG AA testés |
| Performance | LCP maximal 624 ms ; INP maximal observé 32 ms ; zéro longue tâche |
| Audit Composer | aucune vulnérabilité connue |

Le guide Laravel 13 a été contrôlé point par point. kView INVESTOR ne référence pas
les anciens alias de middleware CSRF, ne fournit pas de store de cache ou de
queue personnalisé, n'utilise pas d'`upsert` avec clé vide et possède sa propre
vue de pagination. Les noms de préfixe Redis et de cookie UAT sont explicites.

La commande `php artisan kview_investor:verify-uat` est la porte opérationnelle
restante. Elle vérifie PostgreSQL, les migrations, le client Passport, le
password grant, un endpoint bearer, le refresh puis révoque les jetons créés.
Voir `dev_guide/uat-smoke-check.md`.

## 13. Checkpoint de phase 4 — pilote `/search`

Le 17 juillet 2026, `/search` est devenue la première route produit Inertia.
`SearchController@index` rend `Search/Index` avec seulement `query`,
`searchUrl` et des groupes de résultats normalisés. Les modèles Eloquent ne
traversent pas directement la frontière Laravel/Vue.

À ce checkpoint, la route utilisait `inertia-dashboard.blade.php`, qui étendait
le dashboard Blade historique. Blade conservait l'unique topbar, l'unique
sidebar, la recherche globale et les actions rapides ; Vue possédait seulement
la carte marquée `[data-frontend-owner="vue"]`. `ui-page-loading.js` cédait à
cette frontière et n'interceptait ni ses formulaires, ni ses liens, ni son
historique. Le menu global et le champ local ne synchronisaient pas leurs
valeurs ou leurs erreurs.
Chaque résultat vers une route encore Blade restait une ancre native.

Au checkpoint de phase 4, `ApplicationShell.vue` restait le spécimen
local/testing de phase 3.5 et n'était pas composé par `/search`. Le contrat de
sidebar est identique pour le shell actuel et sa future migration : ouverte à
`240px` ou cachée à `0`, jamais sous forme de rail compact.

La référence Blade a été isolée au commit `b276b8a`. Après capture de cette
baseline, parité et validation du remplacement, la vue
`resources/views/search/index.blade.php` a été supprimée. Le commit permet de
reproduire la baseline sans conserver deux implémentations actives.

### Comparaison locale à froid

Le cache navigateur est vidé explicitement par CDP avant chacun des trois
chargements à froid. Le checkpoint retient leur médiane desktop finale.

| Architecture finale embarquée, desktop local | Médiane/valeur |
| --- | ---: |
| responseEnd | 25 ms |
| DCL | 63 ms |
| Load | 119 ms |
| Ressources transférées brutes | 641 468 B |
| Ressources décodées | 686 411 B |
| LCP | 108 ms |
| CLS | 0 |
| Tâches >= 50 ms | 0 |

Le harness utilise Chromium local sans throttling. Les octets sont la somme des
`PerformanceResourceTiming` des ressources secondaires ; le document HTML
principal n'est pas inclus. Le serveur PHP local ne compresse pas les assets :
le budget cold protège donc le payload brut hybride dans l'intervalle
`1..700 000 B`, avec LCP <= `2 500 ms`, CLS <= `0,1` et aucune tâche d'au moins
`50 ms`. Ces observations ne prédisent pas les percentiles production et ne
doivent pas être comparées à une mesure servie avec compression.

### Navigation chaude naturelle

| Architecture finale, desktop | Médiane | Ressources | Requêtes | CLS | Tâches >= 50 ms | INP observé |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| Visite Inertia naturelle | 76 ms | 4,2–7,7 kB | 1 | 0 | 0 | 16–24 ms |

Le délai réseau artificiel de `250 ms` utilisé par Playwright sert uniquement
à rendre visible et testable l'état de chargement. Les artefacts
`search-warm-delayed` n'entrent jamais dans les échantillons naturels.

### Contrats validés

- payload minimal et typé, requête vide et résultats ordonnés ;
- liens de résultats natifs vers GP, fonds et investisseurs encore Blade ;
- soumission Inertia locale depuis le formulaire de la carte ;
- historique précédent/suivant, synchronisation de l'URL et restauration du
  champ ;
- indépendance entre le menu global de la topbar et le champ local de la carte ;
- exactement une topbar/sidebar, frontière Vue respectée par la navigation
  partielle Blade et sidebar ouverte à `240px` ou cachée à `0` ;
- remise à zéro du scroll sur une nouvelle recherche et restauration lors du
  retour historique ;
- états de chargement et erreurs réseau inline du formulaire local, sans
  effacer les résultats, puis relance réussie ;
- focus après rendu et absence de course lors d'une double soumission rapide ;
- clavier, zéro violation axe, aucune erreur console pertinente et aucun
  débordement horizontal ;
- cinq largeurs : desktop large, desktop contraint à 1 024 px, régression
  signalée à 919 px, tablette à 768 px et mobile à 390 px.
- aucun chevauchement entre recherche et compte dans la topbar à 1 024 px.

Le run final réussit 147 tests PHP et 53 tests Vitest. Le parcours Search
Playwright produit 3 passages et 1 skip intentionnel ; axe reste à zéro sur les
cinq largeurs contrôlées. Build, typecheck, lint et cache des vues sont verts.

Le test authentifié requiert
`php artisan db:seed --class=CrudDemoSeeder`, `E2E_EMAIL` et `E2E_PASSWORD`.
Sans ces variables, il peut être ignoré localement mais fait échouer la CI.

La phase 4 reste validée indépendamment du shell. Son étape suivante devait
déployer un layout persistant, sécuriser logout/session puis migrer les
fonctions globales conservées par Blade.

## 14. Checkpoint de phase 5.1 — layout persistant technique

Le 17 juillet 2026, deux routes authentifiées `local/testing` ont adopté
`AuthenticatedLayout`. Inertia remplace uniquement leur slot : Playwright
conserve un marqueur sur la même instance DOM de `ApplicationShell` et vérifie
que l'état replié de la sidebar survit à l'aller-retour. Le shell respecte aussi
le drawer mobile, le focus, axe et l'absence de débordement.

À ce checkpoint, la recherche globale de ce banc restait un `GET` natif vers `/search` afin de ne
pas traverser partiellement la racine autonome et la racine hybride Blade. Le
test navigateur confirme un vrai rechargement vers l'unique shell historique.

`/logout` accepte seulement `POST`. Blade rend un formulaire CSRF et Vue envoie
une visite protégée contre la double soumission. Logout Inertia et expiration
de session renvoient `409` avec `X-Inertia-Location` vers `/login`; une requête
native non authentifiée garde la redirection Laravel standard.

Ce checkpoint ne migrait aucune route produit supplémentaire. `/search` restait
la carte Vue de phase 4 dans le shell Blade ; à la clôture 5.1,
suggestions/actions globales, Excel Login, Settings, toasts, pré-paint sidebar
et autres routes restaient ouverts.

Le run complet réussit `152` tests PHP / `1 777` assertions et `56` tests
Vitest. Le parcours Inertia compte `11` passages et `3` skips intentionnels ;
PHPStan est sans erreur sur les fichiers 5.1 et conserve ses `136` erreurs
historiques au niveau global. La matrice Playwright complète compte `18`
passages et `4` skips intentionnels.

## 15. Checkpoint de phase 5.2 — recherche globale du shell technique

Le 17 juillet 2026, le banc persistant a reçu le propriétaire Vue de la
recherche globale sans toucher au shell produit. Laravel sérialise désormais
`searchSuggestUrl`, trois presets et trois actions par défaut via
`ApplicationNavigation`. `GlobalSearchConfiguration` est également consommé
par `SearchController`, ce qui garde une seule définition serveur des actions
et de leurs URLs.

`ApplicationGlobalSearch` réutilise `/search/suggest`, conserve toutes les
sorties natives et n'appelle aucun runtime historique. Son panneau est
téléporté dans `body`, collisionné sur desktop/mobile et relié à une vraie
combobox par listbox, options et `aria-activedescendant`. Les requêtes sont
debouncées, annulées et invalidées immédiatement ; une nouvelle saisie retire
également l'ancienne sélection et ses liens avant le prochain résultat. Escape,
focus/clic extérieur, viewport visuel mobile et démontage nettoient le cycle de
vie.

Les 17 tests PHP ciblés et les 12 tests Vitest du composant/shell réussissent.
Le run complet compte `153` tests PHP / `1 797` assertions, `60` tests Vitest
et `11` passages du parcours Inertia pour `3` skips intentionnels. Typecheck,
ESLint et build sont verts. Chromium passe en desktop et mobile avec panneau
ouvert et peuplé, navigation clavier, axe sans violation, collision dans le
viewport, persistance du shell et absence de débordement horizontal.

La frontière produit ne change pas : `/search` conserve sa topbar globale
Blade indépendante de la carte locale Vue. Le cutover, Excel Login, Settings,
toasts et pré-paint sidebar restaient alors les étapes suivantes.

## 16. Checkpoint de phase 5.3 — surfaces globales du shell technique

Le 18 juillet 2026, le banc persistant a porté les toasts globaux, Excel Login
et le menu utilisateur complet. Avant le portage, un nouveau parcours
Playwright a figé le comportement Blade : pile de notifications, protocole
Excel mocké, modale Settings, Teleport, Escape et restitution du focus. Il
reste volontairement actif comme test de compatibilité du shell produit.

Le package `kview/ui-core` expose désormais `KviewToastProvider`,
`useKviewToast`, `KviewPopover` et `KviewAvatar`. Vue possède chaque cycle de
vie sans hook `data-ui-*`, sans `window.kviewToast` et sans
`window.kviewFloating`. Laravel fournit l'avatar privé cache-busté et les URLs
User Settings, Data Status, Workspace et Excel ; les liens Settings du shell
technique restaient alors des navigations natives vers le fallback Blade.

Excel conserve exactement le contrat historique : une requête partagée,
pending commun, timeout, en-têtes same-origin, toasts et URL `lncom://`
encodée. Le popover compte est directement téléporté dans `body`, collisionné,
fermé par Escape ou clic extérieur avec la politique de focus attendue, et
contient avatar, identité, Workspace, User Settings, Data Status, Excel et
logout `POST`.

La validation réussit `156` tests PHP / `1 869` assertions, `17` fichiers
Vitest / `75` tests, typecheck, ESLint, build, Pint et PHPStan ciblé. La matrice
Playwright complète compte `24` passages et `6` skips intentionnels sur desktop
et mobile. Les packages archivés sont consommés avec succès depuis des
applications propres Laravel 11, 12 et 13, et le manifeste de release est
cohérent. Aucune route produit n'est basculée : Settings restait le lot suivant,
puis le pré-paint sidebar et le cutover `/search`.

## 17. Checkpoint de phase 5.4 — Settings Vue comparable à Blade

Le 18 juillet 2026, `ApplicationSettingsDialog` a porté Account, Preferences,
Workspace, Integrations, System et l'onglet Configuration réservé aux
administrateurs dans le shell Inertia technique. Le portage ne supprime aucune
vue : chaque onglet affiche un lien « Compare Blade » vers
`/preferences?tab=<onglet>`, et les liens Settings restent de vraies ancres
pour les clics modifiés ou les sorties natives.

`App\Support\ApplicationSettings` constitue l'unique présentateur serveur. Le
contrôleur envoie son contexte à `user_config.edit` pour Blade ou une
sérialisation JSON sûre pour Vue lorsque les en-têtes modale/JSON sont
explicites. Onglets, permissions, options, statuts et URLs ne sont donc pas
maintenus deux fois. Les endpoints d'écriture restent identiques ; Vue ajoute
les erreurs inline `422`, le pending, l'annulation, les toasts et le refresh des
props partagées.

Le package expose `KviewDialog` et `KviewDropdown`. Reka UI 2.10.1 fournit
uniquement leurs mécaniques invisibles de dialog et listbox ; les panels
kView INVESTOR importent l'API kView et conservent tous les styles/tokens existants.
La suite PHP complète passe `158` tests / `1 919` assertions. Typecheck,
ESLint, Vitest complet (`19` fichiers / `81` tests), build Vite,
`composer validate`, `test:ui-release` et `test:ui-consumer` sont verts. Le
parcours Settings Playwright desktop et mobile confirme le JSON Vue, la
comparaison Blade HTML, la restitution du focus et `Ctrl/Cmd+K`, le dropdown, la confirmation imbriquée
et axe sans violation sur les écrans contrôlés.

Le premier consommateur d'archive a exposé une résolution implicite des peers
de l'entrée Vue qui ne fonctionnait que dans le monorepo. `kview/ui-core`
publie désormais `vue` et `reka-ui` dans ses `peerDependencies`, et le fixture
propre les résout depuis le host. Les consommateurs Laravel 11, 12 et 13 sont
verts. Un consommateur Blade-only n'importe pas cette entrée facultative et ne
charge donc ni Vue ni Reka.

## 18. Clôture de phase 5 — shell produit persistant

Le 18 juillet 2026, `/search` a quitté la racine hybride de phase 4 pour la
racine standard `inertia.blade.php`. `Search/Index` déclare
`AuthenticatedLayout` : une même instance de `ApplicationShell` conserve la
sidebar, la topbar, la recherche globale, Excel Login, le compte, les toasts et
Settings pendant que seul le slot de page est remplacé. Les fichiers
`inertia-dashboard.blade.php`, `inertia-dashboard.ts` et
`inertia-dashboard.css`, ainsi que leur entrée Vite, sont retirés.

Les deux racines applicatives incluent avant leurs assets le même bootstrap
synchrone de préférences. Il restaure la préférence desktop ouverte à `240px`
ou masquée à `0` dès le premier paint ; le drawer mobile reste un état modal
transitoire qui n'écrase jamais cette préférence.

La recherche globale suit un lien marqué `inertia: true` seulement si son hôte
active aussi `useInertia`. Le shell produit active ce mode pour `/search` et
ferme/invalide le panneau téléporté avant la visite. Les créations rapides,
résultats et autres destinations encore Blade restent des ancres natives. Une
entrée depuis Blade charge donc une fois la racine Inertia complète ; les
recherches suivantes conservent le shell, et une sortie métier recharge le
document Blade.

`#application-content` est la région de scroll Inertia. Le shell expose
`aria-busy` au départ d'une visite pertinente ; un skeleton structurel limité
au contenu n'apparaît qu'après `120 ms` et seulement si le pathname change.
Les recherches same-path gardent les résultats existants, prefetch et
`showProgress: false` sont ignorés, aucun second progress bar n'est ajouté et la
view transition ne concerne que le contenu avec un fallback reduced-motion.

La clôture est validée par `159` tests PHP / `1 960` assertions, `19` fichiers
Vitest / `86` tests, typecheck, ESLint, build Vite, PHPStan ciblé, validation
Composer, manifeste de release et consommateurs propres Laravel 11, 12 et 13.
La matrice Playwright complète passe `29` scénarios réussis, avec `7` skips
intentionnels sur desktop/mobile et axe reste sans violation sur les surfaces
contrôlées.
La médiane cold du root persistant est `526 709 B` transférés, avec LCP
`84 ms` desktop / `72 ms` mobile, CLS `0` et aucune tâche longue. La visite
Inertia naturelle médiane mesure `144 ms` desktop / `95 ms` mobile dans le
harness Chromium local non compressé.

Cette clôture migrait historiquement le shell de la première route Inertia, pas
toutes les pages. Depuis, `/activity`, les consultations/formulaires de phase 6
et les sept index de phase 7 utilisent aussi ce shell. Imports, dashboards et
les autres routes non migrées restent dans le shell Blade jusqu'à leur portage
incrémental.

## 19. Checkpoint de phase 6.1 — activité

Le 19 juillet 2026, `/activity` est devenue la deuxième route produit de la
racine Inertia standard. `Activity/Index` réutilise `AuthenticatedLayout` et
compose `ActivityFeed` avec un payload Laravel dédié : aucune sérialisation
brute de modèle, Carbon ou paginator n'est exposée au navigateur.

Le serveur conserve la normalisation des filtres, leurs compteurs, le tri, la
déduplication, l'historique consulté en session, les libellés temporels et la
pagination à 25 éléments. Les filtres et pages utilisent Inertia et conservent
l'identité du shell ; Home et les fiches métier restent des navigations natives
vers Blade. `AppLink` transmet désormais les politiques `preserveState` et
`preserveScroll` uniquement à sa branche Inertia.

L'ancienne vue `activity.index` a été supprimée après recherche des
consommateurs et validation navigateur. Le composant Blade des dernières mises
à jour reste présent pour la Home. Le CSS du feed et des panneaux dashboard a
un propriétaire commun chargé par Blade et Inertia ; la composition propre à
Activity reste isolée dans `activity.css`.

Les preuves couvrent le contrat PHP, les composants Vue, le typecheck, ESLint,
le build, la persistance du shell, le clavier, l'historique, les sorties natives,
desktop/mobile et axe. Le contrôle a détecté puis corrigé le contraste du
compteur du filtre actif. La CI crée aussi explicitement son compte Playwright
administrateur afin que les scénarios Settings soient réellement exécutables.
Le badge de statut passe par le nouvel adaptateur public
`@kview/visualization/vue` et son CSS `metrics` ciblé. Le checkpoint complet
passe `168` tests PHP / `2 130` assertions, `22` fichiers Vitest / `93` tests et
`32` scénarios Playwright, avec `8` skips intentionnels sur desktop/mobile.

## 20. Lot de phase 6.2 — détail des taux de change

Le 19 juillet 2026, `ExchangeRateController@show` a été porté vers
`ExchangeRates/Show` dans le même `AuthenticatedLayout`. Le contrôleur expose
uniquement la paire et cinq cartes de présentation (`From`, `To`, `Rate`,
`Date`, `Source`) ; `FinanceFormatter` reste le propriétaire serveur du nombre
et de la date. Aucun modèle, Carbon ou formulaire brut n'est sérialisé.

Le rendu Vue reproduit la fiche Blade avec `KviewCard`, le variant `detail` de
`KviewPageHeader` et `KviewInfoCard`. Ces contrats ont été ajoutés aux packages
plutôt que copiés dans la page. `KviewMetricTrend` complète l'entrée publique de
visualisation, et `KviewConfirmDialog` fournit l'`alertdialog` destructif avec
Cancel initial, Escape/backdrop, pending et restitution du focus.

La frontière CRUD reste intentionnellement hybride. Back et Edit sont des
navigations natives vers l'index et l'édition Blade. Delete conserve le vrai
formulaire Laravel, le CSRF et `_method=DELETE`, puis le redirect/flash natif
vers l'index. Les entrées depuis les vues Blade désactivent explicitement la
navigation partielle historique afin de charger la racine Inertia une seule
fois. L'ancienne vue `exchange_rates.show` est retirée.

Les tests du contrôleur, de la page et des primitives protègent le payload, les
cinq cartes, les frontières natives, le cycle create/update vers Inertia et la
confirmation. La comparaison Playwright desktop/mobile couvre aussi la
géométrie, les marges et le backdrop du dialogue, Escape, le focus, axe et la
console. Le checkpoint global passe `174` tests PHP / `2 243` assertions,
`25` fichiers Vitest / `105` tests et `35` scénarios Playwright, avec `9` skips
responsive intentionnels ; le consommateur archive Laravel 13 valide les
nouveaux exports Vue et l'entrée CSS `cards`.

## 21. Clôture des lots 6.3 à 6.5

Les consultations Call/Distribution et Capital Account, les formulaires CRUD
simples, puis les fiches et formulaires Funds, General Partners, Investors et
Investments utilisent désormais la racine Inertia persistante. Les wrappers de
page restent minces : les payloads Laravel possèdent les règles métier et les
formatters, tandis que `BusinessFormPage`, `FinancialRecordPage`,
`PortfolioRecordPage` et les entrées publiques kView possèdent la composition
Vue réutilisable.

Les anciennes vues Blade `show`, `create`, `edit` et `_form` remplacées ont été
retirées. À ce checkpoint, les index Blade réels de Calls/Distributions et
Capital Accounts avaient été conservés, comme ceux des autres entités, afin de
ne pas masquer la pagination et les commandes ERP avant leur portage en phase
7. Les créations
Investment imbriquées depuis un Investor ou un Fund, les suppressions avec
retour contextuel, les images dynamiques, les erreurs Laravel associatives des
alias et les relations UUID sont couvertes comme contrats explicites.

La fermeture qualité couvre la suite PHP complète, les composants Vue, le
typecheck, ESLint, le build Vite, Pint et PHPStan sur les fichiers modifiés, les
archives consommatrices Laravel 11/12/13, puis Playwright desktop/mobile et axe.
La validation locale finale du 19 juillet 2026 passe `204` tests PHP / `4 176`
assertions, `35` fichiers Vitest / `152` tests et `38` scénarios Playwright,
avec `12` skips responsive intentionnels. TypeScript, ESLint, Vite, Pint,
PHPStan et les trois consommateurs propres sont verts. Ces compteurs complètent
les mesures historiques consignées dans les checkpoints précédents sans les
réécrire.

## 22. Checkpoint d'implémentation de phase 7.11–7.12

Le 20 juillet 2026, le moteur public `KviewCrudTable` est connecté aux sept
index de production. Les routes GPs, Funds, Investors, Investments,
Calls/Distributions et Capital Accounts rendent la page mince `Business/Index`;
Exchange Rates rend `ExchangeRates/Index` afin d'ajouter la synchronisation ECB
et Settings dans le slot d'actions du header commun. Toutes déclarent
`AuthenticatedLayout` et conservent l'instance du shell pendant les visites
same-root.

La frontière est commune : `BusinessIndexPayload` sérialise les colonnes et
cellules présentées, les routes, previews, confirmations, libellés et la
pagination ; `AbstractIndexListQuery` et une `*ListQuery` par ressource
whitelistent recherche, tri et filtres texte/nombre/date/multiselect. Le host
`BusinessIndexPage` ne possède que les visites Inertia partielles et les
formulaires Laravel natifs de suppression. Les suppressions Investment,
Call/Distribution et Capital Account venant d'un index utilisent
`return_index=1` pour conserver le retour contextuel.

Les sept vues `index.blade.php` historiques ne servent plus ces routes et ont
été supprimées après preuve de non-consommation et gate navigateur. Les
composants publics `x-erp.crud-table` et `x-smart-table`, leurs
registres, styles, modules et traductions restent supportés pour les packages
kView et les autres applications Blade.

Le gate agrégé du 20 juillet 2026 passe `224` tests PHP / `5 359` assertions,
`37` fichiers Vitest / `179` tests et `55` scénarios Playwright, avec `23`
skips de projets responsive intentionnels et aucun échec. Pint et PHPStan sur
les fichiers modifiés, TypeScript, ESLint, build, manifeste de release,
Composer et consommateurs Laravel 11/12/13 sont verts. Les parcours couvrent
les sept routes, la recherche, les filtres multiselect/date, la pagination, la
sélection, l'export, la preview, la confirmation, Escape/focus, le row tap
mobile, les actions Exchange Rates et le retour après suppression.

## 23. Références de mesure

- Guide de migration Laravel 13 : <https://laravel.com/docs/13.x/upgrade>
- LCP : <https://web.dev/articles/lcp?hl=fr>
- INP : <https://web.dev/articles/inp?hl=fr>
