From d16b10d2eec27bc24afe59f5f564f7a5a130ce0e Mon Sep 17 00:00:00 2001 From: monomono Date: Sat, 15 Aug 2026 17:48:26 -0500 Subject: [PATCH] =?UTF-8?q?#49=20docs:=20documentar=20provenance=20(gr?= =?UTF-8?q?=C3=A1ficos,=20admin=20CRUD,=20patrones=20de=20testing)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 6100b1b..c802b38 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,8 +14,13 @@ src/ ├── assets/ # Imágenes, iconos estáticos ├── components/ # Componentes Vue reutilizables +│ ├── order/ # Componentes del resumen de pedido público +│ ├── provenance/ # Provenance (público + admin): gráficos, sección y CRUD admin +│ │ └── admin/ # Organizaciones, Proveedores, Geografía, SupplierLinkDialog +│ └── graph/ # CytoscapeChart.vue (wrapper genérico de cytoscape) ├── layouts/ # Layouts de página ├── pages/ # Vistas (auto-routed desde文件名) +│ └── admin/ # Páginas admin (products, organizations, suppliers, geography, ...) ├── plugins/ # Configuración de Vuetify, etc. ├── router/ # Configuración de rutas ├── services/ # API services (auth.js, etc.) @@ -23,6 +28,7 @@ src/ │ ├── api-implementation.js # Factory que selecciona implementación │ ├── auth.js # Manejo de auth (login, tokens JWT) │ ├── django-api.js # Implementación de API para Django +│ ├── graph/ # Genérico de grafos: graph-layout.js (layout por columnas + cytoscape) │ └── http.js # Axios instance con interceptors ├── stores/ # Pinia stores └── styles/ # SCSS settings @@ -89,12 +95,16 @@ No hay un estilo mayoritario. El código histórico está partido: ### Config de ESLint - `.eslintrc.js` está **versionado** y extiende `vuetify` (estilo **StandardJS**) - Tiene `ignorePatterns` masivo: `src/**` excepto los archivos nuevos de la tarea - (`!src/components/order/**`, `!src/components/PublicOrderSummary.vue`, `!src/pages/pedido/**`) + (`!src/components/order/**`, `!src/components/PublicOrderSummary.vue`, + `!src/components/provenance/**`, `!src/components/graph/*.vue`, + `!src/services/graph/*.js`, `!src/pages/pedido/**`) - **Los archivos nuevos deben seguir StandardJS** para quedar lint-eados: - 2 espacios (indent), sin semicolons, comillas simples - `function () {}` con espacio, `const f = (x) => x` (arrow-parens en args únicos NO) - Sin trailing commas; `{ clave: valor }` con espacios internos - Eventos personalizados en kebab-case, `v-slot:nombre` (no `#nombre`) + - Atributos en orden alfabético dentro de su categoría (`vue/attributes-order`): + directivas (`v-if`, `v-model`) primero, luego props/attrs, luego `@eventos` ### PELIGRO: `npm run lint` usa `--fix` - Reformatea automáticamente TODO archivo no ignorado que no cumpla estilo @@ -109,6 +119,9 @@ No hay un estilo mayoritario. El código histórico está partido: - Los tests **no usan globals**: importar `describe/it/expect/vi` explícitamente desde `vitest` - Tests de páginas con router: esperar a que el router actualice `route.params` con un helper (`waitForRouteParam`) - Los `.d.ts` generados (`auto-imports.d.ts`, `components.d.ts`, `typed-router.d.ts`) están en `.gitignore` +- **Diálogos Vuetify se teleportan a `document.body`**: en tests, el contenido NO está en `wrapper.text()`. Assertar sobre `document.body.textContent` (ver `tests/unit/components/provenance/ProvenanceDetailModal.spec.js`). Helpers para interactuar con inputs/buttons de diálogos en `tests/unit/components/provenance/admin/helpers.js` (`setBodyInput`, `clickBody`) +- **Selects/autocompletados en tests**: escribir en su `` NO cambia el `v-model`. Emitir `update:modelValue` sobre el componente (`findAllComponents({ name: 'VSelect' })` / `{ name: 'VAutocomplete' }`). OJO: `VAutocomplete` también matchea como `VSelect`, y `v-data-table` añade un `VSelect` (items-per-page); filtrar por `props('items')` cuando haya varios +- **Listas largas** (municipios, proveedores): `v-autocomplete` con búsqueda, pero la selección debe conservarse aunque el filtro no la incluya → `items` computado que devuelve los filtrados + los seleccionados que no estén (patrón en `SuppliersManagement.vue`, `GeographyManagement.vue`, `SupplierLinkDialog.vue`) ## Common Issues 1. **Página en blanco:** Verificar que los componentes en `src/pages/*.vue` tengan import explícito @@ -159,3 +172,14 @@ No hay un estilo mayoritario. El código histórico está partido: - `getPublicOrderSummary(code)` en `services/api.js` / `django-api.js` - Componentes modulares en `src/components/order/`: `OrderAccessInfo.vue` (código + link), `OrderCustomer.vue`, `OrderLines.vue`, `OrderPayment.vue`, `OrderTotal.vue` - Orquestador: `PublicOrderSummary.vue`; `OrderAccessInfo.vue` se comparte con `SummaryPurchase.vue` + +## Provenance (Origen e historia de los productos) +- Los gráficos se renderizan en el resumen público (`ProvenanceSection` dentro de `PublicOrderSummary.vue`) a partir de `product_provenance` embebido en el resumen (`GET /don_confiao/resumen_publico/`). El backend NO genera los gráficos. +- Payload: `[{ product: {id, name, catalogue_images[]}, suppliers: [{ supplier: {...}, organization|null, municipality|null, department|null, country|null }] }]`. +- **Genérico reutilizable:** + - `src/services/graph/graph-layout.js`: `computeColumnLayout` (layout por columnas puro) y `toCytoscapeElements` (adapta nodos/aristas a cytoscape, añade clase `has-image` si el nodo tiene imagen) + - `src/components/graph/CytoscapeChart.vue`: wrapper de cytoscape.js (props `elements`, `styles` (map a `style` en cytoscape), `layout`, `height`; emite `select` con `node.data()`) +- **Específico público** (`src/components/provenance/`): builders puros en `provenance-graph.js` (`buildSupplierOrganizationGraph`, `buildTerritoryGraph`, `hasAnySupplier`, `hasAnyTerritory`), los charts (que muestran "próximamente estará disponible" cuando no hay relaciones), `ProvenanceDetailModal.vue` y `ProvenanceSection.vue` +- **Admin CRUD** (`src/components/provenance/admin/`): `OrganizationsManagement.vue`, `SuppliersManagement.vue`, `GeographyManagement.vue` (tabs países/departamentos/municipios), `SupplierLinkDialog.vue` (vincula productos↔proveedores, abierto desde `ProductsManagement.vue`). Páginas en `src/pages/admin/{organizations,suppliers,geography}.vue`; rutas en `ADMIN_ROUTES` (`router/index.js`); ítems en `NavBar.vue` +- **Endpoints provenance**: `/don_confiao/api/organizations/`, `/suppliers/`, `/countries/`, `/departments/`, `/municipalities/` (CRUD); vincular productos con `PATCH /don_confiao/api/products//` body `{"suppliers": [ids]}`; detalle de producto (con `suppliers`) via `GET /don_confiao/api/products//` +- Los tests mockean cytoscape (`vi.mock('cytoscape', ...)`) y la API con `global.provide: { api }`