← all branches

feat/discovery

safeviewing older commit
414db56 · incrementalPR #305reviewed 2026-07-23 00:52 UTC0H · 0M · 2L · 9I
The branch
Purpose
Add contextual feature discovery for existing platform users — ambient spotlights, Descubre hub, and first-run product tour, all flag-gated (feature-discovery-spotlights OFF by default).
Goal
Feature Discovery v1 — spotlights, hub, first-run tour
Sub-goals
  • SG-1: Ambient spotlights — one contextual coachmark per user per day, computed at read from real rows, retired after 2 dismissals / 3 unclicked shows
  • SG-2: Descubre hub — header badge listing user gaps, self-serve pull, re-launch tour link
  • SG-3: First-run linear product tour — 5 fixed steps, dimmed scrim + spotlight cutout, Hazlo ahora shortcut
  • SG-4: Adversarial review pass — two prod blockers (preview bypass keyed on Host vs VERCEL_ENV; spotlight self-destruct from self-invalidating query) found and fixed
  • SG-5: discovery_state table — RLS-gated, profile-scoped, migration 0065, FCIS throughout
The changes (whole branch)
What
Merge commit renumbers discovery's migration 0064→0065 (main landed its own 0064 for utility_contract_overview_reconcile_runs). Also brings in the utilityContractOverviewReconcileRuns schema barrel export from main.
Why
Migration number conflict resolution after main merged the reconcile-and-repair migration (#215) before this branch merged.
Areas
apps/platform+162152domains/core/src/discovery+3140domains/cross-domain/src+107034packages/database+1311packages/api/src/schemas+990packages/analytics/src+980packages/secrets+15212e2e/platform+610scripts+300
Blast
68 files, ~3600 additions across platform UI, domain decisions, DB schema, API contracts, analytics events. Flag-gated — no user impact until feature-discovery-spotlights is enabled.
feature-discovery-spotlights (PostHog flag, OFF by default)
ci· gh pr checks unavailable (personal access token scope)coderabbit· no .coderabbit.yaml in repo

Findings · 11

correctness4

low

clicked_at set without guaranteed updated_at advancement

packages/database/drizzle/0065_discovery_state.sql:12

When clicked_at is first written, updated_at must be advanced by the shell. If a shell issues a click-only update without setting updated_at/version, the timestamp will silently go stale. Not detectable from the migration alone — verify the click shell path sets both fields.

info

updated_at has no ON UPDATE trigger — relies on application layer

packages/database/drizzle/0065_discovery_state.sql:5

Consistent with the rest of the schema (shell sets updated_at). Raw SQL UPDATE would silently leave it stale, but that's a known constraint across all tables.

info

Journal ordering correct after renumber

packages/database/drizzle/meta/_journal.json

idx 63→64→65 is strictly monotonic. idx:64 = 0064_strong_echo (main), idx:65 = 0065_discovery_state (this branch). No collision, no gap.

info

schema/index.ts merge-in (utilityContractOverviewReconcileRuns) is unrelated to discovery

packages/database/src/schema/index.ts

Export came from main's 2deee0e8 merge commit. Correct placement in the barrel; no interaction with discovery_state.

security4

low

public_id uniqueness via unique index rather than UNIQUE constraint

packages/database/drizzle/0065_discovery_state.sql:16

public_id is text NOT NULL + a unique index. Functionally equivalent for enforcement but a unique index can be dropped without a table migration while a UNIQUE constraint cannot. Low risk in a migration-controlled schema; consistent with other tables in the repo.

info

RLS policies follow established profiles-subquery pattern

packages/database/drizzle/0065_discovery_state.sql

SELECT/INSERT/UPDATE gate on profile_id IN (SELECT id FROM profiles WHERE auth_id = auth.uid()). Identical to user-preferences pattern. profiles.auth_id is indexed — subquery is efficient.

info

No DELETE policy for authenticated role — intentional

packages/database/drizzle/0065_discovery_state.sql

Authenticated users cannot delete their own rows; deletion happens only via CASCADE from profiles. Correct posture for exposure-tracking state.

info

service_role ALL policy is standard and acceptable

packages/database/drizzle/0065_discovery_state.sql

Standard Supabase pattern used across the schema. No concern.

conventions2

info

Journal ordering and file naming correct

packages/database/drizzle/meta/_journal.json

idx values strictly monotonic 0→65, no gaps. File names match journal tags exactly.

info

schema/index.ts barrel export placement follows established pattern

packages/database/src/schema/index.ts

Merged export placed correctly after the UCO export, before billing schemas. Style consistent with surrounding exports.

tests1

info

Migration files require no tests — Drizzle convention

Generated migration SQL has no test requirement. Discovery feature itself has unit, integration, and E2E coverage already in the branch.

History · 36 commits

  1. c1fe7b7needs attentionincremental3H · 4M · 3L2026-07-27 06:02
  2. 414db56safeincremental0H · 0M · 2L2026-07-23 00:52current
  3. ea68968needs attentionincremental0H · 4M · 7L2026-07-22 23:01
  4. 4bdb2c9needs attentionincremental1H · 3M · 5L2026-07-21 23:22
  5. 6e3f255safeincremental0H · 0M · 0L2026-07-20 16:46
  6. cc41079blockedincremental5H · 5M · 3L2026-07-20 16:25
  7. 2451ee0needs attentionincremental0H · 5M · 6L2026-07-20 16:09
  8. ab7c103needs attentionincremental0H · 1M · 6L2026-07-20 15:52
  9. 7eff611needs attentionincremental0H · 1M · 2L2026-07-18 00:41
  10. 246c67csafeincremental0H · 0M · 0L2026-07-17 23:58
  11. 7521b17safeincremental0H · 0M · 0L2026-07-17 23:35
  12. 1847ec8needs attentionincremental0H · 2M · 4L2026-07-17 23:28
  13. 5d3175cneeds attentionincremental3H · 6M · 4L2026-07-17 19:31
  14. d3f875dneeds attentionincremental1H · 2M · 4L2026-07-17 18:01
  15. 47d25faneeds attentionincremental1H · 1M · 2L2026-07-17 00:46
  16. 440d838needs attentionincremental4H · 9M · 9L2026-07-17 00:27
  17. 7466f97needs attentionincremental0H · 1M · 5L2026-07-16 23:20
  18. b686d58needs attentionincremental0H · 2M · 2L2026-07-16 14:24
  19. 9ea1446blockedincremental2H · 7M · 10L2026-07-16 13:44
  20. 6f39bb9needs attentionincremental0H · 2M · 7L2026-07-14 21:53
  21. 2eadf2aneeds attentionincremental0H · 1M · 2L2026-07-14 20:12
  22. 97bd08fneeds attentionincremental0H · 2M · 5L2026-07-14 19:40
  23. a48e3ffneeds attentionincremental5H · 8M · 6L2026-07-14 18:22
  24. 69473b7needs attentionincremental2H · 5M · 3L2026-07-14 01:34
  25. 92e4235needs attentionincremental2H · 1M · 3L2026-07-14 01:04
  26. 6be8018safeincremental0H · 0M · 3L2026-07-14 00:15
  27. 090b4daneeds attentionincremental1H · 3M · 5L2026-07-13 23:50
  28. fa7683bneeds attentionincremental1H · 4M · 3L2026-07-13 18:55
  29. d64cd72needs attentionincremental2H · 3M · 2L2026-07-13 16:27
  30. c1f337bneeds attentionincremental3H · 7M · 14L2026-07-13 13:30
  31. 46e32b2safeincremental0H · 0M · 3L2026-07-11 02:54
  32. 3b30949needs attentionincremental0H · 2M · 3L2026-07-11 02:39
  33. 9f8dbdfneeds attentionincremental3H · 5M · 5L2026-07-11 02:32
  34. 23191eeneeds attentionincremental5H · 12M · 7L2026-07-11 02:18
  35. fa9b88fneeds attentionincremental0H · 1M · 2L2026-07-11 01:30
  36. 6a8bf42blockedfull8H · 11M · 8L2026-07-11 01:08