docs: add catalog vehicle navigation design spec
Catalog redesign: TecDoc hierarchical navigation (Brand→Model→Year→Engine→Category→Parts) with local stock + bodega availability + aftermarket alternatives. Offline fallback to local inventory. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
211
docs/plans/2026-04-01-catalog-vehiculo-design.md
Normal file
211
docs/plans/2026-04-01-catalog-vehiculo-design.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# Catálogo POS con Navegación por Vehículo — Design Spec
|
||||
|
||||
**Date:** 2026-04-01
|
||||
**Status:** Approved
|
||||
**Goal:** Rediseñar el catálogo del POS para navegar el catálogo TecDoc completo (1.5M+ partes) por vehículo (Marca → Modelo → Año → Motor → Categoría → Subcategoría → Partes), mostrando stock local + stock de bodegas + alternativas aftermarket.
|
||||
|
||||
---
|
||||
|
||||
## 1. Arquitectura
|
||||
|
||||
### Dos fuentes de datos
|
||||
|
||||
- **nexus_autoparts DB** (servidor central): catálogo TecDoc (brands, models, years, engines, model_year_engine, part_categories, part_groups, parts, vehicle_parts, part_cross_references, aftermarket_parts, warehouse_inventory)
|
||||
- **tenant DB** (por refaccionaria): inventario local (inventory, inventory_operations)
|
||||
|
||||
El catalog_bp.py consulta ambas DBs. Para nexus_autoparts usa una conexión directa (misma máquina). Para el tenant usa get_tenant_conn() existente.
|
||||
|
||||
### Flujo de navegación
|
||||
|
||||
```
|
||||
Marca (619) → Modelo (13K) → Año (78) → Motor (30K MYE) → Categoría (36) → Subcategoría (493) → Partes
|
||||
↓
|
||||
Panel lateral:
|
||||
- Stock local
|
||||
- Stock bodegas
|
||||
- Alternativas
|
||||
- [Agregar al carrito]
|
||||
```
|
||||
|
||||
### Conexión entre tablas
|
||||
|
||||
```
|
||||
brands → models (brand_id) → model_year_engine (model_id + year_id + engine_id)
|
||||
↓
|
||||
vehicle_parts (model_year_engine_id)
|
||||
↓
|
||||
parts (id_part) → part_groups (group_id) → part_categories (category_id)
|
||||
↓
|
||||
part_cross_references + aftermarket_parts (alternativas)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Endpoints (9 total)
|
||||
|
||||
Todos bajo `/pos/api/catalog/`. Requieren auth JWT del tenant.
|
||||
|
||||
### Navegación jerárquica
|
||||
|
||||
**GET /pos/api/catalog/brands**
|
||||
- Source: nexus_autoparts.brands
|
||||
- Response: `{data: [{id_brand, name_brand}]}` ordenado alfabéticamente
|
||||
- Solo marcas que tienen model_year_engine con partes vinculadas
|
||||
|
||||
**GET /pos/api/catalog/models?brand_id=X**
|
||||
- Source: nexus_autoparts.models WHERE brand_id = X
|
||||
- Response: `{data: [{id_model, name_model}]}`
|
||||
|
||||
**GET /pos/api/catalog/years?model_id=X**
|
||||
- Source: nexus_autoparts.model_year_engine JOIN years WHERE model_id = X
|
||||
- Response: `{data: [{id_year, year_car}]}` ordenado DESC (más reciente primero)
|
||||
- Solo años que tienen MYE entries para ese modelo
|
||||
|
||||
**GET /pos/api/catalog/engines?model_id=X&year_id=Y**
|
||||
- Source: nexus_autoparts.model_year_engine JOIN engines WHERE model_id AND year_id
|
||||
- Response: `{data: [{id_mye, name_engine, trim_level}]}`
|
||||
|
||||
**GET /pos/api/catalog/categories?mye_id=X**
|
||||
- Source: nexus_autoparts.vehicle_parts JOIN parts JOIN part_groups JOIN part_categories WHERE mye_id
|
||||
- Response: `{data: [{id_part_category, name_part_category, part_count}]}`
|
||||
- Solo categorías que tienen partes para ese vehículo
|
||||
|
||||
**GET /pos/api/catalog/groups?mye_id=X&category_id=Y**
|
||||
- Source: nexus_autoparts.vehicle_parts JOIN parts JOIN part_groups WHERE mye_id AND category_id
|
||||
- Response: `{data: [{id_part_group, name_part_group, part_count}]}`
|
||||
|
||||
### Partes con disponibilidad
|
||||
|
||||
**GET /pos/api/catalog/parts?mye_id=X&group_id=Y**
|
||||
- Source: nexus_autoparts (partes) + tenant DB (stock local)
|
||||
- Para cada parte:
|
||||
1. Datos base de nexus_autoparts.parts
|
||||
2. Stock local: busca en tenant_db.inventory WHERE part_number = oem_part_number OR catalog_part_id = part_id
|
||||
3. Indicador de disponibilidad en bodegas (count de warehouse_inventory con stock > 0)
|
||||
- Response: `{data: [{id_part, oem_part_number, name_part, description, local_stock, local_price, bodega_count}]}`
|
||||
- Paginado (default 30 per page)
|
||||
|
||||
**GET /pos/api/catalog/part/\<part_id\>**
|
||||
- Source: nexus_autoparts + tenant DB + warehouse_inventory
|
||||
- Response detallada:
|
||||
```json
|
||||
{
|
||||
"part": {id, oem_part_number, name_part, description, image_url, group_name, category_name},
|
||||
"local": {stock, price_1, price_2, price_3, inventory_id} | null,
|
||||
"bodegas": [{business_name, price, stock, location}],
|
||||
"alternatives": [{part_number, manufacturer, name, local_stock, bodega_count}]
|
||||
}
|
||||
```
|
||||
- Alternativas: busca en part_cross_references + aftermarket_parts para el mismo part_id
|
||||
|
||||
### Búsqueda inteligente
|
||||
|
||||
**GET /pos/api/catalog/search?q=...**
|
||||
- Lógica:
|
||||
- Si q contiene números + guiones (regex `\d.*-|-.* \d`): busca en parts.oem_part_number ILIKE
|
||||
- Si es texto: busca en parts.name_part ILIKE + parts.description ILIKE
|
||||
- Enriquece con stock local del tenant
|
||||
- Response: `{data: [{id_part, oem_part_number, name_part, local_stock, local_price, vehicle_info}]}`
|
||||
- vehicle_info: obtiene marca+modelo del primer vehicle_parts match
|
||||
- Límite: 50 resultados
|
||||
|
||||
---
|
||||
|
||||
## 3. UI del Catálogo
|
||||
|
||||
### Layout principal
|
||||
|
||||
- Barra superior: búsqueda inteligente + botón carrito con badge
|
||||
- Breadcrumb de navegación (click para regresar a cualquier nivel)
|
||||
- Área principal: cards/lista según el nivel de navegación
|
||||
- Panel lateral derecho: detalle de parte seleccionada (slide-in)
|
||||
- Banner inferior: status de conexión (online/offline)
|
||||
|
||||
### Niveles de navegación
|
||||
|
||||
1. **Marcas**: grid de cards con nombre (logo futuro). Filtro de texto rápido
|
||||
2. **Modelos**: lista filtrable con búsqueda inline
|
||||
3. **Años**: botones horizontales ordenados DESC
|
||||
4. **Motores**: cards con nombre del motor y trim
|
||||
5. **Categorías**: cards con nombre y conteo de partes
|
||||
6. **Subcategorías**: cards con nombre y conteo
|
||||
7. **Partes**: grid de cards con OEM, nombre, marca, badge de stock (verde/amarillo/rojo/gris)
|
||||
|
||||
### Badges de stock en lista de partes
|
||||
|
||||
- ✅ Verde: hay stock local
|
||||
- ⚠️ Amarillo: sin stock local pero hay en bodegas
|
||||
- ❌ Rojo: sin stock en ningún lado (pero hay alternativas)
|
||||
- ⬜ Gris: no disponible en absoluto
|
||||
|
||||
### Panel lateral de detalle
|
||||
|
||||
Al clickear una parte:
|
||||
- Nombre completo, número OEM, descripción
|
||||
- **Mi stock**: cantidad + precio (price_1/2/3 según tier del cliente seleccionado)
|
||||
- **En bodegas**: tabla de bodegas con stock y precio
|
||||
- **Alternativas** (si sin stock local ni bodegas): lista de cross-references con su disponibilidad
|
||||
- Selector de cantidad + **botón "Agregar al carrito"**
|
||||
- Selector de fuente: "De mi stock" o "Pedir a bodega X" (si no tiene local)
|
||||
|
||||
### Carrito
|
||||
|
||||
- Mismo carrito que ya existe (localStorage)
|
||||
- Al agregar, indica la fuente (local o bodega)
|
||||
- "Ir a cobrar" → POS con carrito pre-cargado
|
||||
|
||||
### Breadcrumb
|
||||
|
||||
```
|
||||
Inicio > Toyota > Corolla > 2020 > 1.8L 4cyl > Frenos > Pastillas
|
||||
```
|
||||
Click en cualquier nivel navega de regreso.
|
||||
|
||||
### Búsqueda inteligente
|
||||
|
||||
- Un campo único arriba
|
||||
- Al escribir, detecta si es número de parte o texto
|
||||
- Resultados en dropdown con: OEM, nombre, vehículo compatible
|
||||
- Click en resultado abre el panel lateral directamente
|
||||
|
||||
---
|
||||
|
||||
## 4. Modo offline (fallback)
|
||||
|
||||
- Cuando las llamadas a `/pos/api/catalog/brands` fallan (timeout o error de red):
|
||||
- Muestra banner "Modo offline — mostrando solo tu inventario"
|
||||
- Cambia a modo inventario local (grid plano del inventario del tenant)
|
||||
- Búsqueda funciona solo contra inventario local
|
||||
- Carrito sigue funcionando normalmente
|
||||
- Cuando regresa la conexión:
|
||||
- Auto-detecta (fetch periódico o evento online)
|
||||
- Restaura navegación TecDoc completa
|
||||
- Quita banner offline
|
||||
|
||||
---
|
||||
|
||||
## 5. Estilo visual
|
||||
|
||||
- Usa tokens.css existente (ambos temas: industrial y modern)
|
||||
- Mismo sidebar compartido (sidebar.js)
|
||||
- Cards de navegación usan componentes existentes del design system
|
||||
- Panel lateral usa el componente panel-deslizante del design system
|
||||
- Badges de stock usan los colores semánticos (--color-success, --color-warning, --color-error)
|
||||
- Responsive: sidebar colapsa en mobile, panel lateral se convierte en modal
|
||||
|
||||
---
|
||||
|
||||
## 6. Archivos a modificar/crear
|
||||
|
||||
### Backend
|
||||
- **Reescribir**: `/home/Autopartes/pos/blueprints/catalog_bp.py` — 9 endpoints nuevos
|
||||
- **Crear**: `/home/Autopartes/pos/services/catalog_service.py` — lógica de consulta a nexus_autoparts + enriquecimiento con stock local
|
||||
|
||||
### Frontend
|
||||
- **Reescribir**: `/home/Autopartes/pos/templates/catalog.html` — nueva UI con navegación jerárquica
|
||||
- **Reescribir**: `/home/Autopartes/pos/static/js/catalog.js` — lógica de navegación, búsqueda, panel lateral, carrito
|
||||
|
||||
### Sin cambios
|
||||
- app.py (ruta /pos/catalog ya existe)
|
||||
- sidebar.js, app-init.js, tokens.css (compartidos, sin cambios)
|
||||
- Otros blueprints y páginas (sin impacto)
|
||||
Reference in New Issue
Block a user