================================================================================ RE-QA — Redmine #21 (epic) — Enhance Matching Results & AI Assistant with Company Enrichment and Market Insights Projet : GetYourJob (id 11) PR #239 (base dev) branche feat/redmine-21-insights-ui Commit du correctif : 549534e (fix i18n collision marketInsights) Date : 2026-06-11 Statut entrant : In development -> draggé en QA avant tests ================================================================================ OBJET DE LA RE-QA Vérifier que la régression i18n bloquante (collision de clé top-level `marketInsights:` introduite par #66) est levée, ET que les 3 surfaces de l'épic restent fonctionnelles (#64 carte entreprise, #66 section Tendances, #67 assistant). Déclencheur d'échec dur : NO-FAKE-DATA. ENVIRONNEMENT Worktree : .worktrees/redmine-21-insights-ui (node_modules + .env présents) npx prisma generate : OK DB Postgres port 5436 : UP App dev : npm run dev -- -p 3013 (Next.js 16.0.10 Turbopack, Ready) (toutes les valeurs sensibles — env/clés/tokens/DB URL — filtrées de ce rapport) -------------------------------------------------------------------------------- AC1 — RÉGRESSION i18n CORRIGÉE (le bloqueur) ===> OK -------------------------------------------------------------------------------- 1a. Exactement UNE clé top-level `marketInsights:` par fichier de locale : en.ts -> ligne 2771 (page Statistiques) + marketInsightsSection: l.3114 (#66) fr.ts -> ligne 2780 (page Statistiques) + marketInsightsSection: l.3123 (#66) Le nouveau bloc #66 est bien renommé `marketInsightsSection:` (plus de doublon). 1b. tsc --noEmit — TS1117 dans en.ts / fr.ts : grep "translations/(en|fr).ts" sur la sortie tsc => ZÉRO erreur. Seul TS1117 restant : src/scripts/cron-geocode-jobs.ts(66,9) — fichier NON touché par cette branche (pré-existant, hors scope). Confirmé via `git diff --name-only de4b286~1 HEAD` (cron-geocode absent du diff). 1c. Résolution runtime des deux namespaces (import { en, fr } from '../index') : EN marketInsights.title = "Market Statistics" (page restaurée) EN marketInsights.tabs = object (n'est plus undefined) EN marketInsights.kpi = object (n'est plus undefined) EN marketInsights.compensation = object (n'est plus undefined) FR marketInsights.title = "Statistiques Marché" (page restaurée) FR marketInsights.tabs = object FR marketInsights.kpi = object EN marketInsightsSection.title = "Market insights" (distinct) FR marketInsightsSection.title = "Tendances du marche" (distinct) => section != page : les deux namespaces résolvent séparément. 1d. Test garde-fou (anti-récidive) : src/infrastructure/i18n/translations/__tests__/marketInsights-namespaces.test.ts => 5 tests PASS. 1e. Rendu LIVE de la page précédemment cassée /profile/developer/market-insights (port 3013) : - En-tête rendu : "Statistiques Marché" (libellé résolu, PAS la clé brute `marketInsights.title`, PAS "undefined"), sous-titre + état de chargement "Analyse du marché en cours...". - Nav latérale : "Statistiques Marché" sous "Insights". - Aucune clé brute `marketInsights.*` / `marketInsightsSection.*` ne fuit dans le texte de la page (grep sur le DOM => NONE). - Console navigateur : aucune erreur i18n / undefined. - Page authentifiée au-delà de l'en-tête (OAuth Google/LinkedIn) ; le contenu des graphes nécessite un login prod impraticable en QA -> preuve i18n via en-tête rendu + test de résolution runtime déterministe. Capture : qa-reqa-21-market-statistics-page.png -------------------------------------------------------------------------------- AC2 — SECTION MARKET INSIGHTS (#66 / #61 / #63) ===> OK -------------------------------------------------------------------------------- - MarketInsightsSection.tsx : 100% des t(...) utilisent `marketInsightsSection.*` (title, skillsTitle, locationTitle, workModeTitle, offersCount, topLocation, workModeShare, loading, error, retry, empty) — aucun `marketInsights.*` nu. - Sous-blocs : compétences demandées (compteurs réels par offre), localisation (phrase tendance), mode de travail (part %). Empty -> EmptyState "Aucune tendance disponible..." (jamais de chiffre par défaut). NO-FAKE-DATA OK. - Suites : MarketInsightsSection.test.tsx (5) + route.test.ts (8) + MarketInsightsService.test.ts (11) => PASS. -------------------------------------------------------------------------------- AC3 — CARTE #64 + ASSISTANT #67 (régression-check) ===> OK -------------------------------------------------------------------------------- - #64 CompanyEnrichmentCard.test.tsx (5) PASS : rend seulement les champs présents (jamais "N/A"), return null sans enrichment, lien /companies/. - #67 SendAssistantMessageUseCase.prompt.test.ts (4) + assistantCompanyAndInsights.test.ts (5) PASS : outils get_company_data / get_market_insights déclarés + implémentés (present-only, "donnée indisponible" sinon agrégat réel), prompt skills>locations + mention type société. -------------------------------------------------------------------------------- SUITE COMPLÈTE DE L'ÉPIC -------------------------------------------------------------------------------- npx vitest run (7 suites de l'épic) : SendAssistantMessageUseCase.prompt.test.ts ... 4 PASS MarketInsightsService.test.ts ............... 11 PASS marketInsights-namespaces.test.ts ........... 5 PASS route.test.ts (api/market-insights) ......... 8 PASS MarketInsightsSection.test.tsx .............. 5 PASS CompanyEnrichmentCard.test.tsx .............. 5 PASS assistantCompanyAndInsights.test.ts ......... 5 PASS -------------------------------------------------------- Test Files : 7 passed (7) Tests : 43 passed (43) ================================================================================ VERDICT : PASS (re-QA) - Régression i18n marketInsights : CORRIGÉE (1 seule clé top-level/locale, 0 TS1117 dans en/fr, page "Statistiques Marché" résout ses libellés). - 3 surfaces de l'épic : OK. NO-FAKE-DATA : respecté partout. -> #21 LAISSÉ en QA (promotion preprod = autre agent). PIÈCES JOINTES - qa-reqa-21-rapport-technique.txt (ce rapport) - qa-reqa-21-market-statistics-page.png (page précédemment cassée, en-tête "Statistiques Marché" résolu) ================================================================================