diff --git a/README.md b/README.md index 180e085..13160a7 100644 --- a/README.md +++ b/README.md @@ -1,333 +1,205 @@ # Nexus Autoparts -Sistema completo de gestión de base de datos de vehículos y nexus-autoparts con dashboard web, herramientas de web scraping y múltiples interfaces de consulta. +**Sistema de catalogo de autopartes con navegacion jerarquica, similar a 7zap.com/RockAuto.** -## Descripción +Plataforma SaaS que conecta talleres con bodegas/distribuidores. Permite buscar partes OEM y aftermarket por vehiculo (marca, modelo, ano, motor), gestionar inventario de bodegas, y consultar disponibilidad y precios en tiempo real. -**Nexus Autoparts** es una solución integral para la gestión de información de vehículos que incluye: +## Tech Stack -- Base de datos SQLite normalizada con información de marcas, modelos, motores y años -- Dashboard web moderno y responsivo para consultar y explorar datos -- Herramientas de web scraping para recopilar datos de RockAuto.com -- Interfaces de línea de comandos (CLI) y programática -- Scripts de utilidad para gestión y mantenimiento de datos +| Componente | Tecnologia | +|------------|-----------| +| Backend | Python 3, Flask | +| Base de datos | PostgreSQL | +| ORM / SQL | SQLAlchemy (`text()` raw SQL) | +| Autenticacion | JWT (PyJWT) + bcrypt | +| Data import | TecDoc via Apify, NHTSA VIN API | +| Frontend | HTML/CSS/JS vanilla (sin framework) | +| Dependencias extra | openpyxl (Excel), csv (CSV import) | -## Estadísticas de la Base de Datos +## Estadisticas de la Base de Datos -| Elemento | Cantidad | -|----------|----------| -| Marcas | 12 | -| Modelos | 10,923 | -| Motores | 10,919 | -| Combinaciones modelo-año-motor | 12,075 | +- **1.4M+** partes OEM +- **300K+** partes aftermarket +- **13M+** cross-references (numeros alternos, supersesiones, intercambios) +- **12B+** vehicle-part links (fitment) +- **100+** marcas, miles de modelos, anos 1956-2026 -## Tecnologías Utilizadas +## Features -### Backend -- **Python 3** - Lenguaje principal -- **SQLite 3** - Base de datos -- **Flask 2.3.3** - Framework web -- **BeautifulSoup4** - Web scraping -- **requests** - HTTP client -- **lxml** - Parser XML/HTML +- **Catalogo de autopartes** con navegacion jerarquica: Marca > Modelo > Ano > Motor > Categoria > Grupo > Parte +- **TecDoc integration** (via Apify) para importar datos OEM y aftermarket de Europa/Mexico +- **SaaS multi-tenant** con roles: `ADMIN`, `OWNER`, `TALLER`, `BODEGA` +- **JWT authentication** con access tokens (15 min) y refresh tokens (30 dias) +- **Gestion de inventario** para bodegas con mapeo flexible de columnas CSV/Excel +- **Disponibilidad de partes** en multiples bodegas con precios comparativos +- **Alternativas aftermarket** con cross-references por cada parte OEM +- **Panel de administracion** con gestion de usuarios, import/export CSV, CRUD de categorias/grupos/partes/fabricantes/fitment +- **Busqueda full-text** en el catalogo de partes (PostgreSQL `tsvector`) +- **Busqueda combinada** vehiculo + parte (e.g., "Toyota Corolla 2020 frenos") +- **VIN decoder** via NHTSA API con cache en base de datos +- **Diagramas explosionados** con hotspots clickeables +- **Vehicle-to-part linking** (12B+ vehicle_parts links) -### Frontend -- **HTML5** - Estructura -- **Bootstrap 5.3.0** - Framework CSS -- **JavaScript (ES6+)** - Lógica cliente -- **Font Awesome 6.0.0** - Iconos +## Quick Start -## Estructura del Proyecto +### Requisitos previos -``` -Autopartes/ -├── vehicle_database/ # Sistema principal de base de datos -│ ├── sql/ -│ │ └── schema.sql # Esquema de la base de datos -│ ├── scripts/ -│ │ ├── database_manager.py # Gestión de la BD -│ │ ├── query_interface.py # Interfaz CLI -│ │ └── csv_importer.py # Importador CSV -│ ├── data/ -│ │ ├── brands.csv # Datos de marcas -│ │ ├── engines.csv # Datos de motores -│ │ └── models.csv # Datos de modelos -│ ├── vehicle_database.db # Base de datos SQLite -│ └── setup.sh # Script de inicialización -│ -├── dashboard/ # Interfaz web -│ ├── server.py # Backend Flask -│ ├── index.html # Frontend HTML -│ ├── dashboard.js # Lógica JavaScript -│ └── start_dashboard.sh # Script de inicio -│ -├── console/ # Consola Pick/VT220 -│ ├── main.py # Punto de entrada -│ ├── db.py # Capa de datos abstracta -│ ├── core/ # Framework (app, screens, nav, keys) -│ ├── screens/ # 14 pantallas (menú, CRUD, búsqueda) -│ ├── renderers/ # Renderer VT220 (curses) -│ ├── utils/ # Formato y API VIN -│ └── tests/ # 116 tests -│ -├── vehicle_scraper/ # Herramientas de web scraping -│ ├── rockauto_scraper.py # Scraper RockAuto -│ ├── rockauto_scraper_v2.py # Scraper mejorado -│ ├── scrape_toyota.py # Scraper Toyota -│ ├── scrape_nissan_ford_chevrolet.py -│ └── manual_input.py # Ingreso manual -│ -├── add_*.py # Scripts para agregar datos -├── remove_*.py # Scripts de limpieza -└── QUICK_START.sh # Guía rápida de inicio -``` +- Python 3.8+ +- PostgreSQL con la base `nexus_autoparts` -## Consola Pick/VT220 - -Interfaz de terminal inspirada en los sistemas Pick/D3, 100% operada con teclado. Estética verde sobre negro con caracteres de caja, sin dependencias externas. +### Instalacion ```bash -python -m console +cd /home/Autopartes +pip install -r requirements.txt ``` -Funcionalidades: navegación por vehículo (marca→modelo→año→motor), búsqueda por número de parte, búsqueda full-text, decodificador VIN (NHTSA), catálogo por categorías, comparador OEM vs aftermarket, y administración CRUD completa. - -116 tests automatizados. Ver [`console/README.md`](console/README.md) para documentación completa. - -## Instalación - -### Requisitos Previos - -- Python 3.8 o superior -- pip (gestor de paquetes de Python) - -### Pasos de Instalación - -1. **Clonar el repositorio** - ```bash - git clone https://git.consultoria-as.com/[usuario]/Nexus-Autoparts.git - cd Nexus-Autoparts - ``` - -2. **Instalar dependencias** - ```bash - pip install flask requests beautifulsoup4 lxml - ``` - -3. **Inicializar la base de datos (opcional - ya incluye datos)** - ```bash - cd vehicle_database - ./setup.sh - ``` - -## Uso - -### Iniciar el Dashboard Web +### Ejecutar el servidor ```bash -cd dashboard +cd /home/Autopartes/dashboard python3 server.py ``` -El dashboard estará disponible en: `http://localhost:5000` +El servidor arranca en `http://localhost:5000`. -### Iniciar la Consola Pick/VT220 +### Importar datos de TecDoc ```bash -python -m console +# Fase 1: descargar datos de TecDoc a JSON +python3 scripts/import_tecdoc.py download + +# Fase 2: importar JSON a PostgreSQL +python3 scripts/import_tecdoc.py import + +# Ver progreso +python3 scripts/import_tecdoc.py status ``` -### Usar la Interfaz CLI Legacy +### Importar partes y linkar vehiculos ```bash -cd vehicle_database/scripts -python3 query_interface.py +# Importar partes TecDoc (OEM + aftermarket) +python3 scripts/import_tecdoc_parts.py + +# Importar datos en vivo desde TecDoc API +python3 scripts/import_live.py + +# Crear links vehiculo-parte (fitment masivo) +python3 scripts/link_vehicle_parts.py + +# Migrar datos aftermarket +python3 scripts/migrate_aftermarket.py + +# Aplicar schema SaaS (roles, users, inventory tables) +python3 scripts/migrate_saas_schema.py ``` -### Ejecutar Web Scraping +## Paginas del Dashboard -```bash -cd vehicle_scraper -python3 rockauto_scraper_v2.py -``` +| Ruta | Archivo | Descripcion | +|------|---------|-------------| +| `/login.html` | `login.html` | Login con JWT | +| `/demo.html` | `demo.html` | Catalogo publico / demo | +| `/admin` | `admin.html` | Panel de administracion (ADMIN/OWNER) | +| `/bodega.html` | `bodega.html` | Gestion de inventario para bodegas | +| `/tienda.html` | `tienda.html` | Vista de tienda/catalogo para talleres | +| `/pos.html` | `pos.html` | Punto de venta | +| `/captura.html` | `captura.html` | Captura de partes | +| `/cuentas.html` | `cuentas.html` | Gestion de cuentas | -### Agregar Datos Manualmente +## API Overview -```bash -cd vehicle_scraper -python3 manual_input.py -``` +Documentacion completa en [`docs/API.md`](docs/API.md). -## API REST +### Auth (`/api/auth/`) +- `POST /api/auth/register` - Registrar usuario (TALLER/BODEGA) +- `POST /api/auth/login` - Login, retorna access + refresh tokens +- `POST /api/auth/refresh` - Renovar access token +- `GET /api/auth/me` - Info del usuario autenticado -El dashboard expone los siguientes endpoints: +### Catalogo (`/api/`) +- `GET /api/brands` - Listar marcas +- `GET /api/models?brand=X` - Modelos por marca +- `GET /api/years?brand=X&model=Y` - Anos disponibles +- `GET /api/engines?brand=X&model=Y&year=Z` - Motores disponibles +- `GET /api/categories` - Categorias de partes (arbol jerarquico) +- `GET /api/parts?group_id=X` - Partes por grupo +- `GET /api/parts/{id}/alternatives` - Alternativas aftermarket +- `GET /api/parts/{id}/cross-references` - Cross-references +- `GET /api/search?q=...` - Busqueda combinada (vehiculos + partes + aftermarket) -| Endpoint | Método | Descripción | -|----------|--------|-------------| -| `/api/brands` | GET | Obtiene todas las marcas | -| `/api/models?brand=X` | GET | Obtiene modelos por marca | -| `/api/years` | GET | Obtiene años disponibles | -| `/api/engines` | GET | Obtiene motores disponibles | -| `/api/vehicles` | GET | Búsqueda con filtros | +### Inventario (`/api/inventory/`) +- `GET/PUT /api/inventory/mapping` - Mapeo de columnas CSV +- `POST /api/inventory/upload` - Subir CSV/Excel de inventario +- `GET /api/inventory/items` - Listar inventario propio +- `DELETE /api/inventory/items` - Limpiar inventario -### Ejemplo de Uso +### Disponibilidad y Aftermarket +- `GET /api/parts/{id}/availability` - Bodegas con stock (auth: TALLER/ADMIN/OWNER) +- `GET /api/parts/{id}/aftermarket` - Alternativas aftermarket + cross-refs (publico) -```bash -# Obtener todas las marcas -curl http://localhost:5000/api/brands +### Admin (`/api/admin/`) +- `GET /api/admin/users` - Listar usuarios (auth: ADMIN/OWNER) +- `PUT /api/admin/users/{id}/activate` - Activar/desactivar usuario +- `GET /api/admin/stats` - Estadisticas del catalogo +- CRUD completo: categories, groups, parts, manufacturers, aftermarket, crossref, fitment +- Import/Export CSV: `POST /api/admin/import/{type}`, `GET /api/admin/export/{type}` -# Buscar vehículos por marca y año -curl "http://localhost:5000/api/vehicles?brand=Toyota&year=2020" -``` +### VIN Decoder +- `GET /api/vin/decode/{vin}` - Decodificar VIN via NHTSA API +- `GET /api/vin/{vin}/parts` - Partes para un VIN decodificado +- `GET /api/vin/{vin}/match?mye_id=X` - Vincular VIN manualmente a vehiculo -## Esquema de Base de Datos +## Scripts -### Tablas +| Script | Funcion | +|--------|---------| +| `import_tecdoc.py` | Descarga datos de TecDoc API (vehiculos, modelos, marcas) a JSON | +| `import_tecdoc_parts.py` | Importa partes OEM y aftermarket desde TecDoc | +| `import_live.py` | Importacion en vivo desde TecDoc API | +| `link_vehicle_parts.py` | Genera links vehiculo-parte (fitment masivo) | +| `migrate_aftermarket.py` | Migra datos aftermarket a la estructura normalizada | +| `migrate_saas_schema.py` | Crea tablas SaaS: sessions, warehouse_inventory, roles, etc. | +| `import_phase1.py` | Importacion inicial fase 1 | +| `run_all_brands.sh` | Script auxiliar para importar todas las marcas | -#### brands -| Campo | Tipo | Descripción | -|-------|------|-------------| -| id | INTEGER | Clave primaria | -| name | TEXT | Nombre de la marca | -| country | TEXT | País de origen | -| founded_year | INTEGER | Año de fundación | +## Configuracion -#### models -| Campo | Tipo | Descripción | -|-------|------|-------------| -| id | INTEGER | Clave primaria | -| brand_id | INTEGER | FK a brands | -| name | TEXT | Nombre del modelo | -| body_type | TEXT | Tipo de carrocería | -| generation | TEXT | Generación | -| production_start_year | INTEGER | Año inicio producción | -| production_end_year | INTEGER | Año fin producción | +Archivo principal: [`config.py`](config.py) -#### engines -| Campo | Tipo | Descripción | -|-------|------|-------------| -| id | INTEGER | Clave primaria | -| name | TEXT | Nombre del motor | -| displacement_cc | INTEGER | Cilindrada en cc | -| cylinders | INTEGER | Número de cilindros | -| fuel_type | TEXT | Tipo de combustible | -| power_hp | INTEGER | Potencia en HP | -| torque_nm | INTEGER | Torque en Nm | -| engine_code | TEXT | Código del motor | +| Variable | Default | Descripcion | +|----------|---------|-------------| +| `DATABASE_URL` | `postgresql://nexus:...@localhost/nexus_autoparts` | PostgreSQL connection string | +| `JWT_SECRET` | `nexus-saas-secret-change-in-prod-2026` | Secreto para firmar tokens JWT | +| `JWT_ACCESS_EXPIRES` | `900` (15 min) | Duracion del access token en segundos | +| `JWT_REFRESH_EXPIRES` | `2592000` (30 dias) | Duracion del refresh token en segundos | -#### years -| Campo | Tipo | Descripción | -|-------|------|-------------| -| id | INTEGER | Clave primaria | -| year | INTEGER | Año | +## Arquitectura -#### model_year_engine -| Campo | Tipo | Descripción | -|-------|------|-------------| -| id | INTEGER | Clave primaria | -| model_id | INTEGER | FK a models | -| year_id | INTEGER | FK a years | -| engine_id | INTEGER | FK a engines | -| trim_level | TEXT | Nivel de equipamiento | -| drivetrain | TEXT | Tracción | -| transmission | TEXT | Transmisión | - -### Diagrama de Relaciones +Documentacion detallada en [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md). ``` -brands ──┐ - │ - ├──< models ──┐ - │ │ -years ───┼─────────────┼──< model_year_engine - │ │ -engines ─┴─────────────┘ + +------------------+ + | TecDoc (Apify) | + +--------+---------+ + | + download/import + | + v ++----------+ +--------+---------+ +----------------+ +| Frontend |<--->| Flask Server |<--->| PostgreSQL | +| (HTML/JS)| | (server.py) | | nexus_autoparts| ++----------+ +--------+---------+ +----------------+ + | + JWT auth (PyJWT) + | + +------------+------------+ + | | | + TALLER BODEGA ADMIN + (consulta) (inventario) (gestion) ``` -## Scripts Disponibles - -### Scripts de Datos - -| Script | Descripción | -|--------|-------------| -| `add_toyota_data.py` | Agrega datos de Toyota | -| `add_honda_data.py` | Agrega datos de Honda | -| `add_nissan_data.py` | Agrega datos de Nissan | -| `add_ford_data.py` | Agrega datos de Ford | -| `add_chevrolet_data.py` | Agrega datos de Chevrolet | -| `add_audi_data.py` | Agrega datos de Audi | -| `add_acura_data.py` | Agrega datos de Acura | -| ... | Y más marcas | - -### Scripts de Mantenimiento - -| Script | Descripción | -|--------|-------------| -| `remove_brands_and_cleanup.py` | Limpia marcas innecesarias | -| `check_and_remove_brands.py` | Verifica y elimina marcas | - -## Funcionalidades del Dashboard - -### Panel de Filtros -- Selección de marca -- Selección de modelo (dinámico según marca) -- Filtro por año -- Filtro por motor - -### Panel de Resultados -- Visualización en tarjetas -- Información detallada del vehículo -- Especificaciones del motor -- Datos de transmisión y tracción - -### Características -- Diseño responsivo -- Actualización en tiempo real -- Animaciones y transiciones suaves -- Soporte para múltiples idiomas - -## Arquitectura del Sistema - -``` -┌─────────────────┐ ┌──────────────────┐ -│ RockAuto.com │────>│ Web Scraper │ -└─────────────────┘ └────────┬─────────┘ - │ - v -┌─────────────────┐ ┌──────────────────┐ -│ Manual Input │────>│ SQLite Database │ -└─────────────────┘ └────────┬─────────┘ - │ - ┌───────────────────────┼───────────────────────┐ - │ │ │ - v v v -┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐ -│ Flask API │ │ Pick Console │ │ CSV Importer │ -└────────┬────────┘ │ (VT220/Rich) │ └──────────────────┘ - │ └──────────────────┘ - v -┌─────────────────┐ -│ Web Dashboard │ -│ (Browser) │ -└─────────────────┘ -``` - -## Contribuir - -1. Fork el repositorio -2. Crea una rama para tu feature (`git checkout -b feature/nueva-funcionalidad`) -3. Commit tus cambios (`git commit -am 'Agrega nueva funcionalidad'`) -4. Push a la rama (`git push origin feature/nueva-funcionalidad`) -5. Crea un Pull Request - -## Licencia - -Este proyecto es de uso interno. - -## Contacto - -Para más información, contactar al equipo de desarrollo. - --- -**Nexus Autoparts** - Sistema de Gestión de Base de Datos de Vehículos +**Nexus Autoparts** - Tu conexion directa con las partes que necesitas diff --git a/docs/API.md b/docs/API.md index 091fcce..b9d7fe1 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1,123 +1,754 @@ # API Reference - Nexus Autoparts -Documentación completa de la API REST del sistema Nexus Autoparts. +Documentacion completa de la API REST del sistema Nexus Autoparts. ## Base URL ``` -http://localhost:5000/api +http://localhost:5000 ``` -## Endpoints +## Autenticacion + +Los endpoints protegidos requieren un header `Authorization: Bearer `. +Los access tokens tienen una duracion de 15 minutos. Usa el endpoint `/api/auth/refresh` para obtener uno nuevo. + +--- + +## 1. Auth + +### POST /api/auth/register + +Registra un nuevo usuario. La cuenta inicia inactiva (requiere activacion por ADMIN). + +**Auth:** No requerida + +**Request body:** +```json +{ + "name": "Juan Perez", + "email": "juan@taller.com", + "password": "secreto123", + "role": "TALLER", + "business_name": "Taller Perez", + "phone": "555-1234", + "address": "Calle 1 #123" +} +``` + +| Campo | Tipo | Requerido | Descripcion | +|-------|------|-----------|-------------| +| name | string | Si | Nombre del usuario | +| email | string | Si | Email (unico) | +| password | string | Si | Password (se hashea con bcrypt) | +| role | string | Si | `TALLER` o `BODEGA` | +| business_name | string | Si | Nombre del negocio | +| phone | string | No | Telefono | +| address | string | No | Direccion | + +**Response 201:** +```json +{ + "message": "Registration successful. Account pending activation." +} +``` + +**Response 409:** +```json +{ + "error": "Email already registered" +} +``` + +--- + +### POST /api/auth/login + +Autentica un usuario y retorna access + refresh tokens. + +**Auth:** No requerida + +**Request body:** +```json +{ + "email": "juan@taller.com", + "password": "secreto123" +} +``` + +**Response 200:** +```json +{ + "access_token": "eyJhbGci...", + "refresh_token": "abc123def456...", + "user": { + "id": 1, + "name": "Juan Perez", + "role": "TALLER", + "business_name": "Taller Perez" + } +} +``` + +**Errores:** +- `401` - Email o password invalido +- `403` - Cuenta no activa + +--- + +### POST /api/auth/refresh + +Renueva un access token usando un refresh token valido. + +**Auth:** No requerida + +**Request body:** +```json +{ + "refresh_token": "abc123def456..." +} +``` + +**Response 200:** +```json +{ + "access_token": "eyJhbGci..." +} +``` + +**Errores:** +- `401` - Refresh token invalido o expirado + +--- + +### GET /api/auth/me + +Retorna la informacion del usuario autenticado (extraida del JWT). + +**Auth:** Cualquier rol autenticado + +**Response 200:** +```json +{ + "user_id": 1, + "role": "TALLER", + "business_name": "Taller Perez" +} +``` + +--- + +## 2. Admin - User Management + +### GET /api/admin/users + +Lista todos los usuarios registrados. + +**Auth:** `ADMIN`, `OWNER` + +**Response 200:** +```json +[ + { + "id": 1, + "name": "Juan Perez", + "email": "juan@taller.com", + "business_name": "Taller Perez", + "phone": "555-1234", + "is_active": true, + "created_at": "2026-03-01T10:00:00", + "last_login": "2026-03-18T08:30:00", + "role": "TALLER" + } +] +``` + +--- + +### PUT /api/admin/users/{user_id}/activate + +Activa o desactiva un usuario. + +**Auth:** `ADMIN`, `OWNER` + +**Request body:** +```json +{ + "is_active": true +} +``` + +**Response 200:** +```json +{ + "message": "User updated", + "is_active": true +} +``` + +--- + +### GET /api/admin/stats + +Estadisticas generales del catalogo. Usa `pg_class.reltuples` para tablas grandes (performance). + +**Auth:** No requerida (publico) + +**Response 200:** +```json +{ + "categories": 10, + "groups": 150, + "manufacturers": 200, + "parts": 1400000, + "aftermarket": 300000, + "fitment": 12000000000 +} +``` + +--- + +## 3. Catalog - Brands, Models, Years, Engines ### GET /api/brands -Obtiene la lista de todas las marcas de vehículos disponibles. +Lista todas las marcas que tienen vehiculos en la base de datos. -**Request:** -```bash -curl http://localhost:5000/api/brands +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| detailed | bool | Si `true`, incluye `model_count` y `vehicle_count` | +| region | int | Bitmask de region para filtrar marcas | + +**Response 200 (simple):** +```json +["ACURA", "AUDI", "BMW", "CHEVROLET", "FORD", "HONDA", "TOYOTA"] ``` -**Response:** +**Response 200 (detailed=true):** ```json -{ - "brands": [ - { - "id": 1, - "name": "Toyota", - "country": "Japan", - "founded_year": 1937 - }, - { - "id": 2, - "name": "Honda", - "country": "Japan", - "founded_year": 1948 - } - ] -} +[ + { + "name": "TOYOTA", + "model_count": 85, + "vehicle_count": 4200 + } +] ``` --- ### GET /api/models -Obtiene modelos de vehículos, opcionalmente filtrados por marca. +Lista modelos, opcionalmente filtrados por marca. -**Parámetros:** -| Parámetro | Tipo | Requerido | Descripción | -|-----------|------|-----------|-------------| -| brand | string | No | Nombre de la marca para filtrar | +**Auth:** No requerida -**Request:** -```bash -# Todos los modelos -curl http://localhost:5000/api/models +**Query params:** -# Modelos de Toyota -curl "http://localhost:5000/api/models?brand=Toyota" +| Param | Tipo | Descripcion | +|-------|------|-------------| +| brand | string | Nombre de la marca (ILIKE) | +| detailed | bool | Si `true` con brand, incluye year_min/max, vehicle_count, engine_count | + +**Response 200 (simple):** +```json +["4RUNNER", "CAMRY", "COROLLA", "HIGHLANDER", "RAV4"] ``` -**Response:** +**Response 200 (detailed=true&brand=TOYOTA):** ```json -{ - "models": [ - { - "id": 1, - "name": "Camry", - "brand": "Toyota", - "body_type": "Sedan", - "generation": "XV70", - "production_start_year": 2017, - "production_end_year": null - } - ] -} +[ + { + "name": "CAMRY", + "year_min": 1987, + "year_max": 2026, + "year_count": 40, + "vehicle_count": 320, + "engine_count": 15 + } +] ``` --- ### GET /api/years -Obtiene todos los años disponibles en la base de datos. +Lista anos disponibles, opcionalmente filtrados. -**Request:** -```bash -curl http://localhost:5000/api/years -``` +**Auth:** No requerida -**Response:** +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| brand | string | Filtrar por marca | +| model | string | Filtrar por modelo | + +**Response 200:** ```json -{ - "years": [1990, 1991, 1992, ..., 2024, 2025] -} +[2026, 2025, 2024, 2023, 2022] ``` --- ### GET /api/engines -Obtiene todos los motores disponibles. +Lista motores disponibles, opcionalmente filtrados. -**Request:** -```bash -curl http://localhost:5000/api/engines +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| brand | string | Filtrar por marca | +| model | string | Filtrar por modelo | +| year | int | Filtrar por ano | + +**Response 200:** +```json +["1.8L I4 Gas", "2.0L I4 Hybrid", "2.5L I4 Gas"] ``` -**Response:** +--- + +### GET /api/vehicles + +Busqueda de vehiculos con filtros y paginacion. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Default | Descripcion | +|-------|------|---------|-------------| +| brand | string | - | Filtrar por marca | +| model | string | - | Filtrar por modelo | +| year | int | - | Filtrar por ano | +| engine | string | - | Filtrar por motor | +| page | int | 1 | Pagina | +| per_page | int | 50 | Items por pagina (max 100) | + +**Response 200:** ```json { - "engines": [ + "data": [ { - "id": 1, - "name": "2.5L 4-Cylinder", - "displacement_cc": 2500, - "cylinders": 4, - "fuel_type": "Gasoline", + "brand": "TOYOTA", + "model": "CAMRY", + "year": 2020, + "engine": "2.5L I4 Gas", "power_hp": 203, "torque_nm": 250, - "engine_code": "A25A-FKS" + "displacement_cc": 2487, + "cylinders": 4, + "fuel_type": "gasoline", + "trim_level": "LE", + "drivetrain": "FWD", + "transmission": "automatic" + } + ], + "pagination": { + "page": 1, + "per_page": 50, + "total": 320, + "total_pages": 7 + } +} +``` + +--- + +### GET /api/model-year-engine + +Similar a `/api/vehicles` pero retorna `id` (mye_id) para navegacion al catalogo de partes. + +**Auth:** No requerida + +**Query params:** Igual que `/api/vehicles`, mas `with_parts` (bool) para filtrar solo vehiculos con partes catalogadas. + +**Response 200:** +```json +{ + "data": [ + { + "id": 12345, + "brand": "TOYOTA", + "model": "CAMRY", + "year": 2020, + "engine": "2.5L I4 Gas", + "trim_level": "LE", + "drivetrain": "FWD", + "transmission": "automatic" + } + ], + "pagination": { "page": 1, "per_page": 50, "total": 120, "total_pages": 3 } +} +``` + +--- + +### GET /api/catalog/stats + +Estadisticas basicas del catalogo. + +**Auth:** No requerida + +**Response 200:** +```json +{ + "brands": 107, + "models": 10923, + "vehicles": 82456, + "parts": 1400000 +} +``` + +--- + +## 4. Parts Catalog + +### GET /api/categories + +Lista categorias de partes en estructura de arbol. + +**Auth:** No requerida + +**Response 200:** +```json +[ + { + "id": 1, + "name": "Engine", + "name_es": "Motor", + "slug": "engine", + "icon_name": "engine", + "display_order": 1, + "children": [ + { + "id": 5, + "name": "Engine Electrical", + "name_es": "Electrico del Motor", + "slug": "engine-electrical", + "icon_name": null, + "display_order": 2, + "children": [] + } + ] + } +] +``` + +--- + +### GET /api/categories/{category_id}/groups + +Lista grupos (subcategorias) dentro de una categoria. + +**Auth:** No requerida + +**Response 200:** +```json +[ + { + "id": 10, + "name": "Oil Filter", + "name_es": "Filtro de Aceite", + "slug": "oil-filter", + "display_order": 1 + } +] +``` + +--- + +### GET /api/parts + +Lista partes con paginacion y filtros. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| group_id | int | Filtrar por grupo | +| category_id | int | Filtrar por categoria | +| search | string | Busqueda por nombre o numero OEM (ILIKE) | +| page | int | Pagina (default 1) | +| per_page | int | Items por pagina (max 100) | + +**Response 200:** +```json +{ + "data": [ + { + "id": 500, + "oem_part_number": "04152-YZZA1", + "name": "Oil Filter", + "name_es": "Filtro de Aceite", + "group_id": 10, + "group_name": "Oil Filters", + "category_name": "Engine", + "image_url": "/static/parts_images/abc.jpg" + } + ], + "pagination": { "page": 1, "per_page": 50, "total": 200, "total_pages": 4 } +} +``` + +--- + +### GET /api/parts/{part_id} + +Detalle de una parte especifica. + +**Auth:** No requerida + +**Response 200:** +```json +{ + "id": 500, + "oem_part_number": "04152-YZZA1", + "name": "Oil Filter", + "name_es": "Filtro de Aceite", + "description": "Engine oil filter element", + "description_es": "Elemento de filtro de aceite del motor", + "group_id": 10, + "group_name": "Oil Filters", + "group_name_es": "Filtros de Aceite", + "category_id": 1, + "category_name": "Engine", + "category_name_es": "Motor", + "image_url": null +} +``` + +--- + +### GET /api/vehicles/{mye_id}/categories + +Categorias de partes disponibles para un vehiculo especifico. + +**Auth:** No requerida + +**Response 200:** +```json +[ + { + "id": 1, + "name": "Engine", + "name_es": "Motor", + "slug": "engine", + "icon_name": "engine", + "display_order": 1 + } +] +``` + +--- + +### GET /api/vehicles/{mye_id}/groups + +Grupos de partes disponibles para un vehiculo, opcionalmente filtrado por categoria. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| category_id | int | Filtrar por categoria | + +**Response 200:** +```json +[ + { + "id": 10, + "name": "Oil Filters", + "name_es": "Filtros de Aceite", + "slug": "oil-filters", + "display_order": 1, + "parts_count": 5 + } +] +``` + +--- + +### GET /api/vehicles/{mye_id}/parts + +Partes para un vehiculo especifico con paginacion. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| category_id | int | Filtrar por categoria | +| group_id | int | Filtrar por grupo | +| page | int | Pagina (default 1) | +| per_page | int | Items por pagina (max 100) | + +**Response 200:** +```json +{ + "data": [ + { + "id": 500, + "oem_part_number": "04152-YZZA1", + "name": "Oil Filter", + "name_es": "Filtro de Aceite", + "quantity_required": 1, + "position": "front", + "category_name": "Engine", + "group_name": "Oil Filters", + "image_url": null + } + ], + "pagination": { "page": 1, "per_page": 50, "total": 45, "total_pages": 1 } +} +``` + +--- + +## 5. Cross-References and Aftermarket + +### GET /api/manufacturers + +Lista fabricantes (OEM y aftermarket). + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| type | string | `oem`, `aftermarket`, `remanufactured` | +| quality_tier | string | `economy`, `standard`, `premium`, `oem` | + +**Response 200:** +```json +[ + { + "id": 1, + "name": "DENSO", + "type": "aftermarket", + "quality_tier": "premium", + "country": "Japan", + "logo_url": null, + "website": "https://denso.com" + } +] +``` + +--- + +### GET /api/parts/{part_id}/alternatives + +Alternativas aftermarket para una parte OEM. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| quality_tier | string | Filtrar por calidad | +| manufacturer_id | int | Filtrar por fabricante | + +**Response 200:** +```json +[ + { + "id": 100, + "part_number": "XP-1234", + "name": "Premium Oil Filter", + "name_es": "Filtro de Aceite Premium", + "manufacturer_name": "DENSO", + "manufacturer_id": 1, + "quality_tier": "premium", + "price_usd": 12.50, + "warranty_months": 24, + "in_stock": null + } +] +``` + +--- + +### GET /api/parts/{part_id}/cross-references + +Cross-references (numeros alternos) para una parte. + +**Auth:** No requerida + +**Response 200:** +```json +[ + { + "id": 50, + "cross_reference_number": "90915-YZZF1", + "reference_type": "oem_alternate", + "source": "TecDoc", + "notes": null + } +] +``` + +--- + +### GET /api/parts/{part_id}/availability + +Disponibilidad en bodegas activas que tienen la parte en stock. + +**Auth:** `TALLER`, `ADMIN`, `OWNER` + +**Response 200:** +```json +[ + { + "bodega": "Refacciones del Norte", + "price": 125.50, + "stock": 15, + "location": "Principal", + "updated_at": "2026-03-18T10:00:00" + } +] +``` + +--- + +### GET /api/parts/{part_id}/aftermarket + +Alternativas aftermarket y cross-references combinadas (endpoint publico). + +**Auth:** No requerida + +**Response 200:** +```json +{ + "alternatives": [ + { + "id": 100, + "part_number": "XP-1234", + "name": "Premium Oil Filter", + "manufacturer": "DENSO", + "quality_tier": "premium", + "price": 12.50, + "source": "aftermarket" + } + ], + "cross_references": [ + { + "number": "90915-YZZF1", + "source": "TecDoc", + "notes": null } ] } @@ -125,146 +756,718 @@ curl http://localhost:5000/api/engines --- -### GET /api/vehicles +### GET /api/aftermarket -Búsqueda de vehículos con múltiples filtros. +Lista partes aftermarket con paginacion y filtros. -**Parámetros:** -| Parámetro | Tipo | Requerido | Descripción | -|-----------|------|-----------|-------------| -| brand | string | No | Marca del vehículo | -| model | string | No | Modelo del vehículo | -| year | integer | No | Año del vehículo | -| engine | string | No | Nombre/código del motor | -| limit | integer | No | Límite de resultados (default: 100) | +**Auth:** No requerida -**Request:** -```bash -# Búsqueda completa -curl "http://localhost:5000/api/vehicles?brand=Toyota&model=Camry&year=2020" +**Query params:** -# Solo por marca -curl "http://localhost:5000/api/vehicles?brand=Honda" +| Param | Tipo | Descripcion | +|-------|------|-------------| +| manufacturer_id | int | Filtrar por fabricante | +| quality_tier | string | Filtrar por calidad | +| search | string | Buscar por nombre, part number o OEM number | +| page | int | Pagina (default 1) | +| per_page | int | Items por pagina (max 100) | -# Con límite -curl "http://localhost:5000/api/vehicles?brand=Ford&limit=50" -``` - -**Response:** +**Response 200:** ```json { - "vehicles": [ + "data": [ { - "brand": "Toyota", - "model": "Camry", - "year": 2020, - "body_type": "Sedan", - "generation": "XV70", - "engine_name": "2.5L 4-Cylinder", - "displacement_cc": 2500, - "cylinders": 4, - "fuel_type": "Gasoline", - "power_hp": 203, - "torque_nm": 250, - "engine_code": "A25A-FKS", - "trim_level": "LE", - "drivetrain": "FWD", - "transmission": "8-Speed Automatic" + "id": 100, + "part_number": "XP-1234", + "name": "Premium Oil Filter", + "oem_part_number": "04152-YZZA1", + "manufacturer_name": "DENSO", + "quality_tier": "premium", + "price_usd": 12.50 } ], - "total": 1 + "pagination": { "page": 1, "per_page": 50, "total": 300000, "total_pages": 6000 } } ``` --- -## Códigos de Respuesta +### GET /api/search/part-number/{part_number} -| Código | Descripción | -|--------|-------------| -| 200 | OK - Solicitud exitosa | -| 400 | Bad Request - Parámetros inválidos | -| 404 | Not Found - Recurso no encontrado | -| 500 | Internal Server Error - Error del servidor | +Busqueda por numero de parte en OEM, aftermarket y cross-references. -## Manejo de Errores +**Auth:** No requerida -Todas las respuestas de error siguen el formato: +**Response 200:** +```json +[ + { + "id": 500, + "oem_part_number": "04152-YZZA1", + "name": "Oil Filter", + "name_es": "Filtro de Aceite", + "match_type": "oem", + "matched_number": "04152-YZZA1" + }, + { + "id": 500, + "oem_part_number": "04152-YZZA1", + "name": "Oil Filter", + "name_es": "Filtro de Aceite", + "match_type": "cross_reference", + "matched_number": "90915-YZZF1" + } +] +``` + +--- + +## 6. Search + +### GET /api/search + +Busqueda combinada inteligente. Detecta automaticamente vehiculo + parte en el query. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Default | Descripcion | +|-------|------|---------|-------------| +| q | string | (requerido) | Texto de busqueda | +| type | string | `all` | `all`, `parts`, `vehicles` | +| category_id | int | - | Filtrar partes por categoria | +| limit | int | 50 | Limite de resultados | +| offset | int | 0 | Offset para paginacion | + +**Ejemplo:** `GET /api/search?q=Toyota Corolla 2020 oil filter` + +**Response 200:** +```json +{ + "parts": [ + { + "id": 500, + "oem_part_number": "04152-YZZA1", + "name": "Oil Filter", + "name_es": null, + "image_url": null, + "group_name": "Oil Filters", + "category_name": "Engine", + "match_type": "oem" + } + ], + "vehicles": [ + { + "id": 12345, + "brand": "TOYOTA", + "model": "COROLLA", + "year": 2020, + "engine": "1.8L I4 Gas" + } + ], + "vehicle_parts": [ + { + "id": 500, + "oem_part_number": "04152-YZZA1", + "name": "Oil Filter", + "group_name": "Oil Filters", + "category_name": "Engine", + "quantity": 1, + "position": null, + "match_type": "vehicle_part" + } + ], + "matched_vehicle": { + "id": 12345, + "brand": "TOYOTA", + "model": "COROLLA", + "year": 2020, + "engine": "1.8L I4 Gas" + }, + "total_count": 5 +} +``` + +--- + +### GET /api/search/parts + +Busqueda full-text en partes usando PostgreSQL `tsvector`. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| q | string | (requerido) Texto de busqueda | +| category_id | int | Filtrar por categoria | +| group_id | int | Filtrar por grupo | +| page | int | Pagina (default 1) | +| per_page | int | Items por pagina (max 100) | + +**Response 200:** +```json +{ + "data": [ + { + "id": 500, + "oem_part_number": "04152-YZZA1", + "name": "Oil Filter", + "name_es": "Filtro de Aceite", + "description": "Engine oil filter", + "group_name": "Oil Filters", + "category_name": "Engine", + "rank": 0.85 + } + ], + "pagination": { "page": 1, "per_page": 50, "total": 25, "total_pages": 1 } +} +``` + +--- + +## 7. VIN Decoder + +### GET /api/vin/decode/{vin} + +Decodifica un VIN de 17 caracteres via la API de NHTSA. Cacheado por 30 dias. + +**Auth:** No requerida + +**Response 200:** +```json +{ + "vin": "1HGBH41JXMN109186", + "make": "HONDA", + "model": "CIVIC", + "year": 2021, + "engine_info": { + "configuration": "In-Line", + "cylinders": 4, + "displacement_l": 2.0, + "fuel_type": "Gasoline" + }, + "body_class": "Sedan/Saloon", + "drive_type": "FWD", + "matched_vehicle": { + "mye_id": 5678, + "brand": "HONDA", + "model": "CIVIC", + "year": 2021, + "engine": "2.0L I4 Gas" + }, + "cached": false +} +``` + +--- + +### GET /api/vin/{vin}/parts + +Retorna partes organizadas por categoria para un VIN previamente decodificado. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| category_id | int | Filtrar por categoria | + +**Response 200:** +```json +{ + "vin": "1HGBH41JXMN109186", + "vehicle_info": { + "vin": "1HGBH41JXMN109186", + "make": "HONDA", + "model": "CIVIC", + "year": 2021, + "mye_id": 5678 + }, + "categories": [ + { + "id": 1, + "name": "Engine", + "name_es": "Motor", + "parts": [ + { + "id": 500, + "oem_part_number": "15400-RTA-004", + "name": "Oil Filter", + "name_es": "Filtro de Aceite", + "group_name": "Oil Filters", + "quantity_required": 1, + "position": null + } + ] + } + ] +} +``` + +--- + +### GET /api/vin/{vin}/match + +Vincula manualmente un VIN a un vehiculo (model_year_engine). + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| mye_id | int | (requerido) ID del model_year_engine | + +**Response 200:** +```json +{ + "success": true, + "vin": "1HGBH41JXMN109186", + "mye_id": 5678 +} +``` + +--- + +## 8. Diagrams + +### GET /api/diagrams + +Lista diagramas, opcionalmente filtrados por grupo. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| group_id | int | Filtrar por grupo de partes | + +**Response 200:** +```json +[ + { + "id": 1, + "name": "Front Suspension Assembly", + "name_es": "Ensamble de Suspension Delantera", + "group_id": 20, + "group_name": "Suspension", + "thumbnail_path": "/static/diagrams/thumb_001.jpg", + "display_order": 1 + } +] +``` + +--- + +### GET /api/diagrams/{diagram_id} + +Detalle de un diagrama con hotspots. + +**Auth:** No requerida + +**Response 200:** +```json +{ + "id": 1, + "name": "Front Suspension Assembly", + "name_es": "Ensamble de Suspension Delantera", + "group_id": 20, + "group_name": "Suspension", + "image_path": "static/diagrams/moog/front_suspension.png", + "image_url": "/static/diagrams/moog/front_suspension.png", + "svg_content": null, + "width": null, + "height": null, + "hotspots": [ + { + "id": 10, + "part_id": 500, + "callout_number": 1, + "label": null, + "shape": "circle", + "coords": "150,200,25", + "color": null, + "part_name": "Ball Joint", + "part_number": "K500123" + } + ] +} +``` + +--- + +### GET /api/vehicles/{mye_id}/diagrams + +Diagramas disponibles para un vehiculo especifico. + +**Auth:** No requerida + +--- + +### GET /api/vehicles/{mye_id}/diagrams/by-category + +Diagramas agrupados por categoria para un vehiculo. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| category_id | int | Filtrar por categoria | + +--- + +### GET /api/diagrams/{diagram_id}/hotspots + +Lista hotspots de un diagrama. + +**Auth:** No requerida + +--- + +### GET /api/diagrams/{diagram_id}/parts + +Partes asociadas a un diagrama (con cross-references). + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| mye_id | int | Filtrar por vehiculo especifico | + +--- + +### GET /api/diagrams/search + +Busqueda de diagramas por nombre o vehiculo. + +**Auth:** No requerida + +**Query params:** + +| Param | Tipo | Descripcion | +|-------|------|-------------| +| q | string | Texto de busqueda en nombre | +| brand | string | Filtrar por marca | +| model | string | Filtrar por modelo | + +--- + +## 9. Inventory (BODEGA) + +### GET /api/inventory/mapping + +Retorna el mapeo de columnas configurado para el usuario actual. + +**Auth:** `BODEGA`, `ADMIN` + +**Response 200:** +```json +{ + "mapping": { + "part_number": "NUMERO_PARTE", + "price": "PRECIO", + "stock": "EXISTENCIA", + "location": "ALMACEN" + } +} +``` + +--- + +### PUT /api/inventory/mapping + +Guarda o actualiza el mapeo de columnas CSV/Excel. + +**Auth:** `BODEGA`, `ADMIN` + +**Request body:** +```json +{ + "mapping": { + "part_number": "NUMERO_PARTE", + "price": "PRECIO", + "stock": "EXISTENCIA", + "location": "ALMACEN" + } +} +``` + +Los campos `part_number`, `price` y `stock` son requeridos en el mapeo. `location` es opcional (default: "Principal"). + +**Response 200:** +```json +{ + "message": "Mapping saved", + "mapping": { "part_number": "NUMERO_PARTE", "price": "PRECIO", "stock": "EXISTENCIA" } +} +``` + +--- + +### POST /api/inventory/upload + +Sube un archivo CSV o Excel (.xlsx) de inventario. Aplica el mapeo de columnas y hace UPSERT en `warehouse_inventory`. + +**Auth:** `BODEGA`, `ADMIN` + +**Request:** `multipart/form-data` con campo `file` + +Proceso: +1. Lee el mapeo de columnas del usuario +2. Parsea el archivo (CSV o Excel) +3. Para cada fila, busca la parte por OEM part number (o aftermarket part number) +4. UPSERT en `warehouse_inventory` (user_id, part_id, warehouse_location) + +**Response 200:** +```json +{ + "message": "Upload processed", + "upload_id": 5, + "imported": 450, + "errors": 12, + "error_samples": [ + { "row": 15, "error": "Part not found: XYZ-999" } + ] +} +``` + +--- + +### GET /api/inventory/uploads + +Historial de uploads del usuario (ultimos 50). + +**Auth:** `BODEGA`, `ADMIN` + +**Response 200:** +```json +[ + { + "id": 5, + "filename": "inventario_marzo.xlsx", + "status": "completed", + "rows_total": 462, + "rows_imported": 450, + "rows_errors": 12, + "created_at": "2026-03-18T10:00:00", + "completed_at": "2026-03-18T10:00:15" + } +] +``` + +--- + +### GET /api/inventory/items + +Lista paginada del inventario del usuario actual. + +**Auth:** `BODEGA`, `ADMIN` + +**Query params:** + +| Param | Tipo | Default | Descripcion | +|-------|------|---------|-------------| +| page | int | 1 | Pagina | +| per_page | int | 50 | Items por pagina (max 200) | +| q | string | - | Buscar por OEM number o nombre | + +**Response 200:** +```json +{ + "data": [ + { + "id": 100, + "part_id": 500, + "oem_part_number": "04152-YZZA1", + "name": "Oil Filter", + "price": 125.50, + "stock": 15, + "location": "Principal", + "updated_at": "2026-03-18T10:00:00" + } + ], + "pagination": { "page": 1, "per_page": 50, "total": 450, "total_pages": 9 } +} +``` + +--- + +### DELETE /api/inventory/items + +Elimina todo el inventario del usuario actual. + +**Auth:** `BODEGA`, `ADMIN` + +**Response 200:** +```json +{ + "message": "Inventory cleared", + "deleted": 450 +} +``` + +--- + +## 10. Admin CRUD + +Todos los endpoints CRUD de admin no requieren autenticacion actualmente (a implementar). + +### Categories + +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| POST | `/api/admin/categories` | Crear categoria | +| PUT | `/api/admin/categories/{id}` | Actualizar categoria | +| DELETE | `/api/admin/categories/{id}` | Eliminar categoria | + +### Groups + +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | `/api/admin/groups?category_id=X` | Listar grupos | +| POST | `/api/admin/groups` | Crear grupo | +| PUT | `/api/admin/groups/{id}` | Actualizar grupo | +| DELETE | `/api/admin/groups/{id}` | Eliminar grupo | + +### Parts + +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| POST | `/api/admin/parts` | Crear parte | +| PUT | `/api/admin/parts/{id}` | Actualizar parte | +| DELETE | `/api/admin/parts/{id}` | Eliminar parte | + +### Manufacturers + +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| POST | `/api/admin/manufacturers` | Crear fabricante | +| PUT | `/api/admin/manufacturers/{id}` | Actualizar fabricante | +| DELETE | `/api/admin/manufacturers/{id}` | Eliminar fabricante | + +### Aftermarket Parts + +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| POST | `/api/admin/aftermarket` | Crear parte aftermarket | +| PUT | `/api/admin/aftermarket/{id}` | Actualizar parte aftermarket | +| DELETE | `/api/admin/aftermarket/{id}` | Eliminar parte aftermarket | + +### Cross-References + +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | `/api/admin/crossref?page=1&per_page=50` | Listar cross-refs (paginado) | +| POST | `/api/admin/crossref` | Crear cross-reference | +| PUT | `/api/admin/crossref/{id}` | Actualizar cross-reference | +| DELETE | `/api/admin/crossref/{id}` | Eliminar cross-reference | + +### Fitment (Vehicle-Part Links) + +| Metodo | Endpoint | Descripcion | +|--------|----------|-------------| +| GET | `/api/admin/fitment?brand=X&model=Y&mye_id=Z` | Listar fitment (paginado) | +| POST | `/api/admin/fitment` | Crear fitment | +| DELETE | `/api/admin/fitment/{id}` | Eliminar fitment | + +### CSV Import + +`POST /api/admin/import/{type}` + +Tipos validos: `categories`, `groups`, `parts`, `manufacturers`, `aftermarket`, `crossref`, `fitment` + +**Request body:** +```json +{ + "records": [ + { "name": "Engine", "name_es": "Motor", "slug": "engine" } + ] +} +``` + +**Response 200:** +```json +{ + "imported": 10, + "errors": ["Row 3: duplicate key..."] +} +``` + +### CSV Export + +`GET /api/admin/export/{type}?page=1&per_page=1000` + +Tipos validos: `categories`, `groups`, `parts`, `manufacturers`, `aftermarket`, `crossref`, `fitment` + +**Response 200:** +```json +{ + "data": [ { "id": 1, "name": "Engine", "name_es": "Motor" } ], + "pagination": { "page": 1, "per_page": 1000, "total": 10, "total_pages": 1 } +} +``` + +--- + +## 11. Image Upload + +### POST /api/admin/upload-image + +Sube una imagen en base64 para partes. + +**Auth:** No requerida (a proteger) + +**Request body:** +```json +{ + "image": "data:image/png;base64,iVBORw0KGgo..." +} +``` + +**Response 200:** +```json +{ + "url": "/static/parts_images/abc123.png", + "filename": "abc123.png" +} +``` + +--- + +## Formato de Paginacion + +Todos los endpoints paginados retornan: ```json { - "error": "Descripción del error", - "code": 400 + "data": [], + "pagination": { + "page": 1, + "per_page": 50, + "total": 1000, + "total_pages": 20 + } } ``` -## Ejemplos de Uso +## Codigos de Error -### Python - -```python -import requests - -BASE_URL = "http://localhost:5000/api" - -# Obtener marcas -response = requests.get(f"{BASE_URL}/brands") -brands = response.json()["brands"] - -# Buscar vehículos -params = { - "brand": "Toyota", - "year": 2020, - "limit": 50 -} -response = requests.get(f"{BASE_URL}/vehicles", params=params) -vehicles = response.json()["vehicles"] -``` - -### JavaScript - -```javascript -const BASE_URL = 'http://localhost:5000/api'; - -// Obtener marcas -async function getBrands() { - const response = await fetch(`${BASE_URL}/brands`); - const data = await response.json(); - return data.brands; -} - -// Buscar vehículos -async function searchVehicles(filters) { - const params = new URLSearchParams(filters); - const response = await fetch(`${BASE_URL}/vehicles?${params}`); - const data = await response.json(); - return data.vehicles; -} - -// Uso -const vehicles = await searchVehicles({ - brand: 'Toyota', - year: 2020 -}); -``` - -### cURL - -```bash -# Obtener todas las marcas -curl -X GET http://localhost:5000/api/brands - -# Buscar vehículos Toyota del 2020 -curl -X GET "http://localhost:5000/api/vehicles?brand=Toyota&year=2020" - -# Obtener modelos de Honda -curl -X GET "http://localhost:5000/api/models?brand=Honda" -``` - -## Rate Limiting - -Actualmente no hay límites de tasa implementados. Para uso en producción, se recomienda implementar rate limiting. - -## CORS - -El servidor está configurado para aceptar solicitudes desde cualquier origen (CORS habilitado). Para producción, configure los orígenes permitidos apropiadamente. +| Codigo | Descripcion | +|--------|-------------| +| 400 | Bad request (datos faltantes o invalidos) | +| 401 | No autenticado (token faltante, invalido o expirado) | +| 403 | Sin permisos (rol insuficiente o cuenta inactiva) | +| 404 | Recurso no encontrado | +| 409 | Conflicto (e.g., email duplicado) | +| 500 | Error interno del servidor | +| 502 | Error en API externa (NHTSA) | +| 503 | API externa no disponible | diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..a68ba89 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,449 @@ +# Arquitectura - Nexus Autoparts + +## Vista General del Sistema + +``` ++-------------------+ +-------------------+ +-------------------+ +| | | | | | +| TecDoc (Apify) | | NHTSA VIN API | | CSV/Excel | +| Actor API | | vpic.nhtsa.gov | | (Bodega upload) | +| | | | | | ++--------+----------+ +--------+----------+ +--------+----------+ + | | | + | download/import | decode | upload + | | | + v v v ++--------+---------------------------+---------------------------+----------+ +| | +| Flask Server (server.py) | +| Puerto 5000 | +| | +| +-------------+ +-------------+ +-------------+ +-----------------+ | +| | Auth Module | | Catalog API | | Inventory | | Admin CRUD | | +| | (auth.py) | | (publico) | | (BODEGA) | | (import/export) | | +| | JWT + bcrypt | | | | CSV mapping | | | | +| +------+------+ +------+------+ +------+------+ +--------+--------+ | +| | | | | | ++---------+----------------+----------------+-------------------+-----------+ + | | | | + v v v v ++-------------------------------------------------------------------------+ +| | +| PostgreSQL (nexus_autoparts) | +| SQLAlchemy text() raw SQL | +| | +| +----------+ +----------+ +----------+ +----------+ +---------------+ | +| | brands | | models | | years | | engines | | fuel_type | | +| +----+-----+ +----+-----+ +----+-----+ +----+-----+ | drivetrain | | +| | | | | | transmission | | +| +------+------+------------+------------+ +---------------+ | +| | | +| v | +| +-----------------------+ | +| | model_year_engine | (MYE - tabla central de vehiculos) | +| | PK: id_mye | | +| | UNIQUE(model,year, | | +| | engine,trim_level) | | +| +----------+------------+ | +| | | +| | 1:N | +| v | +| +---------------------+ +---------------------+ | +| | vehicle_parts | | vehicle_diagrams | | +| | (12B+ rows) | | | | +| | mye_id + part_id | | mye_id + diagram_id | | +| +----------+----------+ +----------+----------+ | +| | | | +| v v | +| +---------------------+ +---------------------+ | +| | parts (1.4M+ OEM) | | diagrams | | +| | oem_part_number | | image_path | | +| | group_id -> groups | | group_id -> groups | | +| +---+------+----------+ +-----+---------------+ | +| | | | | +| | v v | +| | +--------------------+ +---------------------+ | +| | | part_groups | | diagram_hotspots | | +| | | category_id | | part_id, coords | | +| | +--------+-----------+ +---------------------+ | +| | | | +| | v | +| | +--------------------+ | +| | | part_categories | | +| | | (arbol jerarquico) | | +| | | parent_id -> self | | +| | +--------------------+ | +| | | +| +----------+-----------+ | +| | | | +| v v | +| +---------------------+ +------------------------+ | +| | aftermarket_parts | | part_cross_references | | +| | (300K+) | | (13M+) | | +| | oem_part_id -> parts| | part_id -> parts | | +| | manufacturer_id | | reference_type | | +| +----------+----------+ +------------------------+ | +| | | +| v | +| +---------------------+ | +| | manufacturers | | +| | type, quality_tier | | +| +---------------------+ | +| | +| === SaaS Tables === | +| | +| +----------+ +----------+ +---------------------+ +-------------+ | +| | users | | roles | | warehouse_inventory | | sessions | | +| | id_user | | ADMIN | | user_id + part_id | | refresh | | +| | id_rol | | OWNER | | price, stock | | token | | +| | email | | TALLER | | location | | expires_at | | +| | pass | | BODEGA | +---------------------+ +-------------+ | +| +----------+ +----------+ | +| +------------------------+ | +| | inventory_uploads | | +| | inventory_col_mappings | | +| +------------------------+ | +| | +| === Lookup Tables === | +| countries, materials, shapes, position_part, reference_type, | +| manufacture_type, quality_tier | +| | ++-------------------------------------------------------------------------+ + + | | | | + v v v v ++-------------------+ +----------+ +-------------+ +----------------+ +| login.html | | demo.html| | admin.html | | bodega.html | +| tienda.html | | (catalog)| | (CRUD + | | (inventory | +| pos.html | | | | users) | | upload/manage) | +| cuentas.html | | | | | | | +| captura.html | | | | | | | ++-------------------+ +----------+ +-------------+ +----------------+ + Frontend: HTML/CSS/JS vanilla (sin framework) + Shared: nav.js, shared.css +``` + +--- + +## Database Schema Overview + +### Tablas principales y sus relaciones + +**Vehiculos (jerarquia):** +``` +brands (id_brand, name_brand, country, region) + | + +--< models (id_model, brand_id, name_model, body_type) + | + +--< model_year_engine (id_mye, model_id, year_id, engine_id, trim_level) + | | | + | | +-- engines (id_engine, name_engine, displacement_cc, cylinders, power_hp) + | +-------- years (id_year, year_car) + | + +--< vehicle_parts (mye_id, part_id, quantity, position) + +--< vehicle_diagrams (mye_id, diagram_id) +``` + +**Partes (jerarquia):** +``` +part_categories (id, name, parent_id) <-- arbol recursivo + | + +--< part_groups (id, category_id, name) + | + +--< parts (id_part, oem_part_number, name, group_id) + | + +--< aftermarket_parts (oem_part_id -> parts, manufacturer_id, part_number) + +--< part_cross_references (part_id -> parts, cross_reference_number, type) + +--< vehicle_parts (part_id -> parts, mye_id) +``` + +**SaaS / Multi-tenant:** +``` +roles (id_rol: 1=ADMIN, 2=OWNER, 3=TALLER, 4=BODEGA) + | + +--< users (id_user, email, pass, id_rol, business_name, is_active) + | + +--< sessions (refresh_token, expires_at) + +--< warehouse_inventory (user_id, part_id, price, stock, location) + +--< inventory_uploads (user_id, filename, status, rows_imported) + +--< inventory_column_mappings (user_id, mapping JSON) +``` + +### Convenciones de nombres en PostgreSQL + +| Tabla | PK | Naming pattern | +|-------|-----|---------------| +| brands | `id_brand` | `name_brand` | +| models | `id_model` | `name_model` | +| years | `id_year` | `year_car` | +| engines | `id_engine` | `name_engine` | +| model_year_engine | `id_mye` | Tabla pivote central | +| parts | `id_part` | `name_part`, `oem_part_number` | +| part_categories | `id_part_category` | `name_part_category` | +| part_groups | `id_part_group` | `name_part_group` | +| manufacturers | `id_manufacture` | `name_manufacture` | + +--- + +## TecDoc Data Pipeline + +Pipeline de 3 fases para importar datos de TecDoc (el catalogo europeo de autopartes). + +``` +Fase 1: DOWNLOAD Fase 2: IMPORT Fase 3: LINK +(import_tecdoc.py download) (import_tecdoc.py import) (link_vehicle_parts.py) + ++------------------+ +------------------+ +------------------+ +| Apify TecDoc | | JSON files | | parts + | +| Actor API | | data/tecdoc/ | | model_year_engine| +| $69/month | | | | | +| HTTP 201 = run | | manufacturers/ | | Genera links | +| | --------> | models/ | ---------> | masivos en | +| typeId=1 (cars) | JSON | vehicles/ | INSERT | vehicle_parts | +| langId=4 (EN) | files | | partes + | (12B+ filas) | +| countryId=153(MX)| | Resumable: | vehiculos | | ++------------------+ | skips existing | +------------------+ + +------------------+ +``` + +### Scripts adicionales + +- **`import_tecdoc_parts.py`**: Importa partes OEM y aftermarket desde TecDoc +- **`import_live.py`**: Importa datos en tiempo real (sin bajar a JSON primero) +- **`migrate_aftermarket.py`**: Normaliza datos aftermarket a la estructura con `quality_tier`, `manufacturers` + +### Filtros de importacion + +- Se descartan variantes regionales (e.g., "TOYOTA (GAC)") +- `countryFilterId=153` limita a vehiculos vendidos en Mexico +- El script es resumable: si un JSON ya existe en `data/tecdoc/`, se salta + +--- + +## Auth Flow + +Flujo de autenticacion basado en JWT con refresh tokens. + +``` + Cliente Servidor PostgreSQL + | | | + | POST /api/auth/register | | + | {name, email, pass, role} | | + |------------------------------>| bcrypt.hash(pass) | + | |----------------------------->| + | | INSERT users (is_active=F) | + | 201 "pending activation" | | + |<------------------------------| | + | | | + | (Admin activa la cuenta) | | + | | | + | POST /api/auth/login | | + | {email, password} | | + |------------------------------>| SELECT users WHERE email | + | |<-----------------------------| + | | bcrypt.check(pass) | + | | Verify is_active=true | + | | | + | | jwt.encode(user_id, role, | + | | business_name, exp=15min) | + | | | + | | secrets.token_urlsafe(48) | + | | INSERT sessions | + | |----------------------------->| + | | | + | {access_token, refresh_token,| | + | user: {id, name, role}} | | + |<------------------------------| | + | | | + | GET /api/... (protected) | | + | Authorization: Bearer | | + |------------------------------>| jwt.decode(AT) | + | | Check role in allowed_roles | + | | Set g.user = {user_id, role}| + | 200 {data} | | + |<------------------------------| | + | | | + | (Access token expires) | | + | | | + | POST /api/auth/refresh | | + | {refresh_token} | | + |------------------------------>| SELECT sessions | + | |<-----------------------------| + | | Check expires_at > now() | + | | jwt.encode(new access_token)| + | {access_token} | | + |<------------------------------| | +``` + +### Roles y permisos + +| Rol | ID | Permisos | +|-----|----|----------| +| `ADMIN` | 1 | Todo: gestionar usuarios, catalogo, inventario | +| `OWNER` | 2 | Gestionar usuarios, ver estadisticas | +| `TALLER` | 3 | Consultar catalogo, ver disponibilidad en bodegas | +| `BODEGA` | 4 | Gestionar inventario propio, subir CSV/Excel | + +### JWT Token payload + +```json +{ + "user_id": 1, + "role": "TALLER", + "business_name": "Taller Perez", + "type": "access", + "exp": 1742300000, + "iat": 1742299100 +} +``` + +--- + +## Inventory Flow (Bodega) + +Flujo para que una bodega suba su inventario via CSV/Excel. + +``` + Bodega (Browser) Servidor PostgreSQL + | | | + | 1. PUT /api/inventory/mapping| | + | {part_number: "NUM_PARTE", | | + | price: "PRECIO", | | + | stock: "EXISTENCIA", | UPSERT inventory_col_map | + | location: "ALMACEN"} |----------------------------->| + |<------------------------------| | + | | | + | 2. POST /api/inventory/upload| | + | multipart/form-data: file | | + |------------------------------>| | + | | a) Read mapping | + | |<-----------------------------| + | | | + | | b) Parse CSV/Excel | + | | (openpyxl or csv module) | + | | | + | | c) For each row: | + | | - Extract part_number | + | | using mapping | + | | - Find part by OEM # | + | | - If not found, try | + | | aftermarket_parts | + | | - UPSERT warehouse_inv | + | |----------------------------->| + | | | + | {imported: 450, errors: 12} | d) Update inventory_uploads | + |<------------------------------|----------------------------->| +``` + +### Tabla `warehouse_inventory` + +```sql +warehouse_inventory ( + id_inventory BIGSERIAL PRIMARY KEY, + user_id INTEGER REFERENCES users, + part_id INTEGER REFERENCES parts, + price NUMERIC(12,2), + stock_quantity INTEGER DEFAULT 0, + warehouse_location VARCHAR(100) DEFAULT 'Principal', + updated_at TIMESTAMP, + UNIQUE(user_id, part_id, warehouse_location) +) +``` + +El UNIQUE constraint permite que una bodega tenga la misma parte en multiples ubicaciones (e.g., "Principal", "Sucursal Norte"). + +--- + +## Aftermarket Linking + +Como se relacionan partes OEM con alternativas aftermarket y cross-references. + +``` + +--------------------+ + | parts | + | (OEM catalog) | + | id_part: 500 | + | oem_part_number: | + | "04152-YZZA1" | + +--------+-----------+ + | + +--------------+--------------+ + | | + v v ++----------------------------+ +----------------------------+ +| aftermarket_parts | | part_cross_references | +| (alternativas) | | (numeros alternos) | +| | | | +| oem_part_id: 500 | | part_id: 500 | +| manufacturer_id: -> DENSO | | cross_reference_number: | +| part_number: "DXP-1234" | | "90915-YZZF1" | +| quality_tier: "premium" | | reference_type: | +| price_usd: 12.50 | | "oem_alternate" | +| warranty_months: 24 | | source: "TecDoc" | ++----------------------------+ +----------------------------+ +``` + +### Tipos de cross-reference + +| Tipo | Descripcion | +|------|-------------| +| `oem_alternate` | Otro numero OEM para la misma parte (mismo fabricante) | +| `supersession` | La parte fue reemplazada por un numero nuevo | +| `interchange` | Numero de un competidor que es equivalente | +| `competitor` | Referencia cruzada a otra marca | + +### Flujo de busqueda por numero de parte + +Cuando un taller busca un numero de parte, el sistema busca en 3 lugares: + +1. **`parts.oem_part_number`** - Match directo OEM +2. **`aftermarket_parts.part_number`** - Match en parte aftermarket, retorna el OEM original +3. **`part_cross_references.cross_reference_number`** - Match en cross-ref, retorna el OEM original + +Esto permite que el taller encuentre la parte sin importar que numero use (OEM, aftermarket, o numero alterno). + +### Calidad (quality_tier) + +| Tier | Descripcion | Ejemplo | +|------|-------------|---------| +| `economy` | Precio bajo, calidad basica | Marcas genericas | +| `standard` | Calidad media, buen balance | Monroe, Moog | +| `premium` | Calidad alta, cercana a OEM | Denso, Bosch | + +--- + +## Stack Frontend + +El frontend es HTML/CSS/JS vanilla sin framework. Cada pagina es independiente. + +``` +dashboard/ + +-- shared.css # Estilos compartidos (colores, layout, cards) + +-- nav.js # Navegacion compartida (inyecta sidebar/header) + +-- login.html + .css + .js + +-- demo.html # Catalogo publico + +-- admin.html + .js # Panel admin (CRUD, users, import/export) + +-- bodega.html + .css + .js # Inventory management + +-- tienda.html + .css + .js # Store view para talleres + +-- pos.html + .css + .js # Point of sale + +-- captura.html + .css + .js # Captura de partes + +-- cuentas.html + .css + .js # Gestion de cuentas + +-- dashboard.js # Logica del catalogo principal + +-- enhanced-search.js # Busqueda avanzada +``` + +### Patron de comunicacion con API + +Todas las paginas usan `fetch()` con el patron: + +```javascript +const token = localStorage.getItem('access_token'); +const res = await fetch('/api/...', { + headers: { 'Authorization': `Bearer ${token}` } +}); +const data = await res.json(); +``` + +### Nota sobre NUMERIC de PostgreSQL + +PostgreSQL retorna valores `NUMERIC` como strings. Todas las funciones de formato en JS usan `parseFloat()` para convertir antes de mostrar.