SITE.md
schema v1.1
source: local
--- schema_version: 1 site: app.cultivaleads.io last_verified: 2026-06-14 source: local login_required: true auth_strategy: COOKIE_API # sesión cookie 24h, email/password --- ## Overview CultivaLeads es un CRM SaaS B2B para gestión de leads y pipelines de ventas. Requiere sesión activa para todas las rutas (redirige a /login si no autenticado). ## Top-level routes - /dashboard → pages/dashboard.md - /leads → pages/leads-list.md - /leads/import → pages/leads-import.md - /leads/new → pages/leads-new.md # draft — no explorado completamente - /leads/:id → pages/lead-detail.md - /reports → pages/reports.md - /settings → sin cobertura — agent debe explorar - /billing → sin cobertura — agent debe explorar ## Common goals - Capturar leads vía CSV masivo → workflows/capture-lead.md - Actualizar estado de un lead → workflows/update-lead-status.md - Exportar reporte de pipeline → workflows/export-report.md ## Site-wide pitfalls - Requiere auth activa para TODAS las rutas (ver pitfalls.md) - El menú "Más acciones" solo aparece al hover sobre la fila de lead - Evitar paths /m/* (versión móvil, DOM diferente)
pages/ — Páginas Mapeadas
6 páginas
Tabla de rutas
| URL Pattern | page_id | Propósito | Cubierto |
|---|---|---|---|
/dashboard |
dashboard |
KPIs + resumen del pipeline | ✓ Cubierto |
/leads |
leads-list |
Listado filtrable con acciones masivas | ✓ Cubierto |
/leads/import |
leads-import |
Importación masiva CSV | ✓ Cubierto |
/leads/new |
leads-new |
Formulario de lead manual | ⚠ Draft |
/leads/:id |
lead-detail |
Ficha individual con historial | ✓ Cubierto |
/reports |
reports |
Generador de reportes PDF | ✓ Cubierto |
pages/leads-import.md — Detalle
--- schema_version: 1 page_id: leads-import url_patterns: - https://app.cultivaleads.io/leads/import purpose: importar leads en bloque desde archivo CSV last_verified: 2026-06-14 source: local ---
Visual anchors — página de importación
| Tipo | Anchor | Estabilidad |
|---|---|---|
| a11y | role=main, heading "Importar Leads" | Alta |
| testid | [data-testid="csv-upload-zone"] | Alta |
| selector_pattern | input[accept=".csv,text/csv"] | Media |
| pattern | dropzone con borde dashed visible | Baja |
Acciones en leads-import
action:open_import_page
Form B compact
pre
on /leads, logged_in
do
click [data-testid="import-btn"] OR hover row → click "Importar CSV" in [data-testid="more-actions-menu"]
post
URL is /leads/import AND [data-testid="csv-upload-zone"] visible
fail
menu not visible after hover | /login redirect | button_not_found
recover
navigate directly to /leads/import; if 403 → session expired, re-auth first
evidence
opencli browser session-01 find "Importar CSV" + state
action:upload_csv_file
Crítica — sin adapter
pre
on /leads/import AND csv-upload-zone visible AND csv_file_path ready
do: opencli browser set_file input[accept=".csv,text/csv"] <csv_file_path>
|| drag-and-drop file onto [data-testid="csv-upload-zone"]
|| drag-and-drop file onto [data-testid="csv-upload-zone"]
post
preview table renders with ≥1 row AND "N leads detectados" text appears
fail
error "formato no soportado" | preview empty | upload spinner loops >10s
recover
verify CSV encoding is UTF-8; if spinner loops: refresh page, retry once; if persists: escalate
evidence
opencli browser session-01 network (observed multipart/form-data POST /api/v1/leads/import/preview)
action:confirm_import
pre
preview table visible AND no validation errors shown
do
click role=button name="Confirmar importación"
post
success banner "X leads importados" visible OR redirect to /leads with toast
fail
validation errors list appears | button disabled | HTTP 422
recover
read validation errors; fix CSV; repeat upload_csv_file
evidence
opencli browser session-01 click + network
pages/lead-detail.md — Acciones de estado
action:update_lead_status
Adapter disponible
pre
on /leads/:id, lead_id known, logged_in, new_status ∈ {Nuevo, Contactado, Calificado, Perdido}
do: opencli cultivaleads lead update-status <lead_id> <new_status>
|| click [data-testid="status-dropdown"] → select option matching new_status
|| click [data-testid="status-dropdown"] → select option matching new_status
post
status badge updates to new_status within 2s; activity log entry created
fail
adapter typed_error | HTTP 409 conflict | status badge unchanged
recover
adapter_health_update: opencli cultivaleads lead update-status -> suspect; fallback to DOM dropdown
evidence
opencli cultivaleads lead update-status + opencli browser session-02 state
pages/reports.md — Exportar PDF
action:generate_pipeline_report
Sin adapter — browser only
pre
on /reports, logged_in, date_range selected, NO export modal currently open
do
select date range via [data-testid="date-range-picker"]; click role=button name="Generar reporte"
post
modal with preview appears AND "Descargar PDF" button visible
fail
prev modal still open (blocks new one) | date-range-picker not responding | spinner >15s
recover
if prev modal open: click [role=button][aria-label="Cerrar"] first; see pitfall:export_modal_blocking
evidence
opencli browser session-03 analyze + network (POST /api/v1/reports/generate)
workflows/ — Flujos de Tarea
3 workflows
Goal
Cargar un archivo CSV con ≥1 leads y confirmar la importación masiva en CultivaLeads. Aplica cuando el usuario tiene una lista externa de prospectos.
State Signature
entry: logged_in, csv_file_path available
success: toast "N leads importados" visible en /leads
success: toast "N leads importados" visible en /leads
Best Path — Browser (sin adapter)
1. navigate /leads/import (action:open_import_page)
2. action:upload_csv_file in pages/leads-import.md
3. action:confirm_import in pages/leads-import.md
2. action:upload_csv_file in pages/leads-import.md
3. action:confirm_import in pages/leads-import.md
Fallback
Si /leads/import falla con 404: crear leads uno a uno via /leads/new (más lento, ~N turns).
Avoid
• No intentar la ruta móvil /m/leads/import — DOM diferente
• No usar drag-drop como first intent (inestable en headless)
• No usar drag-drop como first intent (inestable en headless)
Best Path — Adapter
opencli cultivaleads lead update-status <id> <status>
estimated_turns: 1
Preconditions
lead_id known · logged_in
status ∈ {Nuevo, Contactado, Calificado, Perdido}
status ∈ {Nuevo, Contactado, Calificado, Perdido}
Fallback path (on_adapter_fail)
on_adapter_fail:
- adapter_health_update:
opencli cultivaleads lead update-status
-> suspect
- opencli browser state (verify URL)
- if not on /leads/:id: navigate /leads/:id
- action:update_lead_status in
pages/lead-detail.md (DOM fallback)
estimated_turns: 4
Stale markers
• Menú de estados cambia opciones (rebrand de "Calificado" → "Cualificado") · status dropdown moved to sidebar panel
Best Path — Browser Only
1. Navigate /reports
2. Dismiss any open export modal first (see pitfall:export_modal_blocking)
3. action:generate_pipeline_report in pages/reports.md
4. click "Descargar PDF" in modal → file download
2. Dismiss any open export modal first (see pitfall:export_modal_blocking)
3. action:generate_pipeline_report in pages/reports.md
4. click "Descargar PDF" in modal → file download
State Signature
entry: /reports, logged_in, no modal open
mid: modal visible with preview
success: file download triggered (browser network: GET /api/v1/reports/:id/pdf)
mid: modal visible with preview
success: file download triggered (browser network: GET /api/v1/reports/:id/pdf)
Re-entry Checkpoints
on /reports, no modal → start step 3
modal visible + preview rendered → start step 4
modal visible + spinner → wait 5s then check network
modal visible + preview rendered → start step 4
modal visible + spinner → wait 5s then check network
State Validation
Network request GET /api/v1/reports/:id/pdf returns 200 + Content-Type: application/pdf
Avoid
No abrir el modal mientras otro está abierto (bloqueo silencioso).
pitfalls.md
3 pitfalls verificados
pitfall:hidden_import_button
trigger:agent navega /leads y busca botón "Importar CSV" directamente visible
symptom:button_not_found; agent falla al intentar click sobre elemento inexistente
workaround:hacer hover sobre fila lead → esperar apertura de menú "Más acciones" → clickar "Importar CSV"; o navegar directamente a /leads/import
verified_at: 2026-06-14
pitfall:export_modal_blocking
trigger:agent intenta generar nuevo reporte mientras un modal de exportación anterior sigue abierto
symptom:botón "Generar reporte" no responde; nuevo modal no aparece (bloqueado silenciosamente)
workaround:antes de generar, verificar ausencia de modal via `opencli browser find "Cerrar"`; si existe, cerrar con role=button aria-label="Cerrar"
verified_at: 2026-06-14
pitfall:session_expiry_redirect
trigger:agent ejecuta acción >24h después de la última autenticación
symptom:redirect a /login con parámetro ?next=<original_url>; acciones previas silenciadas
workaround:detectar URL /login en cada estado post-acción; re-autenticar y navegar de vuelta a ?next URL; reintentar acción original
verified_at: 2026-06-14
Nota de scope: Los pitfalls anteriores son de nivel task-executor (acciones que el agente ejecuta). Los bugs internos del adaptador (ej. rotación de queryId en la API) se documentan en
~/.opencli/sites/app.cultivaleads.io/notes.md, no aquí.
apis.md — Endpoints Observados
source: local
endpoint:leads_import_preview
triggers_on_pages:
[leads-import]triggered_by_actions:
[upload_csv_file]contract_strength:
internal-unstablenotes: multipart POST /api/v1/leads/import/preview — responde preview array sin persistir
endpoint:leads_import_confirm
triggers_on_pages:
[leads-import]triggered_by_actions:
[confirm_import]contract_strength:
internal-unstableendpoint:leads_list_v1
triggers_on_pages:
[leads-list, dashboard]triggered_by_actions:
[page_load, apply_filter]contract_strength:
visible-ui (usado por adapter opencli cultivaleads leads list)endpoint:report_generate
triggers_on_pages:
[reports]triggered_by_actions:
[generate_pipeline_report]contract_strength:
internal-unstablenotes: POST /api/v1/reports/generate → returns report_id; luego GET /api/v1/reports/:id/pdf para descarga
Regla: Este archivo solo contiene endpoint_id ↔ trigger mappings. URL, params y response shapes viven exclusivamente en
~/.opencli/sites/app.cultivaleads.io/endpoints.json. No duplicar esquemas aquí.
Estructura de archivos generada
Storage Model v1.1
~/.opencli/sites/app.cultivaleads.io/
├── sitemap/
│ ├── SITE.md~320 tok↑ local overlay
│ ├── pages/
│ │ ├── dashboard.md~280 tok
│ │ ├── leads-list.md~540 tok
│ │ ├── leads-import.md~680 tok≤800 ✓
│ │ ├── lead-detail.md~470 tok
│ │ ├── reports.md~390 tok
│ │ └── draft-leads-new.md⚠ draft, no explorado completo
│ ├── workflows/
│ │ ├── capture-lead.md~420 tok
│ │ ├── update-lead-status.md~380 tok
│ │ └── export-report.md~460 tok
│ ├── pitfalls.md~290 tok
│ └── apis.md~310 tok
├── endpoints.jsonsource of truth para URL/params/response
└── notes.mdadapter-internal bugs (no van a sitemap)
├── sitemap/
│ ├── SITE.md~320 tok↑ local overlay
│ ├── pages/
│ │ ├── dashboard.md~280 tok
│ │ ├── leads-list.md~540 tok
│ │ ├── leads-import.md~680 tok≤800 ✓
│ │ ├── lead-detail.md~470 tok
│ │ ├── reports.md~390 tok
│ │ └── draft-leads-new.md⚠ draft, no explorado completo
│ ├── workflows/
│ │ ├── capture-lead.md~420 tok
│ │ ├── update-lead-status.md~380 tok
│ │ └── export-report.md~460 tok
│ ├── pitfalls.md~290 tok
│ └── apis.md~310 tok
├── endpoints.jsonsource of truth para URL/params/response
└── notes.mdadapter-internal bugs (no van a sitemap)
Two-layer model: La overlay local (~/.opencli) gana ante el global seed (sitemaps/app.cultivaleads.io/).
Promover a global solo tras revisión. Drafts SIEMPRE dentro de sitemap/, nunca en el nivel padre.