SPB Git forge

spb/vrai-prix

Public

Vrai-Prix — l'évaluation du vrai prix des propriétés résidentielles au Québec.

60commits 1branches 0releases
12.3 MBsize
maindefault branch
17 days agolast push
TypeScript 90.2% JavaScript 3.5% Python 3.4% CSS 1.9% HTML 0.6%
11.2 KB

# 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

text
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)

text
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 ·
  2. Main-d'œuvre APCHQ (+ CCQ stub) · 6. StatCan · 7. Détaillants Firecrawl ·
  3. Benchmarks · 9. UI /cout · 10. Intégration propriété · 11. Dépréciation ·
  4. Sources/audit · 13. PDF · 14. Ka · 15. Admin · 16. Tests, mobile, FR/EN ·
  5. 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.