-- Vehicle Database Schema -- Tables for storing vehicle information: brands, years, models, and engines -- Table for vehicle brands/manufacturers CREATE TABLE IF NOT EXISTS brands ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, country TEXT, founded_year INTEGER, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- Table for engine specifications CREATE TABLE IF NOT EXISTS engines ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, displacement_cc REAL, -- Engine displacement in cubic centimeters cylinders INTEGER, -- Number of cylinders fuel_type TEXT CHECK(fuel_type IN ('gasoline', 'diesel', 'electric', 'hybrid', 'other')), power_hp INTEGER, -- Horsepower torque_nm INTEGER, -- Torque in Newton meters engine_code TEXT, -- Manufacturer engine code created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- Table for vehicle models CREATE TABLE IF NOT EXISTS models ( id INTEGER PRIMARY KEY AUTOINCREMENT, brand_id INTEGER NOT NULL, name TEXT NOT NULL, body_type TEXT CHECK(body_type IN ('sedan', 'hatchback', 'suv', 'truck', 'coupe', 'convertible', 'wagon', 'van', 'other')), generation TEXT, -- Model generation (e.g., MK1, MK2) production_start_year INTEGER, production_end_year INTEGER, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (brand_id) REFERENCES brands(id) ); -- Table for years (to link with models) CREATE TABLE IF NOT EXISTS years ( id INTEGER PRIMARY KEY AUTOINCREMENT, year INTEGER NOT NULL UNIQUE, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- Junction table to connect models, years, and engines CREATE TABLE IF NOT EXISTS model_year_engine ( id INTEGER PRIMARY KEY AUTOINCREMENT, model_id INTEGER NOT NULL, year_id INTEGER NOT NULL, engine_id INTEGER NOT NULL, trim_level TEXT, -- Trim level (e.g., base, luxury, sport) drivetrain TEXT CHECK(drivetrain IN ('FWD', 'RWD', 'AWD', '4WD', 'other')), transmission TEXT CHECK(transmission IN ('manual', 'automatic', 'CVT', 'other')), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (model_id) REFERENCES models(id), FOREIGN KEY (year_id) REFERENCES years(id), FOREIGN KEY (engine_id) REFERENCES engines(id), UNIQUE(model_id, year_id, engine_id, trim_level) -- Prevent duplicate combinations ); -- Indexes for better performance CREATE INDEX IF NOT EXISTS idx_models_brand ON models(brand_id); CREATE INDEX IF NOT EXISTS idx_model_year_engine_model ON model_year_engine(model_id); CREATE INDEX IF NOT EXISTS idx_model_year_engine_year ON model_year_engine(year_id); CREATE INDEX IF NOT EXISTS idx_model_year_engine_engine ON model_year_engine(engine_id); -- ===================================================== -- PARTS CATALOG SCHEMA (FASE 1) -- ===================================================== -- Categorías de partes (Engine, Brakes, Suspension, etc.) CREATE TABLE IF NOT EXISTS part_categories ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, name_es TEXT, parent_id INTEGER, slug TEXT UNIQUE, icon_name TEXT, display_order INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (parent_id) REFERENCES part_categories(id) ); -- Grupos dentro de categorías (subcategorías más específicas) CREATE TABLE IF NOT EXISTS part_groups ( id INTEGER PRIMARY KEY AUTOINCREMENT, category_id INTEGER NOT NULL, name TEXT NOT NULL, name_es TEXT, slug TEXT, display_order INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (category_id) REFERENCES part_categories(id) ); -- Catálogo maestro de partes CREATE TABLE IF NOT EXISTS parts ( id INTEGER PRIMARY KEY AUTOINCREMENT, oem_part_number TEXT NOT NULL, name TEXT NOT NULL, name_es TEXT, group_id INTEGER, description TEXT, description_es TEXT, weight_kg REAL, material TEXT, is_discontinued BOOLEAN DEFAULT 0, superseded_by_id INTEGER, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (group_id) REFERENCES part_groups(id), FOREIGN KEY (superseded_by_id) REFERENCES parts(id) ); -- Fitment: qué partes van en qué vehículos CREATE TABLE IF NOT EXISTS vehicle_parts ( id INTEGER PRIMARY KEY AUTOINCREMENT, model_year_engine_id INTEGER NOT NULL, part_id INTEGER NOT NULL, quantity_required INTEGER DEFAULT 1, position TEXT, -- e.g., 'front', 'rear', 'left', 'right' fitment_notes TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (model_year_engine_id) REFERENCES model_year_engine(id), FOREIGN KEY (part_id) REFERENCES parts(id), UNIQUE(model_year_engine_id, part_id, position) ); -- Índices para el catálogo de partes CREATE INDEX IF NOT EXISTS idx_part_categories_parent ON part_categories(parent_id); CREATE INDEX IF NOT EXISTS idx_part_categories_slug ON part_categories(slug); CREATE INDEX IF NOT EXISTS idx_part_groups_category ON part_groups(category_id); CREATE INDEX IF NOT EXISTS idx_parts_oem ON parts(oem_part_number); CREATE INDEX IF NOT EXISTS idx_parts_group ON parts(group_id); CREATE INDEX IF NOT EXISTS idx_vehicle_parts_mye ON vehicle_parts(model_year_engine_id); CREATE INDEX IF NOT EXISTS idx_vehicle_parts_part ON vehicle_parts(part_id); -- ===================================================== -- FASE 2: CROSS-REFERENCES Y AFTERMARKET -- ===================================================== -- Fabricantes (OEM y aftermarket) CREATE TABLE IF NOT EXISTS manufacturers ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, type TEXT CHECK(type IN ('oem', 'aftermarket', 'remanufactured')), quality_tier TEXT CHECK(quality_tier IN ('economy', 'standard', 'premium', 'oem')), country TEXT, logo_url TEXT, website TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- Partes aftermarket vinculadas a OEM CREATE TABLE IF NOT EXISTS aftermarket_parts ( id INTEGER PRIMARY KEY AUTOINCREMENT, oem_part_id INTEGER NOT NULL, manufacturer_id INTEGER NOT NULL, part_number TEXT NOT NULL, name TEXT, name_es TEXT, quality_tier TEXT CHECK(quality_tier IN ('economy', 'standard', 'premium')), price_usd REAL, warranty_months INTEGER, in_stock BOOLEAN DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (oem_part_id) REFERENCES parts(id), FOREIGN KEY (manufacturer_id) REFERENCES manufacturers(id) ); -- Cross-references (números alternativos) CREATE TABLE IF NOT EXISTS part_cross_references ( id INTEGER PRIMARY KEY AUTOINCREMENT, part_id INTEGER NOT NULL, cross_reference_number TEXT NOT NULL, reference_type TEXT CHECK(reference_type IN ('oem_alternate', 'supersession', 'interchange', 'competitor')), source TEXT, notes TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (part_id) REFERENCES parts(id) ); -- Índices para FASE 2 CREATE INDEX IF NOT EXISTS idx_aftermarket_oem ON aftermarket_parts(oem_part_id); CREATE INDEX IF NOT EXISTS idx_aftermarket_manufacturer ON aftermarket_parts(manufacturer_id); CREATE INDEX IF NOT EXISTS idx_aftermarket_part_number ON aftermarket_parts(part_number); CREATE INDEX IF NOT EXISTS idx_cross_ref_part ON part_cross_references(part_id); CREATE INDEX IF NOT EXISTS idx_cross_ref_number ON part_cross_references(cross_reference_number); -- ===================================================== -- FASE 3: DIAGRAMAS EXPLOSIONADOS -- ===================================================== -- Diagramas de partes CREATE TABLE IF NOT EXISTS diagrams ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, name_es TEXT, group_id INTEGER NOT NULL, image_path TEXT NOT NULL, thumbnail_path TEXT, svg_content TEXT, width INTEGER, height INTEGER, display_order INTEGER DEFAULT 0, source TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (group_id) REFERENCES part_groups(id) ); -- Diagramas específicos por vehículo (qué diagramas aplican a qué vehículos) CREATE TABLE IF NOT EXISTS vehicle_diagrams ( id INTEGER PRIMARY KEY AUTOINCREMENT, diagram_id INTEGER NOT NULL, model_year_engine_id INTEGER NOT NULL, notes TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (diagram_id) REFERENCES diagrams(id), FOREIGN KEY (model_year_engine_id) REFERENCES model_year_engine(id), UNIQUE(diagram_id, model_year_engine_id) ); -- Hotspots clickeables en diagramas CREATE TABLE IF NOT EXISTS diagram_hotspots ( id INTEGER PRIMARY KEY AUTOINCREMENT, diagram_id INTEGER NOT NULL, part_id INTEGER, callout_number INTEGER, label TEXT, shape TEXT DEFAULT 'rect' CHECK(shape IN ('rect', 'circle', 'poly')), coords TEXT NOT NULL, color TEXT DEFAULT '#e74c3c', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (diagram_id) REFERENCES diagrams(id), FOREIGN KEY (part_id) REFERENCES parts(id) ); -- Índices para FASE 3 CREATE INDEX IF NOT EXISTS idx_diagrams_group ON diagrams(group_id); CREATE INDEX IF NOT EXISTS idx_vehicle_diagrams_diagram ON vehicle_diagrams(diagram_id); CREATE INDEX IF NOT EXISTS idx_vehicle_diagrams_mye ON vehicle_diagrams(model_year_engine_id); CREATE INDEX IF NOT EXISTS idx_hotspots_diagram ON diagram_hotspots(diagram_id); CREATE INDEX IF NOT EXISTS idx_hotspots_part ON diagram_hotspots(part_id); -- ===================================================== -- FASE 4: BÚSQUEDA FULL-TEXT Y VIN DECODER -- ===================================================== -- Full-Text Search virtual table (SQLite FTS5) CREATE VIRTUAL TABLE IF NOT EXISTS parts_fts USING fts5( oem_part_number, name, name_es, description, description_es, content='parts', content_rowid='id' ); -- Triggers para sincronización automática con parts table CREATE TRIGGER IF NOT EXISTS parts_fts_insert AFTER INSERT ON parts BEGIN INSERT INTO parts_fts(rowid, oem_part_number, name, name_es, description, description_es) VALUES (new.id, new.oem_part_number, new.name, new.name_es, new.description, new.description_es); END; CREATE TRIGGER IF NOT EXISTS parts_fts_delete AFTER DELETE ON parts BEGIN INSERT INTO parts_fts(parts_fts, rowid, oem_part_number, name, name_es, description, description_es) VALUES ('delete', old.id, old.oem_part_number, old.name, old.name_es, old.description, old.description_es); END; CREATE TRIGGER IF NOT EXISTS parts_fts_update AFTER UPDATE ON parts BEGIN INSERT INTO parts_fts(parts_fts, rowid, oem_part_number, name, name_es, description, description_es) VALUES ('delete', old.id, old.oem_part_number, old.name, old.name_es, old.description, old.description_es); INSERT INTO parts_fts(rowid, oem_part_number, name, name_es, description, description_es) VALUES (new.id, new.oem_part_number, new.name, new.name_es, new.description, new.description_es); END; -- Cache de VINs decodificados CREATE TABLE IF NOT EXISTS vin_cache ( id INTEGER PRIMARY KEY AUTOINCREMENT, vin TEXT NOT NULL UNIQUE, decoded_data TEXT NOT NULL, make TEXT, model TEXT, year INTEGER, engine_info TEXT, body_class TEXT, drive_type TEXT, model_year_engine_id INTEGER, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, expires_at DATETIME, FOREIGN KEY (model_year_engine_id) REFERENCES model_year_engine(id) ); -- Índices para FASE 4 CREATE INDEX IF NOT EXISTS idx_vin_cache_vin ON vin_cache(vin); CREATE INDEX IF NOT EXISTS idx_vin_cache_make_model ON vin_cache(make, model, year);