MesDépanneurs.fr
6 domaines d'intervention · 400+ services référencés
Plomberie
Électricité
Serrurerie
Vitrerie
Chauffage
Clim & PAC
💡 Cliquez sur un service pour expand
Schéma relationnel — Configuration des services
📊 Diagramme ERD simplifié
services_domaines
🔑 idINT PK
slugVARCHAR
nomVARCHAR
iconeVARCHAR
couleur_hexCHAR(7)
image_urlTEXT
descriptionTEXT
actifBOOL
ordre_affichageINT
services_categories
🔑 idINT PK
🔗 domaine_idINT FK
slugVARCHAR
nomVARCHAR
descriptionTEXT
image_urlTEXT
ordreINT
services_interventions
🔑 idINT PK
🔗 categorie_idINT FK
slugVARCHAR
nomVARCHAR
descriptionTEXT
prix_minDECIMAL
prix_maxDECIMAL
unite_prixENUM
duree_min_minINT
duree_max_minINT
type_interventionENUM
urgence_disponibleBOOL
image_urlTEXT
actifBOOL
ordreINT
services_variantes
🔑 idINT PK
🔗 intervention_idINT FK
nomVARCHAR
descriptionTEXT
prix_minDECIMAL
prix_maxDECIMAL
image_urlTEXT
services_questions
🔑 idINT PK
🔗 intervention_idINT FK
libelleTEXT
type_champENUM
options_jsonJSON
obligatoireBOOL
image_urlTEXT
ordreINT
CREATE TABLE — Structure complète
-- ============================================================
-- MesDépanneurs.fr — Schéma SQL de configuration des services
-- Version 1.0 | Compatible MySQL 8.0+ / PostgreSQL 14+
-- ============================================================

-- 1. DOMAINES (niveau 1 : Plomberie, Électricité, etc.)
CREATE TABLE services_domaines (
    id                INT UNSIGNED     NOT NULL AUTO_INCREMENT,
    slug              VARCHAR(80)      NOT NULL,
    nom               VARCHAR(120)     NOT NULL,
    icone             VARCHAR(10)      NULL,           -- emoji ou code icon
    couleur_hex       CHAR(7)          NULL,           -- ex: #3b82f6
    image_url         TEXT             NULL,           -- image illustrative
    description       TEXT             NULL,
    actif             TINYINT(1)       NOT NULL DEFAULT 1,
    ordre_affichage   SMALLINT         NOT NULL DEFAULT 0,
    created_at        DATETIME         DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE KEY uq_domaine_slug (slug)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 2. CATÉGORIES (niveau 2 : Fuite, Débouchage, etc.)
CREATE TABLE services_categories (
    id                INT UNSIGNED     NOT NULL AUTO_INCREMENT,
    domaine_id        INT UNSIGNED     NOT NULL,
    slug              VARCHAR(100)     NOT NULL,
    nom               VARCHAR(150)     NOT NULL,
    description       TEXT             NULL,
    image_url         TEXT             NULL,
    actif             TINYINT(1)       NOT NULL DEFAULT 1,
    ordre             SMALLINT         NOT NULL DEFAULT 0,
    created_at        DATETIME         DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE KEY uq_cat_slug (slug),
    FOREIGN KEY (domaine_id) REFERENCES services_domaines(id)
        ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 3. INTERVENTIONS (niveau 3 : la prestation précise + prix)
CREATE TABLE services_interventions (
    id                    INT UNSIGNED     NOT NULL AUTO_INCREMENT,
    categorie_id          INT UNSIGNED     NOT NULL,
    slug                  VARCHAR(150)     NOT NULL,
    nom                   VARCHAR(250)     NOT NULL,
    description           TEXT             NULL,
    prix_min              DECIMAL(8,2)     NULL,
    prix_max              DECIMAL(8,2)     NULL,
    unite_prix            ENUM('TTC_forfait','TTC_heure','TTC_m2','sur_devis')
                                           NOT NULL DEFAULT 'TTC_forfait',
    duree_min_min         SMALLINT         NULL,    -- durée minimale en minutes
    duree_max_min         SMALLINT         NULL,    -- durée maximale en minutes
    type_intervention     ENUM('depannage','installation','entretien','renovation','diagnostic')
                                           NOT NULL DEFAULT 'depannage',
    urgence_disponible    TINYINT(1)       NOT NULL DEFAULT 1,
    garantie_jours        SMALLINT         NULL,    -- ex: 730 = 2 ans
    image_url             TEXT             NULL,    -- image illustrative step
    notes_internes        TEXT             NULL,
    actif                 TINYINT(1)       NOT NULL DEFAULT 1,
    ordre                 SMALLINT         NOT NULL DEFAULT 0,
    created_at            DATETIME         DEFAULT CURRENT_TIMESTAMP,
    updated_at            DATETIME         DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE KEY uq_intervention_slug (slug),
    FOREIGN KEY (categorie_id) REFERENCES services_categories(id)
        ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 4. VARIANTES (niveau 4 : déclinaisons de la même prestation)
-- Ex: Serrure 1pt / 3pts / 5pts, Ballon 50L / 100L / 150L, etc.
CREATE TABLE services_variantes (
    id                INT UNSIGNED     NOT NULL AUTO_INCREMENT,
    intervention_id   INT UNSIGNED     NOT NULL,
    nom               VARCHAR(200)     NOT NULL,
    description       TEXT             NULL,
    prix_min          DECIMAL(8,2)     NULL,
    prix_max          DECIMAL(8,2)     NULL,
    image_url         TEXT             NULL,
    actif             TINYINT(1)       NOT NULL DEFAULT 1,
    ordre             SMALLINT         NOT NULL DEFAULT 0,
    PRIMARY KEY (id),
    FOREIGN KEY (intervention_id) REFERENCES services_interventions(id)
        ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 5. QUESTIONS DU QUESTIONNAIRE (étapes de diagnostic)
-- Chaque intervention peut avoir N questions avec image optionnelle
CREATE TABLE services_questions (
    id                INT UNSIGNED     NOT NULL AUTO_INCREMENT,
    intervention_id   INT UNSIGNED     NOT NULL,
    libelle           TEXT             NOT NULL,
    sous_libelle      TEXT             NULL,
    type_champ        ENUM('radio','checkbox','select','textarea','photo')
                                       NOT NULL DEFAULT 'radio',
    options_json      JSON             NULL, -- [{label, value, prix_ajout, image_url}]
    obligatoire       TINYINT(1)       NOT NULL DEFAULT 1,
    image_url         TEXT             NULL, -- illustration de l'étape
    ordre             SMALLINT         NOT NULL DEFAULT 0,
    PRIMARY KEY (id),
    FOREIGN KEY (intervention_id) REFERENCES services_interventions(id)
        ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT — Données de référence (6 domaines)
-- ============================================================
-- SEED : Les 6 domaines cibles de MesDépanneurs.fr
-- ============================================================

INSERT INTO services_domaines (id, slug, nom, icone, couleur_hex, ordre_affichage) VALUES
(1,  'plomberie',    'Plomberie',             '💧', '#3b82f6', 1),
(2,  'electricite',  'Électricité',           '⚡', '#f59e0b', 2),
(3,  'serrurerie',   'Serrurerie',            '🔑', '#a855f7', 3),
(4,  'vitrerie',     'Vitrerie',              '🪟', '#06b6d4', 4),
(5,  'chauffage',    'Chauffage',             '🔥', '#ef4444', 5),
(6,  'clim-pac',     'Clim & Pompe à chaleur','❄️', '#22c55e', 6);

-- CATÉGORIES — PLOMBERIE (domaine_id=1)
INSERT INTO services_categories (id, domaine_id, slug, nom, ordre) VALUES
(101, 1, 'plomberie-fuites',       'Fuites d\'eau',              1),
(102, 1, 'plomberie-debouchage',   'Débouchage',                2),
(103, 1, 'plomberie-wc',          'WC & Sanitaires',           3),
(104, 1, 'plomberie-ballon',      'Ballon d\'eau chaude',       4),
(105, 1, 'plomberie-robinetterie','Robinetterie',               5),
(106, 1, 'plomberie-installation','Installation & rénovation',  6);

-- CATÉGORIES — ÉLECTRICITÉ (domaine_id=2)
INSERT INTO services_categories (id, domaine_id, slug, nom, ordre) VALUES
(201, 2, 'elec-tableau',     'Tableau électrique',    1),
(202, 2, 'elec-prises',      'Prises & interrupteurs', 2),
(203, 2, 'elec-eclairage',   'Éclairage',              3),
(204, 2, 'elec-mise-normes', 'Mise aux normes',        4),
(205, 2, 'elec-installation','Installation',          5);

-- CATÉGORIES — SERRURERIE (domaine_id=3)
INSERT INTO services_categories (id, domaine_id, slug, nom, ordre) VALUES
(301, 3, 'serr-ouverture',  'Ouverture de porte',    1),
(302, 3, 'serr-serrure',    'Serrures & cylindres',  2),
(303, 3, 'serr-blindage',   'Blindage & sécurité',  3),
(304, 3, 'serr-divers',     'Divers (boîte aux lettres, portail...)', 4);

-- CATÉGORIES — VITRERIE (domaine_id=4)
INSERT INTO services_categories (id, domaine_id, slug, nom, ordre) VALUES
(401, 4, 'vitr-vitrage',     'Remplacement de vitrage',  1),
(402, 4, 'vitr-fenetres',    'Fenêtres & portes-fenêtres',2),
(403, 4, 'vitr-mecanique',   'Mécanismes & crémones',   3),
(404, 4, 'vitr-etancheite',  'Étanchéité & joints',     4);

-- CATÉGORIES — CHAUFFAGE (domaine_id=5)
INSERT INTO services_categories (id, domaine_id, slug, nom, ordre) VALUES
(501, 5, 'chauf-chaudiere-gaz',  'Chaudière à gaz',      1),
(502, 5, 'chauf-chaudiere-elec', 'Chaudière électrique', 2),
(503, 5, 'chauf-chaudiere-fioul','Chaudière fioul',      3),
(504, 5, 'chauf-radiateurs',    'Radiateurs',           4),
(505, 5, 'chauf-ballon-chaud',  'Chauffe-eau & ballons', 5);

-- CATÉGORIES — CLIM & PAC (domaine_id=6)
INSERT INTO services_categories (id, domaine_id, slug, nom, ordre) VALUES
(601, 6, 'clim-installation',  'Installation climatisation',    1),
(602, 6, 'clim-entretien',     'Entretien & maintenance',       2),
(603, 6, 'clim-depannage',     'Dépannage climatisation',       3),
(604, 6, 'pac-installation',   'Installation pompe à chaleur',  4),
(605, 6, 'pac-entretien',      'Entretien pompe à chaleur',     5),
(606, 6, 'pac-depannage',      'Dépannage pompe à chaleur',     6);

-- INTERVENTIONS — PLOMBERIE (exemple exhaustif, cat 101-106)
INSERT INTO services_interventions
  (id, categorie_id, slug, nom, prix_min, prix_max, unite_prix, duree_min_min, duree_max_min, type_intervention, urgence_disponible, garantie_jours)
VALUES
-- Fuites
(1001, 101, 'recherche-fuite-simple',           'Recherche de fuite simple',                   100, 220, 'TTC_forfait', 60, 120, 'diagnostic',   1, 365),
(1002, 101, 'fuite-canalisation-apparente',     'Réparation fuite canalisation apparente',     100, 200, 'TTC_forfait', 30, 120, 'depannage',    1, 365),
(1003, 101, 'fuite-canalisation-encastree',     'Recherche & réparation fuite encastrée',      500, 1000,'TTC_forfait', 120,480, 'depannage',    1, 365),
(1004, 101, 'fuite-robinet-joint',             'Réparation fuite robinet / joint',            80,  150, 'TTC_forfait', 30, 60,  'depannage',    1, 365),
(1005, 101, 'fuite-wc',                        'Réparation fuite WC (mécanisme chasse)',      80,  150, 'TTC_forfait', 30, 60,  'depannage',    1, 365),
(1006, 101, 'degat-des-eaux',                  'Intervention dégât des eaux (urgence)',       150, 450, 'TTC_forfait', 60, 240, 'depannage',    1, 365),
-- Débouchage
(1007, 102, 'debouchage-wc-manuel',            'Débouchage WC (furet/ventouse manuel)',        100, 180, 'TTC_forfait', 30, 120, 'depannage',    1, 2),
(1008, 102, 'debouchage-wc-sanibroyeur',       'Débouchage WC avec sanibroyeur',              100, 200, 'TTC_forfait', 30, 120, 'depannage',    1, 2),
(1009, 102, 'debouchage-lavabo-evier',         'Débouchage lavabo / évier',                   100, 180, 'TTC_forfait', 30, 90,  'depannage',    1, 2),
(1010, 102, 'debouchage-douche-baignoire',     'Débouchage douche / baignoire',               100, 180, 'TTC_forfait', 30, 90,  'depannage',    1, 2),
(1011, 102, 'debouchage-colonne-immeuble',     'Débouchage colonne générale d\'immeuble',      700, 900, 'TTC_forfait', 120,240, 'depannage',    1, 2),
(1012, 102, 'debouchage-haute-pression',       'Débouchage haute pression (camion hydrocureur)',300, 900, 'TTC_forfait', 60, 240, 'depannage',    1, 2),
-- Ballon eau chaude
(1020, 104, 'fuite-ballon-reparation',         'Réparation fuite ballon eau chaude',          100, 220, 'TTC_forfait', 60, 120, 'depannage',    1, 365),
(1021, 104, 'reparation-ballon-electrique',    'Réparation ballon eau chaude électrique',     100, 200, 'TTC_forfait', 60, 120, 'depannage',    1, 365),
(1022, 104, 'pose-ballon-50l',                 'Fourniture & pose ballon 50L',                350, 600, 'TTC_forfait', 120,240, 'installation', 0, 730),
(1023, 104, 'pose-ballon-100l',                'Fourniture & pose ballon 100L',               400, 700, 'TTC_forfait', 120,240, 'installation', 0, 730),
(1024, 104, 'pose-ballon-200l',                'Fourniture & pose ballon 200L+',              600, 1000,'TTC_forfait', 180,360, 'installation', 0, 730),
-- Robinetterie
(1030, 105, 'changement-robinet',             'Changement de robinet',                       80,  150, 'TTC_forfait', 30, 90,  'installation', 1, 365),
(1031, 105, 'pose-mitigeur-thermostatique',   'Pose mitigeur thermostatique',                100, 200, 'TTC_forfait', 45, 90,  'installation', 1, 365),

-- INTERVENTIONS — ÉLECTRICITÉ
(2001, 201, 'panne-tableau-electrique',       'Réparation panne tableau électrique',         150, 250, 'TTC_forfait', 60, 180, 'depannage',    1, 365),
(2002, 201, 'remplacement-tableau-elec',      'Remplacement tableau électrique complet',     800, 2500,'TTC_forfait', 240,480, 'installation', 0, 730),
(2003, 201, 'disjoncteur-differentiel',      'Remplacement disjoncteur différentiel',       150, 300, 'TTC_forfait', 60, 120, 'depannage',    1, 365),
(2010, 202, 'panne-plusieurs-prises',         'Réparation panne plusieurs prises',           150, 300, 'TTC_forfait', 60, 120, 'depannage',    1, 365),
(2011, 202, 'pose-prise-electrique',          'Pose prise électrique',                       80,  150, 'TTC_forfait', 30, 60,  'installation', 1, 365),
(2012, 202, 'pose-prise-arrachee',            'Remplacement prise arrachée',                 150, 200, 'TTC_forfait', 30, 60,  'depannage',    1, 365),
(2020, 203, 'probleme-eclairage',             'Dépannage éclairage (circuit)',               150, 250, 'TTC_forfait', 45, 120, 'depannage',    1, 365),
(2030, 204, 'diagnostic-installation',        'Diagnostic installation électrique',          150, 300, 'TTC_forfait', 60, 120, 'diagnostic',   1, 0),
(2031, 205, 'installation-borne-recharge',    'Installation borne de recharge VE',           800, 2000,'TTC_forfait', 180,360, 'installation', 0, 730),

-- INTERVENTIONS — SERRURERIE
(3001, 301, 'ouverture-porte-claquee',        'Ouverture porte claquée (non verrouillée)',   130, 180, 'TTC_forfait', 15, 60,  'depannage',    1, 0),
(3002, 301, 'ouverture-porte-verrouillee',    'Ouverture porte verrouillée (sans clé)',      150, 250, 'TTC_forfait', 30, 90,  'depannage',    1, 0),
(3003, 301, 'ouverture-porte-blindee-claquee', 'Ouverture porte blindée claquée',             150, 250, 'TTC_forfait', 30, 90,  'depannage',    1, 0),
(3004, 301, 'ouverture-porte-blindee-verrou', 'Ouverture porte blindée verrouillée',         200, 400, 'TTC_forfait', 45, 120, 'depannage',    1, 0),
(3010, 302, 'changement-cylindre',            'Changement de cylindre',                      120, 200, 'TTC_forfait', 30, 60,  'installation', 1, 365),
(3011, 302, 'pose-serrure-1-point',           'Fourniture & pose serrure 1 point',           250, 450, 'TTC_forfait', 60, 120, 'installation', 1, 365),
(3012, 302, 'pose-serrure-3-points',          'Fourniture & pose serrure 3 points',          400, 800, 'TTC_forfait', 60, 180, 'installation', 1, 365),
(3013, 302, 'pose-serrure-5-points-plus',     'Fourniture & pose serrure 5 points ou +',     600, 1000,'TTC_forfait', 90, 240, 'installation', 1, 365),
(3014, 302, 'pose-verrou-applique',           'Pose verrou en applique',                     130, 180, 'TTC_forfait', 30, 60,  'installation', 1, 365),
(3020, 303, 'blindage-porte-existante',       'Blindage sur porte existante (tôle + serrure)',500, 900, 'TTC_forfait', 180,360, 'installation', 0, 730),
(3021, 303, 'porte-blindee-complete',         'Installation porte blindée certifiée A2P',    1000,1800,'TTC_forfait', 240,480, 'installation', 0, 730),
(3030, 304, 'serrure-boite-lettres',          'Remplacement serrure boîte aux lettres',      70,  150, 'TTC_forfait', 20, 45,  'installation', 1, 365),

-- INTERVENTIONS — VITRERIE
(4001, 401, 'remplacement-vitre-simple',      'Remplacement vitre simple',                   100, 200, 'TTC_m2',     60, 180, 'depannage',    1, 365),
(4002, 401, 'remplacement-double-vitrage',    'Remplacement double vitrage',                 150, 280, 'TTC_m2',     90, 240, 'installation', 1, 730),
(4003, 401, 'remplacement-triple-vitrage',   'Remplacement triple vitrage',                 200, 400, 'TTC_m2',     90, 240, 'installation', 0, 730),
(4010, 402, 'remplacement-fenetre-simple',    'Remplacement fenêtre simple vitrage',         300, 500, 'TTC_forfait', 120,240, 'installation', 0, 730),
(4011, 402, 'remplacement-fenetre-double',    'Remplacement fenêtre double vitrage',         500, 800, 'TTC_forfait', 120,240, 'installation', 0, 730),
(4020, 403, 'remplacement-cremone',          'Remplacement crémone de fenêtre',             80,  150, 'TTC_forfait', 30, 60,  'depannage',    1, 365),
(4030, 404, 'remplacement-joints-fenetre',   'Remplacement joints d\'étanchéité fenêtre',   50,  150, 'TTC_forfait', 30, 60,  'entretien',   1, 365),
(4031, 404, 'calfeutrage-porte-fenetre',     'Reprise calfeutrage porte-fenêtre',           100, 200, 'TTC_forfait', 45, 120, 'depannage',    1, 365),

-- INTERVENTIONS — CHAUFFAGE
(5001, 501, 'entretien-chaudiere-gaz',        'Entretien annuel chaudière gaz (obligatoire)', 150, 180, 'TTC_forfait', 45, 90,  'entretien',   0, 365),
(5002, 501, 'contrat-entretien-chaudiere',    'Contrat entretien chaudière (annuel)',         100, 200, 'TTC_forfait', 0,  0,   'entretien',   0, 365),
(5003, 501, 'reparation-chaudiere-gaz',       'Réparation chaudière gaz (marque diverse)',   150, 500, 'TTC_forfait', 60, 240, 'depannage',    1, 365),
(5004, 501, 'remplacement-chaudiere-gaz',     'Remplacement chaudière gaz (fourniture+pose)', 2000,5000,'TTC_forfait', 240,480, 'installation', 0, 730),
(5010, 504, 'purge-radiateur',                'Purge de radiateur',                          80,  150, 'TTC_forfait', 20, 45,  'depannage',    1, 365),
(5011, 504, 'reparation-circuit-radiateurs',  'Réparation circuit de radiateurs',            150, 400, 'TTC_forfait', 60, 180, 'depannage',    1, 365),
(5012, 504, 'desembouage-installation',       'Désembouage installation de chauffage',       300, 600, 'TTC_forfait', 120,240, 'entretien',   0, 365),

-- INTERVENTIONS — CLIM & PAC
(6001, 601, 'installation-clim-monosplit',    'Installation climatisation monosplit',        1200,2500,'TTC_forfait', 240,480, 'installation', 0, 730),
(6002, 601, 'installation-clim-multisplit-2', 'Installation multisplit 2 unités',            2000,3500,'TTC_forfait', 360,600, 'installation', 0, 730),
(6003, 601, 'installation-clim-multisplit-3', 'Installation multisplit 3 unités',            2800,5000,'TTC_forfait', 480,720, 'installation', 0, 730),
(6010, 602, 'entretien-clim-monosplit',       'Entretien annuel climatisation monosplit',    150, 200, 'TTC_forfait', 60, 90,  'entretien',   0, 365),
(6011, 602, 'entretien-clim-bisplit',         'Entretien climatisation bisplit (2 unités)',  200, 300, 'TTC_forfait', 90, 150, 'entretien',   0, 365),
(6012, 602, 'entretien-clim-trisplit',        'Entretien climatisation trisplit (3 unités)', 280, 400, 'TTC_forfait', 120,180, 'entretien',   0, 365),
(6020, 603, 'depannage-clim-plus-froid',      'Dépannage clim ne refroidit plus',            200, 400, 'TTC_forfait', 60, 180, 'depannage',    1, 365),
(6021, 603, 'recharge-gaz-clim',              'Recharge gaz climatisation (fréon)',          150, 400, 'TTC_forfait', 60, 120, 'depannage',    1, 365),
(6030, 604, 'installation-pac-air-air',       'Installation PAC air/air',                    3000,8000,'TTC_forfait', 480,720, 'installation', 0, 730),
(6031, 604, 'installation-pac-air-eau',       'Installation PAC air/eau',                    7000,15000,'TTC_forfait',480,1440,'installation', 0, 730),
(6040, 605, 'entretien-pac',                  'Entretien pompe à chaleur',                   150, 250, 'TTC_forfait', 60, 120, 'entretien',   0, 365),
(6050, 606, 'depannage-pac',                  'Dépannage pompe à chaleur',                   200, 600, 'TTC_forfait', 60, 240, 'depannage',    1, 365);

-- VARIANTES (exemples)
INSERT INTO services_variantes (intervention_id, nom, prix_min, prix_max, ordre) VALUES
-- Ballon eau chaude variantes
(1022, 'Ballon électrique 50L',          350, 500, 1),
(1022, 'Ballon électrique 80L',          400, 600, 2),
(1022, 'Ballon thermodynamique',         800, 1500,3),
(1022, 'Chauffe-eau gaz',               500, 1000,4),
-- Serrure 3 points variantes
(3012, 'Serrure 3 pts standard',         400, 600, 1),
(3012, 'Serrure 3 pts haute sécurité A2P',600, 800, 2),
-- Fenêtre double vitrage matériaux
(4011, 'Fenêtre PVC double vitrage',      350, 600, 1),
(4011, 'Fenêtre aluminium double vitrage', 500, 800, 2),
(4011, 'Fenêtre bois double vitrage',     500, 900, 3),
-- PAC variantes
(6030, 'PAC air/air réversible monosplit',2500,5000,1),
(6030, 'PAC air/air réversible multisplit',4000,8000,2),
(6031, 'PAC air/eau (radiateurs existants)',7000,12000,1),
(6031, 'PAC air/eau (plancher chauffant)', 10000,15000,2);

-- VUE PRATIQUE : Résumé prix par domaine
CREATE VIEW v_services_avec_prix AS
SELECT
    d.nom                              AS domaine,
    c.nom                              AS categorie,
    i.nom                              AS intervention,
    i.type_intervention,
    i.prix_min,
    i.prix_max,
    i.unite_prix,
    i.duree_min_min,
    i.duree_max_min,
    i.urgence_disponible,
    i.garantie_jours,
    i.image_url
FROM   services_interventions i
JOIN   services_categories    c ON i.categorie_id = c.id
JOIN   services_domaines      d ON c.domaine_id   = d.id
WHERE  i.actif = 1 AND c.actif = 1 AND d.actif = 1
ORDER BY d.ordre_affichage, c.ordre, i.ordre;

Parcours de diagnostic

Pilotez le questionnaire étape par étape — chaque réponse affine le besoin jusqu'au résultat tarifé.

📊 Flux de navigation
Chaque étape est une question rattachée à un nœud de l'arbre. La réponse détermine le nœud suivant.
Étape 0
Domaine
domaines
Étape 1
Question
questions
Étape 2
Réponse → Nœud
reponses
Étape N
Intervention
interventions
Résultat
Prix + Variantes
variantes
domaines 1→N questions  |  questions 1→N reponses  |  reponses N→1 questions (next) ou interventions (terminal)  |  interventions 1→N variantes
🗂️ ERD — Tables
domaines
idINT PK
slugVARCHAR
nomVARCHAR
iconeVARCHAR
couleur_hexVARCHAR
image_urlVARCHAR
actifBOOL
ordreINT
questions
idINT PK
domaine_idFK
parent_reponse_idFK NULL
libelleTEXT
sous_libelleTEXT
type_champENUM
image_urlVARCHAR
est_racineBOOL
ordreINT
reponses
idINT PK
question_idFK
next_question_idFK NULL
intervention_idFK NULL
labelVARCHAR
iconeVARCHAR
image_urlVARCHAR
ordreINT
interventions
idINT PK
domaine_idFK
slugVARCHAR
nomVARCHAR
descriptionTEXT
prix_minDECIMAL
prix_maxDECIMAL
unite_prixENUM
urgence_disponibleBOOL
garantie_joursINT
image_urlVARCHAR
variantes
idINT PK
intervention_idFK
nomVARCHAR
descriptionTEXT
prix_minDECIMAL
prix_maxDECIMAL
image_urlVARCHAR
ordreINT
📝 CREATE TABLES
schema.sql
-- ═══════════════════════════════════════════════════
-- MesDépanneurs.fr — Schéma piloté par questions
-- Compatible MySQL 8.0+ / PostgreSQL 14+
-- ═══════════════════════════════════════════════════

CREATE TABLE domaines (
  id            INT AUTO_INCREMENT PRIMARY KEY,
  slug          VARCHAR(80)  NOT NULL UNIQUE,
  nom           VARCHAR(120) NOT NULL,
  icone         VARCHAR(10),
  couleur_hex   VARCHAR(7),
  image_url     VARCHAR(500),
  description   TEXT,
  actif         BOOLEAN DEFAULT TRUE,
  ordre         INT     DEFAULT 0
);

-- Une question appartient à un domaine.
-- Si parent_reponse_id IS NULL c'est la question racine du domaine.
-- Si parent_reponse_id IS NOT NULL, cette question s'affiche
-- après que l'utilisateur a choisi cette réponse.
CREATE TABLE questions (
  id                  INT AUTO_INCREMENT PRIMARY KEY,
  domaine_id          INT NOT NULL REFERENCES domaines(id) ON DELETE CASCADE,
  parent_reponse_id   INT NULL REFERENCES reponses(id),
  libelle             TEXT NOT NULL,
  sous_libelle        TEXT,
  type_champ          ENUM('radio', 'select', 'photo') DEFAULT 'radio',
  image_url           VARCHAR(500),
  est_racine          BOOLEAN DEFAULT FALSE,
  ordre               INT DEFAULT 0
);

-- Une réponse appartient à une question.
-- next_question_id : pointe vers la prochaine question (nœud intermédiaire)
-- intervention_id  : pointe vers le résultat final (nœud terminal)
-- Contrainte : next_question_id XOR intervention_id doit être non null
CREATE TABLE reponses (
  id                INT AUTO_INCREMENT PRIMARY KEY,
  question_id       INT NOT NULL REFERENCES questions(id) ON DELETE CASCADE,
  next_question_id  INT NULL REFERENCES questions(id),
  intervention_id   INT NULL REFERENCES interventions(id),
  label             VARCHAR(200) NOT NULL,
  icone             VARCHAR(10),
  image_url         VARCHAR(500),
  ordre             INT DEFAULT 0,
  CHECK (
    (next_question_id IS NOT NULL AND intervention_id IS NULL)
    OR
    (next_question_id IS NULL AND intervention_id IS NOT NULL)
  )
);

CREATE TABLE interventions (
  id                  INT AUTO_INCREMENT PRIMARY KEY,
  domaine_id          INT NOT NULL REFERENCES domaines(id),
  slug                VARCHAR(120) NOT NULL UNIQUE,
  nom                 VARCHAR(200) NOT NULL,
  description         TEXT,
  prix_min            DECIMAL(8,2),
  prix_max            DECIMAL(8,2),
  unite_prix          ENUM('TTC_forfait', 'TTC_heure', 'TTC_m2', 'sur_devis') DEFAULT 'TTC_forfait',
  duree_min_min       INT,
  duree_max_min       INT,
  urgence_disponible  BOOLEAN DEFAULT TRUE,
  garantie_jours      INT,
  image_url           VARCHAR(500),
  notes_internes      TEXT
);

CREATE TABLE variantes (
  id              INT AUTO_INCREMENT PRIMARY KEY,
  intervention_id INT NOT NULL REFERENCES interventions(id) ON DELETE CASCADE,
  nom             VARCHAR(200) NOT NULL,
  description     TEXT,
  prix_min        DECIMAL(8,2),
  prix_max        DECIMAL(8,2),
  image_url       VARCHAR(500),
  ordre           INT DEFAULT 0
);
🌱 INSERT — Données de référence (Plomberie)
Exemple complet sur le domaine Plomberie illustrant le pattern questions → réponses → interventions → variantes.
seed_plomberie.sql
-- ── DOMAINES ────────────────────────────────────────
INSERT INTO domaines (slug, nom, icone, couleur_hex, ordre) VALUES
  ('plomberie',   'Plomberie',           '💧', '#3b82f6', 1),
  ('electricite', 'Électricité',         '⚡', '#f59e0b', 2),
  ('serrurerie',  'Serrurerie',          '🔑', '#a855f7', 3),
  ('vitrerie',    'Vitrerie',            '🪟', '#06b6d4', 4),
  ('chauffage',   'Chauffage',           '🔥', '#ef4444', 5),
  ('clim-pac',    'Clim & Pompe à chaleur','❄️', '#22c55e', 6);

-- ── INTERVENTIONS (plomberie) ────────────────────────
INSERT INTO interventions (domaine_id, slug, nom, prix_min, prix_max, garantie_jours, urgence_disponible) VALUES
  (1, 'fuite-robinet',           'Fuite robinet / joint',          80,  150, 365, TRUE),
  (1, 'fuite-canalisation',       'Fuite canalisation apparente',   100, 200, 365, TRUE),
  (1, 'fuite-encastree',          'Fuite canalisation encastrée',   500, 1000,365, TRUE),
  (1, 'fuite-wc',                 'Fuite WC / joint de cuvette',    80,  150, 365, TRUE),
  (1, 'fuite-chauffe-eau',        'Fuite chauffe-eau / ballon',     100, 220, 365, TRUE),
  (1, 'debouchage-wc',            'Débouchage WC',                  100, 200, 2,   TRUE),
  (1, 'debouchage-wc-sanibroyeur','Débouchage WC sanibroyeur',      100, 200, 2,   TRUE),
  (1, 'debouchage-evier',         'Débouchage évier / lavabo',      100, 180, 2,   TRUE),
  (1, 'debouchage-douche',        'Débouchage douche / baignoire',  100, 180, 2,   TRUE),
  (1, 'debouchage-colonne',       'Débouchage colonne générale',    700, 900, 2,   TRUE),
  (1, 'reparation-chasse',        'Réparation chasse d\'eau',       80,  150, 365, TRUE),
  (1, 'pose-wc-standard',         'Pose WC standard',               150, 300, 730, FALSE),
  (1, 'pose-wc-suspendu',         'Pose WC suspendu',               200, 400, 730, FALSE),
  (1, 'pose-sanibroyeur',         'Fourniture + pose sanibroyeur',  900, 1100,730, FALSE),
  (1, 'ballon-electrique',        'Remplacement ballon électrique', 350, 1000,730, FALSE),
  (1, 'reparation-robinet',       'Changement robinet / mitigeur',  80,  200, 365, TRUE);

-- ── QUESTIONS PLOMBERIE (arbre) ──────────────────────
-- Q1 (racine) : localisation du problème
INSERT INTO questions (domaine_id, libelle, sous_libelle, est_racine, ordre) VALUES
  (1, 'Où se situe votre problème ?', 'Indiquez la zone concernée dans votre logement', TRUE, 1);
  -- → id = 1

-- Q2 : type de problème sur WC
INSERT INTO questions (domaine_id, parent_reponse_id, libelle, est_racine, ordre) VALUES
  (1, 2, 'Dans quel domaine avez-vous besoin d\'aide ?', FALSE, 1);
  -- → id = 2  (parent_reponse_id=2 = réponse "WC")

-- Q3 : type de problème sur évier/lavabo
INSERT INTO questions (domaine_id, parent_reponse_id, libelle, est_racine, ordre) VALUES
  (1, 3, 'Quel est le problème ?', FALSE, 1);
  -- → id = 3  (parent_reponse_id=3 = réponse "Évier / lavabo")

-- Q4 : type de ballon
INSERT INTO questions (domaine_id, parent_reponse_id, libelle, est_racine, ordre) VALUES
  (1, 6, 'Quel est votre type de chauffe-eau ?', FALSE, 1);
  -- → id = 4  (parent_reponse_id=6 = réponse "Chauffe-eau / ballon")

-- ── RÉPONSES ─────────────────────────────────────────
-- Réponses de Q1 (localisation)
INSERT INTO reponses (question_id, next_question_id, label, icone, ordre) VALUES
  (1, 2, 'WC',                '🚽', 1),  -- id=1, mène à Q2
  (1, 2, 'Évier / lavabo',   '🚿', 2),  -- id=2, mène à Q3
  (1, 3, 'Douche / baignoire','🛁', 3),  -- id=3, mène à Q3
  (1, 4, 'Chauffe-eau / ballon','♨️',4), -- id=4, mène à Q4
  (1, NULL, 'Canalisation',    '🔧', 5); -- terminal → voir ci-dessous

-- Réponses de Q2 (problème WC) — toutes terminales
INSERT INTO reponses (question_id, intervention_id, label, icone, ordre) VALUES
  (2, 6,  'Engorgement / bouchon', '💩', 1),
  (2, 4,  'Fuite au sol',          '💧', 2),
  (2, 11, 'Chasse ne fonctionne plus','🔄',3),
  (2, 12, 'Remplacement WC complet','🔩',4);

-- Réponses de Q3 (problème évier/douche) — terminales
INSERT INTO reponses (question_id, intervention_id, label, icone, ordre) VALUES
  (3, 8, 'Bouchon / eau stagnante', '🚫', 1),
  (3, 2, 'Fuite sous le meuble',    '💧', 2),
  (3, 16,'Robinet à changer',        '🔧', 3);

-- Réponses de Q4 (type chauffe-eau) — terminales
INSERT INTO reponses (question_id, intervention_id, label, icone, ordre) VALUES
  (4, 15,'Électrique', '⚡', 1),
  (4, 5, 'Fuite visible','💧', 2);

-- ── VARIANTES ────────────────────────────────────────
INSERT INTO variantes (intervention_id, nom, prix_min, prix_max, ordre) VALUES
  (6,  'WC standard (furet)',             100, 150, 1),
  (6,  'WC sanibroyeur',                  130, 200, 2),
  (6,  'Débouchage haute pression',        300, 500, 3),
  (15, '50 L (studio/T1)',                350, 500, 1),
  (15, '80 L (T2/T3)',                    400, 600, 2),
  (15, '150–200 L (maison)',              600, 1000,3),
  (15, 'Thermodynamique',                 800, 1500,4),
  (12, 'WC standard à poser',             150, 300, 1),
  (12, 'WC suspendu',                     200, 400, 2),
  (12, 'Sanibroyeur complet',             900, 1100,3);
🔍 Vue — Navigation parcours
views.sql
-- Reconstitue le chemin complet pour chaque intervention
CREATE VIEW v_parcours_interventions AS
WITH RECURSIVE parcours AS (
  -- Ancre : questions racines
  SELECT
    q.id              AS question_id,
    q.domaine_id,
    q.libelle         AS chemin,
    1               AS profondeur
  FROM questions q
  WHERE q.est_racine = TRUE

  UNION ALL

  -- Récursion : suivre les réponses vers les questions suivantes
  SELECT
    q2.id,
    q2.domaine_id,
    CONCAT(p.chemin, ' → ', r.label, ' → ', q2.libelle),
    p.profondeur + 1
  FROM parcours p
  JOIN reponses r   ON r.question_id      = p.question_id
  JOIN questions q2 ON q2.id              = r.next_question_id
)
SELECT
  p.chemin AS parcours_complet,
  r.label  AS derniere_reponse,
  i.nom    AS intervention,
  i.prix_min,
  i.prix_max,
  d.nom    AS domaine
FROM parcours p
JOIN reponses r    ON r.question_id   = p.question_id
JOIN interventions i ON i.id          = r.intervention_id
JOIN domaines d    ON d.id            = p.domaine_id
ORDER BY d.nom, p.profondeur;