Skip to content

fix(dashboard): make demo navigation public-safe#507

Merged
izadoesdev merged 1 commit into
stagingfrom
fix/public-safe-demo
Jun 29, 2026
Merged

fix(dashboard): make demo navigation public-safe#507
izadoesdev merged 1 commit into
stagingfrom
fix/public-safe-demo

Conversation

@izadoesdev

@izadoesdev izadoesdev commented Jun 29, 2026

Copy link
Copy Markdown
Member

Summary

  • trim demo sidebar and command search to public-safe website surfaces only
  • keep Goals and Funnels public in demo, but make them read-only there
  • remove direct demo routes for flags, revenue, and users
  • block public/demo RPC reads for feature flag and target group admin definitions

Validation

  • bun test apps/dashboard/components/layout/navigation/nav-item-active.test.ts apps/dashboard/next-config.test.ts packages/ai/src/query/builders/public-access.test.ts
  • bunx ultracite check
  • bun run --cwd packages/rpc check-types
  • bun run --cwd apps/dashboard check-types
  • commit hook: dotenv -- turbo run check-types + enforce-format
  • pre-push hook: dotenv -- turbo run test

Notes

  • Goals and Funnels are intentionally still visible in the demo because they do not expose admin targeting/configuration data; creation/edit/delete controls are hidden on demo routes.

Summary by cubic

Tightened the demo website experience to be public-safe: hide admin-only surfaces in navigation and command search, keep Goals and Funnels visible but read-only, and block demo/public RPC reads of flags and target groups. Removed demo routes that exposed non-public features.

  • Bug Fixes
    • Navigation: added hideFromDemo on unsafe items (Agent, Flags, Revenue, Users, Realtime, Anomalies, Settings); tests ensure only demo-backed pages appear.
    • Command search: filters out global actions and demo-unsafe items when on /demo/*.
    • Goals/Funnels UI: read-only on demo routes; hide create/edit/delete, suppress empty-state actions, and keep rows fully clickable.
    • RPC: require authenticated workspace to read feature flags and target group definitions; funnels list remains readable for public sites.
    • Removed demo routes: /demo/[id]/flags, /demo/[id]/revenue, /demo/[id]/users (and user detail).

Written for commit 5ac30ee. Summary will update on new commits.

Review in cubic

@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dashboard Ready Ready Preview, Comment Jun 29, 2026 6:38am
databuddy-status Ready Ready Preview, Comment Jun 29, 2026 6:38am
documentation Ready Ready Preview, Comment Jun 29, 2026 6:38am

@izadoesdev izadoesdev marked this pull request as ready for review June 29, 2026 06:36
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

An error occurred during the review process. Please try again later.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/public-safe-demo

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR tightens the demo website experience to be public-safe by hiding admin-only surfaces in navigation and command search, keeping Goals and Funnels visible but read-only, and replacing the sanitize-for-demo pattern on flags and target groups with a hard UNAUTHORIZED block.

  • RPC hardening: flags.list/byId/byKey and targetGroups.list/byId now throw UNAUTHORIZED for demo-tier callers instead of returning sanitized payloads; funnels.list had its withPublicWorkspace auth check moved outside the cache queryFn (previously a cache hit would bypass auth entirely).
  • Navigation & command search: hideFromDemo: true added to Agent, Flags, Revenue, Users, Realtime, Anomalies, and all Settings pages; command search's groupsToSearchGroups previously filtered those items unconditionally (would have silently hidden them from authenticated users too), now correctly gates on isDemoPath. Global Actions, Websites, and API Key sections are also suppressed on demo paths.
  • Demo route deletion: /demo/[id]/flags, /revenue, /users, and /users/[userId] pages removed; a new filesystem-backed test asserts every visible demo nav item has a real page on disk.

Confidence Score: 4/5

Safe to merge; changes are additive guards that block access rather than relax it, and the new filesystem-backed test provides a regression harness for future nav additions.

The logic is straightforward and the RPC changes are conservative (blocking rather than sanitizing). The one pre-existing subtlety — auth inside queryFn in funnels — was only latent because the cache was disabled; the fix is correct and positions the endpoint safely for when the cache is enabled. No mutation paths are affected.

No files require special attention. The funnels.ts auth-before-cache refactor is worth a quick read since it changes control flow, but the intent is clear and backed by integration tests.

Important Files Changed

Filename Overview
packages/rpc/src/routers/flags.ts Replaced sanitize-for-demo pattern with a hard UNAUTHORIZED throw for list/byId/byKey; removed sanitizeFlagForDemo, projectForViewer, and the sanitize cache-key segment.
packages/rpc/src/routers/target-groups.ts Same pattern as flags: sanitizeGroupForDemo removed, requireAuthedTargetGroupRead added to list and byId; sanitize cache-key segment removed.
packages/rpc/src/routers/funnels.ts Moved withPublicWorkspace auth check from inside queryFn to outside cache.withCache, ensuring auth always runs even on cache hits. Funnels remain readable for public/demo.
apps/dashboard/components/ui/command-search.tsx Fixed groupsToSearchGroups: old code always filtered hideFromDemo items unconditionally; new code correctly gates on isDemoPath. Global Actions, Websites, and API Keys sections suppressed on demo paths.
apps/dashboard/components/layout/navigation/navigation-config.tsx Added hideFromDemo: true to Realtime, Anomalies, Users, Flags, Revenue, Databunny/Agent, and all Settings sub-pages.
apps/dashboard/components/layout/navigation/nav-item-active.test.ts Added two demo navigation tests: verifies expected items carry hideFromDemo:true, and checks via existsSync that every visible demo nav item has a real page file on disk.
apps/dashboard/app/(main)/websites/[id]/funnels/page.tsx Detects /demo/* via usePathname; hides Create button and empty-state action on demo, passes readOnly to FunnelsList, gates EditFunnelDialog/DeleteDialog with !isDemoRoute.
apps/dashboard/app/(main)/websites/[id]/goals/page.tsx Same read-only pattern as funnels: isDemoRoute hides Create Goal, empty-state action, edit/delete dialogs, passes readOnly to GoalsList.
apps/api/src/integration/cache-auth-bypass.test.ts Updated integration tests: demo caller for target-groups.list and flags.list now expects UNAUTHORIZED; new test for flags validates the hard block.
apps/dashboard/app/(main)/websites/[id]/funnels/_components/funnel-item.tsx Added readOnly prop; when true suppresses Edit/Delete dropdown. Fixed row layout: padding moved from List.Row to sibling Button so full row surface is clickable.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Client as Demo Caller
    participant RPC as RPC Handler
    participant Cache as Drizzle Cache
    participant DB as Database

    note over Client,DB: flags.list / target-groups.list (NEW)
    Client->>RPC: request (demo tier)
    RPC->>RPC: authorizeFlagRead / withPublicWorkspace
    RPC->>RPC: requireAuthedFlagRead → throws UNAUTHORIZED
    RPC-->>Client: 401 UNAUTHORIZED

    note over Client,DB: funnels.list auth-before-cache fix (NEW)
    Client->>RPC: request (public/demo)
    RPC->>RPC: withPublicWorkspace runs BEFORE cache
    RPC->>Cache: withCache(key, queryFn)
    Cache-->>RPC: hit → return cached rows
    RPC-->>Client: funnel list (auth always checked)

    note over Client,DB: funnels.list (OLD — auth inside queryFn)
    Client->>RPC: request
    RPC->>Cache: withCache(key, queryFn)
    Cache-->>RPC: hit → skip queryFn (auth never ran!)
    RPC-->>Client: cached data (auth bypassed on cache hit)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Client as Demo Caller
    participant RPC as RPC Handler
    participant Cache as Drizzle Cache
    participant DB as Database

    note over Client,DB: flags.list / target-groups.list (NEW)
    Client->>RPC: request (demo tier)
    RPC->>RPC: authorizeFlagRead / withPublicWorkspace
    RPC->>RPC: requireAuthedFlagRead → throws UNAUTHORIZED
    RPC-->>Client: 401 UNAUTHORIZED

    note over Client,DB: funnels.list auth-before-cache fix (NEW)
    Client->>RPC: request (public/demo)
    RPC->>RPC: withPublicWorkspace runs BEFORE cache
    RPC->>Cache: withCache(key, queryFn)
    Cache-->>RPC: hit → return cached rows
    RPC-->>Client: funnel list (auth always checked)

    note over Client,DB: funnels.list (OLD — auth inside queryFn)
    Client->>RPC: request
    RPC->>Cache: withCache(key, queryFn)
    Cache-->>RPC: hit → skip queryFn (auth never ran!)
    RPC-->>Client: cached data (auth bypassed on cache hit)
Loading

Reviews (1): Last reviewed commit: "fix(dashboard): make demo navigation pub..." | Re-trigger Greptile

@izadoesdev izadoesdev merged commit 7e7a4b0 into staging Jun 29, 2026
27 checks passed
@izadoesdev izadoesdev deleted the fix/public-safe-demo branch June 29, 2026 06:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant