FASE 1: Parts Database - Added part_categories, part_groups, parts, vehicle_parts tables - 12 categories, 190 groups with Spanish translations - API endpoints for categories, groups, parts CRUD FASE 2: Cross-References & Aftermarket - Added manufacturers, aftermarket_parts, part_cross_references tables - 24 manufacturers, quality tier system (economy/standard/premium/oem) - Part number search across OEM and aftermarket FASE 3: Exploded Diagrams - Added diagrams, vehicle_diagrams, diagram_hotspots tables - SVG viewer with zoom controls and interactive hotspots - 3 sample diagrams (brake, oil filter, suspension) FASE 4: Search & VIN Decoder - SQLite FTS5 full-text search with auto-sync triggers - NHTSA VIN decoder API integration with 30-day cache - Unified search endpoint FASE 5: Optimization & UX - API pagination (page/per_page, max 100 items) - Dark mode with localStorage persistence - Keyboard shortcuts (/, Ctrl+K, Escape, Backspace, Ctrl+D) - Breadcrumb navigation - ARIA accessibility (labels, roles, focus management) - Skip link for keyboard users Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
297 lines
11 KiB
SQL
297 lines
11 KiB
SQL
-- 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); |