# Vrai-Prix — Onglet « Coût » : plan technique d'implantation > Porté d'UQO Éval vers Vrai-Prix le 2026-09-08 (même socle Next 16 ; nœud M3U96a, `~/apps/vrai-prix`). Les chemins et noms de processus ci-dessous sont ceux de Vrai-Prix. > Rédigé le 2026-09-06 après audit complet du dépôt. Ce document décrit ce qui > existe, ce qui est ajouté, les sources de données réellement accessibles et > l'ordre de réalisation. Il est la référence de la fonctionnalité « Méthode du > coût » et de l'analyse multimodale des annonces « À vendre ». ## 1. Audit du dépôt (état au 2026-09-06) | Aspect | Constat | |---|---| | Framework | Next.js 16.3 (App Router, React 19, React Compiler lint), TypeScript strict, Tailwind v4 | | Backend | Route handlers Node (`src/app/api/*`), aucune couche serveur séparée | | Bases | SQLite via `better-sqlite3` : `data/vraiprix.db` (3,75 M unités MAMH + 745 k ventes, `src/lib/db.ts`), `data/immoka.db` (70 k annonces à vendre + table `vp_eval`, `src/lib/immoka.ts`) | | UI | Design « terminal éditorial » Vrai-Prix : tokens `--accent` (rouge signal), classes `.kicker .klabel .btn .vp-card .src-table .kv-cell`, `useLang()` FR/EN (`LangContext`), sections numérotées `01 —` | | Navigation | `HeaderNav.tsx` (desktop + menu mobile CSS), `MobileTabBar.tsx` (KaTabbar 6 onglets), `FooterNav.tsx`, `sitemap.ts` | | Traduction | Dictionnaire `src/lib/i18n.ts` + libellés inline `fr ? … : …` dans les composants | | PDF | `pdfkit` (`src/lib/report*.ts`), polices dans `assets/fonts`, logo Vrai-Prix, format Lettre | | Propriété | `getUnit(id)` → `UnitRow` (aire_etages_m2, nb_etages, année, valeur_terrain, valeur_batiment, valeur_role, lat/lng, municipalite, genre_construction, lien_physique, cubf) ; `estimateByUnitId` → hédonique + comparables | | Annonces | `getListing(uid)` → photos (`images` JSON), description, `details` JSON, caractéristiques, `eval.unit_id` (jumelage MAMH), `vp_eval` (est, model_est, comps_est, cost_est calibré, role_est) | | Ka | `src/lib/ka/tools.ts` (`KA_TOOLS` + `runKaTool`), boucle agentique SSE dans `src/app/api/ka/route.ts` (Haiku 4.5) | | Anthropic | `@anthropic-ai/sdk` déjà installé, `ANTHROPIC_API_KEY` dans `.env.local` (laptop et nœud) | | Tests | vitest (`src/**/*.test.ts`), moteur d'estimation testé | | Déploiement | Source laptop `~/Desktop/vrai-prix` → rsync staging M1M32 → `mld deploy vrai-prix --node M2U64` (hook post_sync `npm run build`), PM2 `vrai-prix` :8150, ngrok www.vrai-prix.app | Aucune table de coûts, aucun connecteur web, aucun vector store n'existait. ## 2. Sources externes — faisabilité vérifiée (tests du 2026-09-06) | Source | Accès testé | Statut licence retenu | Rôle | |---|---|---|---| | **APCHQ** — grilles « Coût horaire de la main-d'œuvre » (PDF publics, media.apchq.com, secteur résidentiel léger/lourd, 2023 → 26 avril 2026) | Firecrawl parse le PDF : taux horaire, vacances 13 %, avantages sociaux, AE, RQAP, FSS, CCQ, CNESST, **total employeur** par métier | `public_open` (documents publics de l'association, métadonnées + valeurs numériques, URL conservée) | **Source principale main-d'œuvre** (coût employeur complet, historisé) | | **CCQ** — salaires conventionnés | Site en incident de sécurité (services fermés jusqu'au 2026-09-08) ; page « Salaire et taux » accessible mais l'outil de taux est JS/indisponible | `public_open` | Connecteur implanté (détection de changement par hash), synchro reprendra à la remise en service ; APCHQ reflète déjà les conventions CCQ | | **Statistique Canada** — 18-10-0289-01 Indices des prix de la construction de bâtiments (Montréal, Québec RMR ; résidentiel, maison individuelle, rangée, appartements ; 23 divisions), trimestriel, dernier point 2026-T2 | API WDS ouverte (`getDataFromCubePidCoordAndLatestNPeriods`) | `public_open` (licence ouverte StatCan) | Indexation temporelle, tableau de bord « Coût aujourd'hui », validation macro | | **Canac** (canac.ca) | Firecrawl : métadonnée `product:price:amount` + unité (« / Chaque ») | `public_open` (prix affichés publiquement, robots.txt permissif) | Prix matériaux | | **BMR** (bmr.ca) | Firecrawl : `product:price:amount` (attention aux variantes « à partir de ») | `public_open` (URL SEO permises) | Prix matériaux | | **Patrick Morin** | Firecrawl : `product:price:amount` | `public_open` | Prix matériaux | | **RONA** | Cloudflare ; URL FR devinée → 404, l'URL EN de la recherche existe | `public_restricted` (à valider par connecteur, faible priorité) | Prix matériaux (si stable) | | **Home Depot Canada** | Page servie, mais magasin par défaut hors Québec (Niagara Falls) → prix non localisés | `public_restricted` | Désactivé par défaut | | **Altus Group** — Canadian Cost Guide 2026 | PDF derrière formulaire (courriel requis) | `public_restricted` → import manuel après téléchargement légal | Benchmark $/pi² (import CSV admin) | | **RSMeans / Gordian** | Licence payante | `licensed` / `manual_import` | Modèle prévu, import CSV/XLSX autorisé seulement | | **Vrai-Prix (interne)** — coût calibré du duel des méthodes (`marche-stats.json`, `vp_eval.cost_est`) | Local | interne | Benchmark de cohérence (« Trois lectures de la valeur ») | Règle : aucun prix n'est inventé. Les quantités d'assemblage, heures de productivité et pourcentages par défaut sont des **hypothèses documentées** (`source_type = assumption`, badge « hypothèse ») modifiables par l'utilisateur ; les prix de référence internes pour les articles sans observation détaillant (béton livré, fermes, fenêtres…) sont étiquetés `internal_reference` et abaissent la couverture/confiance. L'interface affiche « Donnée non disponible » plutôt qu'un nombre fictif. ## 3. Architecture ajoutée ``` src/lib/cost/ types.ts types partagés (CostInput, CostEstimate, lignes, provenance) units.ts conversion d'unités (source_unit → canonical_unit, facteur conservé) taxonomy.ts divisions MasterFormat, catégories UX, qualités, conditions, matériaux db.ts data/cost.db (schéma §4, migrations versionnées, seeds idempotents) seed/ sources, localisations, articles (~130), assemblages (~55), règles pricing.ts prix canonique par article (médiane robuste multi-source, outliers, indexation) catalog.ts accès DB : articles + prix courants, assemblages, taux, facteurs, indices, benchmarks geometry.ts moteur de quantités (empreinte, périmètre, murs, toit, fondations…) engine.ts calcul PUR et déterministe : assemblages → direct → indirect → RCN → dépréciation → valeur estimate.ts service : entrée (propriété MAMH / construction / annonce) → estimation sauvegardée connectors/ firecrawl.ts (client), apchq, ccq, statcan, canac, bmr, patrickmorin, rona, homedepot, altus, rsmeans, matching ai/ analyse multimodale des annonces (schéma JSON, prompt, images, vecteur, mapping) src/app/cout/ landing + atelier (/cout), /cout/assemblage/[code], /cout/admin src/app/api/cost/* API publique §6 src/app/api/admin/cost/* synchro, connecteurs, anomalies, mappings (jeton COST_ADMIN_TOKEN) src/app/a-vendre/[uid]/analyse-cout analyse IA d'une annonce src/app/api/listings/[uid]/* analyse IA, estimation, overrides, similaires scripts/cost-sync.ts planificateur (PM2 cron sur le nœud) : connecteurs → observations → prix canoniques prompts/property-cost-analysis-v1.md ``` Firecrawl n'est jamais appelé dans le chemin utilisateur : l'UI lit `cost.db`. ## 4. Schéma `data/cost.db` Tables (toutes avec `created_at`) : `cost_sources` (license_status), `cost_raw_observations` (historisées, `content_hash`, `parser_version`, `status`), `cost_items`, `cost_item_sources` (URL produit par détaillant, quantité par emballage), `cost_item_prices` (série temporelle canonique : matériau/main-d'œuvre/équipement, low/median/high, confiance, `price_kind` observed|derived|indexed|reference), `labour_rates` (métier, secteur, base, vacances, avantages, cotisations, total employeur, effective_from/to, source), `cost_locations` (facteurs matériau/main-d'œuvre/équipement), `construction_cost_indices`, `cost_benchmarks`, `cost_assemblies`, `cost_assembly_components`, `cost_estimates` (+ `assumptions_json`, versions méthode/base/assemblages, `cost_snapshot_date`), `cost_estimate_lines` (`calculation_json`), `cost_estimate_snapshots`, `component_condition_rules`, `connector_runs` (observabilité), `product_mappings` (matching IA à valider), `listing_ai_analyses`, `listing_ai_overrides`, `listing_images`, `property_embeddings`, `analysis_conflicts`, `ai_usage`, `cost_meta`. ## 5. Moteur (déterministe) ``` matériau_i = Q × qté_i × (1 + pertes_i) × prix_i × FacteurMatériau main-d'œuvre = Q × heures_i × taux_métier_i × FacteurMainDœuvre équipement = Q × équip_i × taux_équip × FacteurÉquipement Direct = Σ (par assemblage, regroupé en catégories UX) Indirects = Direct × Σ pct (plans, permis, assurances, gestion, financement…) Frais gén. = (Direct + Indirects) × pct ; Profit = (… + FG) × pct ; Contingence = (Direct + Indirects) × pct RCN = Direct + Indirects + FG + Profit + Contingence D_phys = âge-vie (âge effectif / vie économique) OU par composante (vie propre + condition → âge effectif) V_coût = V_terrain + RCN − (D_phys + D_fonct + D_ext) ``` Fourchette : σ par ligne (dispersion observée ou ±8 % référence / ±12 % hypothèse, heures ±15 %) combinés en racine des carrés + composante systématique (facteur régional, modèle d'assemblage 5 %) → P10/P90. Confiance 0-100 (fraîcheur 20, couverture 20, localisation 15, main-d'œuvre 15, benchmarks 10, bâtiment 20) → A-D. Invariants testés : `RCN ≥ Direct`, `valeur dépréciée ≥ 0`, `V = terrain + dépréciée`, même entrée + même instantané de prix = même résultat. ## 6. API Publique : `GET /api/cost/overview`, `/items`, `/items/[code]`, `/assemblies`, `/assemblies/[code]`, `/labour`, `/materials/history`, `/locations`, `/benchmarks`, `/sources`, `/property?id=` (préremplissage MAMH), `POST /api/cost/estimate`, `GET /api/cost/estimate/[id]`, `GET /api/cost/report?estimate=` (PDF). Admin (jeton) : `GET /api/admin/cost/connectors`, `POST /sync/[connector]`, `GET /anomalies`, `GET|POST /mappings`, `POST /benchmarks/import`. Annonces : `POST|GET /api/listings/[uid]/ai-cost-analysis`, `/reanalyze`, `PATCH /override`, `POST|GET /cost-estimate`, `GET /technical-similar`, `GET /ai-analysis-json`. ## 7. Ordre de réalisation 1. Audit (fait) · 2. Schéma + seeds · 3. Moteur pur + tests · 4. ≥ 40 assemblages · 5. Main-d'œuvre APCHQ (+ CCQ stub) · 6. StatCan · 7. Détaillants Firecrawl · 8. Benchmarks · 9. UI `/cout` · 10. Intégration propriété · 11. Dépréciation · 12. Sources/audit · 13. PDF · 14. Ka · 15. Admin · 16. Tests, mobile, FR/EN · 17. Analyse multimodale des annonces (Sonnet 5) · 18. Déploiement M2U64 via mld (cron PM2 `vrai-prix-cost-sync`, `FIRECRAWL_API_KEY` côté serveur). ## 8. Hors périmètre du MVP (phase 2/3) Vision à partir de plans, embeddings d'images, 500+ articles, localisation par municipalité fine, import RSMeans réel, entraînement de modèles.