feat/discovery
needs attentionviewing older commitd64cd72 · incrementalpre-PRreviewed 2026-07-13 16:27 UTC2H · 3M · 2L- Purpose
- Feature discovery system that guides new Batu users through the platform on first run and surfaces contextual feature spotlights as they navigate.
- Goal
- Implement Diego's v1 feature discovery direction: a fixed-sequence product tour on the Contratos page backed by server-side gap tracking, plus contextual spotlights for key platform features (CFE setup, contract add, API credentials). Gated behind PostHog flag with Vercel preview bypass.
- Sub-goals
- SG-1: Domain layer — discovery-state FCIS (type, decisions, queries, shells, mapper) + DB schema (discovery_state table, migration 0058)
- SG-2: API surface — discovery contract/handler/mapper, gap endpoint, recordOutcome mutation
- SG-3: Cross-domain coordinator — feature-discovery decisions + shells spanning core × utility
- SG-4: UI — GuidedTour (linear tour), FeatureSpotlight (contextual coachmarks), DescubreMenu (hub with gap badge)
- SG-5: Analytics — analytics events (tour_started, tour_completed, spotlight_seen, etc.)
- SG-6: Fix series — concurrency, spotlight self-destruct, preview gating, overflow, anchor correctness, idempotent secrets
- What
- Design pass (d64cd721) declutters the tour card: downgrades 'Hazlo ahora' from a competing full-width button to a quiet accent link, removes the redundant 'Saltar' footer text link (X button is the only skip), and replaces the plain step counter with visual progress dots (pill = current, filled = past, outlined = future). One prior fix (c1f337bc) corrected tour step destinations to point to Recibos not Descargas.
- Why
- Diego's v1 direction to reduce visual noise in the tour card — four controls in a 340px card caused overflow and competed for attention. Von Restorff principle: one clear primary CTA (Siguiente), everything else secondary.
- Areas
- apps/platform/src/components/discovery+813−0apps/platform/src/api (discovery contract/handler/mapper)+276−0apps/platform/src/app (layout wiring, pages)+27−2domains/core/src/discovery (FCIS)+361−0domains/cross-domain/src (coordinator)+898−0packages (api schemas, analytics events, database schema, secrets)+301−12e2e/platform+48−0
- Blast
- 48 files, +3586/−31 (excluding DB migrations/snapshots). Touches the full FCIS stack (domain → cross-domain → API → UI) plus analytics and E2E. New DB table (discovery_state). No existing functionality removed.
Findings · 7
conventions3
text-brand-electric-violet utility class is not defined — Hazlo-ahora link will render colorless
apps/platform/src/components/discovery/GuidedTour.tsx:258
The diff introduces `text-brand-electric-violet` on the "Hazlo ahora" button. Checked packages/ui/src/styles/components.css — only `.bg-brand-electric-violet`, `.text-brand-heliotrope`, and `.bg-brand-heliotrope` are defined; `.text-brand-electric-violet` is absent. TailwindCSS v4 silently skips unknown utilities, so the link renders with no color (inherits default text color instead of the intended accent). Fix: add `.text-brand-electric-violet { color: hsl(var(--brand-electric-violet)); }` in components.css alongside its `bg-` sibling, or switch to `text-brand-heliotrope` which is already defined.
Anterior uses bare <button> while Siguiente uses <Button> — inconsistent focus ring and theme contract
apps/platform/src/components/discovery/GuidedTour.tsx:285
The previous-step control is a hand-rolled `<button>` with manual `h-8 rounded-md px-2.5` classes and no explicit `focus-visible` ring. The old code used `<Button size="sm" variant="cancel">` which carries the design system's shared focus ring, disabled styling, and size contract. Using the system `<Button size="sm" variant="ghost">` (or the `cancel` variant) would keep keyboard focus styling consistent between Anterior and Siguiente, and propagate future theme changes automatically.
Progress dots aria-label is a bare fraction with no semantic context
apps/platform/src/components/discovery/GuidedTour.tsx:268
The dots container has `aria-label={\`${stepIdx + 1}/${total}\`}` which announces as "2/5" — no indication this is tour progress. Additionally, the `<span>` dots are decorative but lack `aria-hidden="true"`, so screen readers may enumerate them as unlabelled elements. Fix: use a localized label (`Paso {n} de {total}` — add i18n key) and add `aria-hidden="true"` to every dot `<span>`.
improvement4
Past-step dot opacity (bg-muted-foreground/50) likely fails WCAG 1.4.11 non-text contrast at 6px
apps/platform/src/components/discovery/GuidedTour.tsx:274
Past-step dots use `bg-muted-foreground/50` (50% opacity) at `h-1.5 w-1.5` (6×6 px). At this size and opacity the contrast ratio against a white card background likely falls below the 3:1 minimum for non-text UI components (WCAG 1.4.11). Bump to `bg-muted-foreground` (full opacity) to preserve the three-state encoding without relying on opacity for differentiation.
ArrowRight icon in Hazlo-ahora link won't flip in RTL locales
apps/platform/src/components/discovery/GuidedTour.tsx:261
The `<ArrowRight>` icon always points right. If the platform is ever used in an RTL context the icon direction should mirror. Low risk today but a known trap for icon-decorated CTA links. Add `rtl:rotate-180` to the icon's className or use a directional icon utility when RTL is first supported.
Navigation row lacks a group landmark — AT users can't jump directly to tour controls
apps/platform/src/components/discovery/GuidedTour.tsx:267
The footer `<div>` containing progress dots + Anterior/Siguiente has no landmark or group role. Adding `role="group" aria-label="Navegación del tour"` (or an i18n key) lets screen reader users jump directly to the navigation controls without tabbing through the card body.
Dot key={i} is index-based — fragile if steps become dynamic
apps/platform/src/components/discovery/GuidedTour.tsx:271
Safe with the current static `Array.from({ length: total })` shape. If steps are ever made conditional or reordered, React will reuse wrong DOM nodes and `transition-all` will animate incorrectly. Worth keying on step index or step ID if the catalog drives this in future.
History · 36 commits
- c1fe7b7needs attentionincremental3H · 4M · 3L2026-07-27 06:02
- 414db56safeincremental0H · 0M · 2L2026-07-23 00:52
- ea68968needs attentionincremental0H · 4M · 7L2026-07-22 23:01
- 4bdb2c9needs attentionincremental1H · 3M · 5L2026-07-21 23:22
- 6e3f255safeincremental0H · 0M · 0L2026-07-20 16:46
- cc41079blockedincremental5H · 5M · 3L2026-07-20 16:25
- 2451ee0needs attentionincremental0H · 5M · 6L2026-07-20 16:09
- ab7c103needs attentionincremental0H · 1M · 6L2026-07-20 15:52
- 7eff611needs attentionincremental0H · 1M · 2L2026-07-18 00:41
- 246c67csafeincremental0H · 0M · 0L2026-07-17 23:58
- 7521b17safeincremental0H · 0M · 0L2026-07-17 23:35
- 1847ec8needs attentionincremental0H · 2M · 4L2026-07-17 23:28
- 5d3175cneeds attentionincremental3H · 6M · 4L2026-07-17 19:31
- d3f875dneeds attentionincremental1H · 2M · 4L2026-07-17 18:01
- 47d25faneeds attentionincremental1H · 1M · 2L2026-07-17 00:46
- 440d838needs attentionincremental4H · 9M · 9L2026-07-17 00:27
- 7466f97needs attentionincremental0H · 1M · 5L2026-07-16 23:20
- b686d58needs attentionincremental0H · 2M · 2L2026-07-16 14:24
- 9ea1446blockedincremental2H · 7M · 10L2026-07-16 13:44
- 6f39bb9needs attentionincremental0H · 2M · 7L2026-07-14 21:53
- 2eadf2aneeds attentionincremental0H · 1M · 2L2026-07-14 20:12
- 97bd08fneeds attentionincremental0H · 2M · 5L2026-07-14 19:40
- a48e3ffneeds attentionincremental5H · 8M · 6L2026-07-14 18:22
- 69473b7needs attentionincremental2H · 5M · 3L2026-07-14 01:34
- 92e4235needs attentionincremental2H · 1M · 3L2026-07-14 01:04
- 6be8018safeincremental0H · 0M · 3L2026-07-14 00:15
- 090b4daneeds attentionincremental1H · 3M · 5L2026-07-13 23:50
- fa7683bneeds attentionincremental1H · 4M · 3L2026-07-13 18:55
- d64cd72needs attentionincremental2H · 3M · 2L2026-07-13 16:27current
- c1f337bneeds attentionincremental3H · 7M · 14L2026-07-13 13:30
- 46e32b2safeincremental0H · 0M · 3L2026-07-11 02:54
- 3b30949needs attentionincremental0H · 2M · 3L2026-07-11 02:39
- 9f8dbdfneeds attentionincremental3H · 5M · 5L2026-07-11 02:32
- 23191eeneeds attentionincremental5H · 12M · 7L2026-07-11 02:18
- fa9b88fneeds attentionincremental0H · 1M · 2L2026-07-11 01:30
- 6a8bf42blockedfull8H · 11M · 8L2026-07-11 01:08