Files
qwen3-6-lora/data/raw/sanitized/plans/puedes-revisar-los-tickets-cheerful-catmull.md

113 lines
7.1 KiB
Markdown

# GFIBER-711 — Tutorial interactivo de My Usage
## Contexto
GFIBER-711 ("Tutorial: My Usage") es la tercera subtarea de GFIBER-710 ("Implement
additional in-app tutorials") que se aborda, después de GFIBER-702 (Upsell Evaluator,
mergeado a `dev`) y GFIBER-712 (Dashboard, actualmente en curso en background vía
`agente-gfiber-712-dashboard-tour`, todavía no mergeado). Quedan además GFIBER-713 (Admin)
y GFIBER-714 (Leagues) para más adelante.
A diferencia del Dashboard (solo admin/owner), `/my-metrics` — la ruta real detrás del link
"My Usage" del NavBar — es accesible a **todos los roles autenticados** (confirmado: no hay
`layout.tsx` propio, solo el gate de autenticación general; el propio código documenta
"Accessible to all authenticated roles", con scoping de datos vía RLS por `created_by`/
`agent_id`, no por rol).
El usuario decidió lanzar el agente de GFIBER-711 **en paralelo** con el de GFIBER-712,
aceptando el riesgo de un conflicto de merge en los archivos compartidos de infraestructura
del tour (ver sección de riesgo más abajo), en vez de esperar a que Dashboard termine primero.
## Estructura real de la pantalla
`app/(protected)/my-metrics/page.tsx` (Server Component, `dynamic = "force-dynamic"`)
renderiza, en este orden:
1. Header + `<DateRangeControl>` (línea con `basePath="/my-metrics"`, `activeFilter="mine"`)
**mismo componente compartido** que usa el Dashboard (`components/dashboard/DateRangeControl.tsx`).
2. Grid de 5 `<AgentStatCard>` (design system): Interactions, Offers Made, Accepted,
Rejected, Conversion Rate.
3. `<AdoptionCharts variant="individual">` — también compartido con el Dashboard
(`components/dashboard/AdoptionCharts.tsx`), pero el tour de Dashboard (GFIBER-712) **no**
lo ancla en su alcance aprobado, así que hoy no hay colisión de anclaje ahí.
4. Sección "Sessions" → `<SessionHistoryView showStats={false} detailBasePath="/my-metrics">`
(`app/(protected)/upsell-evaluator/_history/SessionHistoryView.tsx`, ya es `'use client'`).
5. Estado vacío (sin interacciones aún) — sin anclajes, no bloqueante, igual que el caso
análogo en Dashboard.
Grep exhaustivo confirmó: cero `data-tour` en esta pantalla o sus componentes hoy.
## Coordinación de naming con GFIBER-712 (componente compartido)
`DateRangeControl` es usado por ambos tours. Para evitar que el mismo `data-tour` fijo en el
componente diga "dashboard-*" cuando también aparece en `/my-metrics`, ya le pedí al agente
de GFIBER-712 (vía tmux, en curso) que renombre su anclaje de `dashboard-date-range` a
**`date-range-control`** (genérico, por componente, no por página que lo consume). Este plan
asume ese nombre ya renombrado y lo usa igual acá. Si por algún motivo el agente de Dashboard
no llegó a aplicarlo antes de que el de My Usage lo necesite, el agente de My Usage debe
usar `date-range-control` de todos modos (es el nombre correcto a largo plazo) y, si
encuentra `dashboard-date-range` en su lugar, renombrarlo él mismo.
## Reuso de infraestructura
- **`utils/upsell/tour-storage.ts`** — reusar tal cual, `tourId = "my-usage"` → key
`gfiber:tour-seen:my-usage`, independiente de los otros dos tours.
- **`utils/upsell/tour-bridge.ts`** — GFIBER-712 lo está refactorizando de singleton a
`Map<tourId, fn>` en paralelo, en su propio worktree, todavía sin mergear. **Riesgo de
conflicto aceptado por el usuario**: el agente de My Usage va a encontrar la versión
singleton vieja en `dev`. Debe hacer el mismo refactor (`Map<string, fn>` keyado por
`tourId`) de forma independiente, **en un commit dedicado y aislado** (sin mezclarlo con
cambios específicos de My Usage), para que sea lo más fácil posible de reconciliar cuando
ambos PRs converjan — el usuario resolverá ese conflicto de merge manualmente más adelante.
- **`components/NavBar/TourButton.tsx`** — mismo caso: GFIBER-712 lo está creando (reemplaza
a `UpsellTourButton.tsx`) con un mapa `pathname → tourId`. El agente de My Usage debe crear
este mismo componente si todavía no existe en su rama (heredada de `dev` sin ese cambio),
agregando la entrada `"/my-metrics": "my-usage"` al mapa, también en un commit aislado.
- **Patrón de `ProductTour.tsx`** — igual que Dashboard: sin `flow` (no hay máquina de
etapas), `TourController` interno + `TourProvider` + `SkipButton`/`nextButton` custom +
estilos `--fiber-*`.
## Anclajes del tour (4 pasos)
| # | `data-tour` | Elemento real | Contenido del paso |
| 1 | `date-range-control` | `<DateRangeControl>` (compartido) | "Filtra tus métricas por rango de fechas." |
| 2 | `my-usage-stats` | Grid de 5 `<AgentStatCard>` en `page.tsx` | "Tus estadísticas personales: interacciones, ofertas, aceptadas/rechazadas y tasa de conversión." |
| 3 | `adoption-charts` | `<AdoptionCharts variant="individual">` (compartido, sin uso previo por otro tour) | "Tu tendencia de adopción de la herramienta, día a día." |
| 4 | `session-history` | `<SessionHistoryView>` | "Revisa tu historial de sesiones — click en cualquier fila para ver el detalle completo." |
## Cambios a implementar
- `utils/upsell/tour-bridge.ts` — refactor a `Map<tourId, fn>` (si no llegó ya mergeado desde
GFIBER-712 al momento de implementar).
- `components/NavBar/TourButton.tsx` — crear (si no existe ya) o extender su mapa con
`"/my-metrics": "my-usage"`.
- Nuevo `app/(protected)/my-metrics/_flow/ProductTour.tsx` (o ubicación equivalente,
`'use client'`): `TOUR_ID = "my-usage"`, 4 steps de la tabla de arriba.
- `app/(protected)/my-metrics/page.tsx`: envolver el `return` con `<ProductTour>{...}</ProductTour>`.
- `data-tour` en: `components/dashboard/DateRangeControl.tsx` (ya debería tener
`date-range-control` si GFIBER-712 aplicó el rename; si no, renombrarlo), el grid de
`AgentStatCard` en `page.tsx`, `components/dashboard/AdoptionCharts.tsx`,
`app/(protected)/upsell-evaluator/_history/SessionHistoryView.tsx`.
## Riesgo aceptado
Conflicto de merge probable en `tour-bridge.ts` y `TourButton.tsx` cuando los PRs de
GFIBER-712 y GFIBER-711 converjan (ambos tocan los mismos archivos de infraestructura
compartida en paralelo). El usuario ya decidió aceptar este costo a cambio de arrancar ambos
tours en paralelo. Mitigación: instruir a ambos agentes a mantener esos cambios de
infraestructura en commits aislados y descriptivos, para facilitar un rebase/resolución
manual posterior.
## Verificación end-to-end
- Con `localStorage` vacío, login con cualquier rol (no solo admin/owner) → el tour se
dispara solo en `/my-metrics`.
- Recorrer los 4 pasos, incluido el estado con datos reales (no el estado vacío).
- Completar/Saltar → `localStorage["gfiber:tour-seen:my-usage"] === "true"`; reload no lo
re-dispara.
- Botón de reinicio en NavBar (`TourButton`) → en `/my-metrics` relanza el tour de My Usage;
en `/dashboard` y `/upsell-evaluator` sigue relanzando el suyo respectivo, sin pisarse.
- Probar con un agente sin interacciones aún (estado vacío) → confirmar que no rompe nada.
- Confirmar que el tour de Upsell Evaluator y el de Dashboard (si ya está mergeado) siguen
funcionando sin regresión tras el refactor de `tour-bridge.ts`/`TourButton.tsx`.