Skip to content

feat(admin): intention-based admin hubs with Tabs sub-tabs - #2975

Open
riderx wants to merge 15 commits into
mainfrom
cursor/admin-intention-reorg-proposal-185b
Open

feat(admin): intention-based admin hubs with Tabs sub-tabs#2975
riderx wants to merge 15 commits into
mainfrom
cursor/admin-intention-reorg-proposal-185b

Conversation

@riderx

@riderx riderx commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary (AI generated)

  • Reorganize Capgo admin around intention hubs (Pulse, Onboarding, Product, Retention, Customers, Revenue, Platform) with Tabs secondary navigation
  • Shared reload/composables and organization insight columns (Sonar new duplication 0%)
  • Merged latest main; folded frontend-onboarding + plans analytics into Onboarding/Revenue hubs
  • CI/review fixes: loader finally, paid-at i18n, typo, unit test paths, translation contexts, lint import order

Motivation (AI generated)

Admin IA was page-scattered. Intention hubs make ops workflows discoverable. Merge conflicts with main had blocked pull_request CI.

Business Impact (AI generated)

Faster internal triage of onboarding, retention, revenue, and platform health without changing customer-facing product.

Test Plan (AI generated)

  • All PR checks green on latest HEAD (bd30e381e)
  • Unresolved review threads = 0
  • Unit tests for moved admin pages
  • Lint / typos / translation contexts

Generated with AI

Open in Web Open in Cursor 

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added an intention-based admin dashboard with Pulse, Onboarding, Product, Retention, Customers, Revenue, and Platform hubs.
    • Added onboarding, retention, capacity, revenue, plans, notifications, and organization analytics with responsive charts, KPI cards, filters, and refresh controls.
    • Added loading, error, empty-data, and telemetry availability states.
    • Improved organization insights and shared navigation across related views.
  • Bug Fixes

    • Legacy admin links now redirect to updated dashboard locations.
    • Dashboard cards support keyboard activation and accessible button semantics.

Reorganize Capgo admin around admin intentions (Pulse, Onboarding,
Product, Retention, Customers, Revenue, Platform) using the existing
Tabs primary + secondaryTabs pattern. Includes proposal write-up and
visual mocks for PR review.

Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The admin dashboard is reorganized into intention-based hubs with nested routes, legacy redirects, shared loading utilities, and new onboarding, retention, platform, product, customer, and revenue views. Supporting localization, typings, tests, and screenshot capture were added.

Changes

Admin dashboard reorganization

Layer / File(s) Summary
Navigation and routing
src/constants/*, src/constants/adminHubs.ts, src/layouts/admin.vue, src/main.ts, src/route-map.d.ts
Replaced legacy admin tabs with intention-based hubs, added secondary navigation, preserved query parameters, and added legacy redirects.
Shared dashboard utilities
src/composables/*, src/services/admin*, src/components/admin/*
Added shared admin authorization, reload handling, trend calculations, organization formatting, onboarding metrics, and revenue panels.
Dashboard pages
src/pages/admin/dashboard/*
Added Pulse, onboarding, platform capacity, retention, revenue, notifications, and Plans views. Relocated existing analytics pages and removed obsolete dashboard content.
Supporting updates
messages/en.json, tests/*, scripts/capture-admin-screens.mjs, docs/proposals/*
Added localization, updated source-based tests, added screenshot automation, and documented the implemented IA.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: codex

Suggested reviewers: dalanir

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: reorganizing the admin interface into intention-based hubs with secondary tabs.
Description check ✅ Passed The description covers the scope, motivation, impact, and test plan, but it omits the template's Screenshots and repository checklist sections.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

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

@codspeed-hq

codspeed-hq Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 43 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing cursor/admin-intention-reorg-proposal-185b (bd30e38) with main (ebb7cbc)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Extract onboarding funnel/sources/cohorts and retention trials/churn/inactive
pages from the monolithic users dashboard; keep users.vue as a redirect.

Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Replace fake proposal mocks with the implemented Tabs primary/secondary
admin IA and capture live worktree screenshots of Pulse, Onboarding,
Product, Retention, and Customers. Skip local SSO enforcement when
VITE_BRANCH=local so seed admin login works without edge functions.

Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
cursoragent and others added 2 commits August 10, 2026 13:53
Move legacy admin path redirects into main.ts to clear Sonar duplication.
Point registration-source unit tests at onboarding/sources.vue.
Widen email preferences mock return types for vue-tsc.

Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
@cursor cursor Bot changed the title docs(admin): intention-based admin IA with Tabs sub-tabs feat(admin): intention-based admin hubs with Tabs sub-tabs Aug 10, 2026
@riderx
riderx marked this pull request as ready for review August 10, 2026 13:55
@coderabbitai coderabbitai Bot added the codex label Aug 10, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3fd1769. Configure here.

Comment thread src/pages/admin/dashboard/retention/churn.vue Outdated
Comment thread src/pages/admin/dashboard/retention/inactive.vue
@cursor
cursor Bot requested review from Dalanir and WcaleNieWolny August 10, 2026 14:00

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: medium. Left a non-blocking comment — Cursor Bugbot reported 2 unresolved findings and did not complete successfully, so this is above the low-risk auto-approve threshold. Human review is needed; reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver External

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 27

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/capture-admin-screens.mjs`:
- Around line 7-11: Update waitForAdmin to accept a route-specific ready
locator, verify new URL(page.url()).pathname matches the requested path after
navigation, and wait for that locator instead of the generic admin navigation
button. Update each caller to provide the expected content locator before
capturing its screenshot.

In `@src/layouts/admin.vue`:
- Around line 98-117: Update the fallback in activeSecondaryTab to return the
first key from secondaryTabs.value when no exact or prefix match exists, instead
of hubConfig[hub].base; preserve undefined when no secondary tabs are available.
- Around line 66-96: Remove the hardcoded hub conditions from activeTab and
centralize each hub’s primary route in the existing admin tab configuration.
Derive the active tab from that single mapping, ensuring every primary route is
represented in adminTabs while preserving exact, prefix, and pulse fallback
behavior.

In `@src/modules/sso-enforcement.ts`:
- Around line 60-65: Update the SSO bypass condition in the enforcement guard to
require both import.meta.env.DEV and VITE_BRANCH === 'local' before returning
next(). Preserve the existing fail-closed behavior for all production builds and
non-local branches.

In `@src/pages/admin/dashboard/customers/credits.vue`:
- Around line 245-249: Update searchOrgs so queries shorter than two characters
invalidate the active search by clearing or changing currentSearchQuery and
resetting isSearching to false before returning; preserve the existing empty
searchResults behavior and prevent any in-flight longer-query response from
passing the currentSearchQuery check and repopulating results.
- Around line 141-165: Update the monthlyCreditSummary aggregation to make
monthEndMrr order-independent: track the date associated with the selected MRR
for each month and only replace it when the current row.date is later than the
stored date. Preserve the existing creditsBought and creditsConsumed
accumulation and return shape.

In `@src/pages/admin/dashboard/onboarding/cohorts.vue`:
- Around line 114-211: Extract the shared onboarding funnel logic from
onboardingFunnelRates, onboardingFunnelConversionSummaries, and
onboardingFunnelConversionGridClass into a composable such as
useOnboardingFunnel, preserving the existing calculations, labels, activation
telemetry handling, and grid classes. Update both cohorts.vue and index.vue to
consume the composable and remove their duplicated implementations.

In `@src/pages/admin/dashboard/onboarding/index.vue`:
- Around line 450-459: Add the mainStore.isAdmin guard to both reload watchers
in src/pages/admin/dashboard/onboarding/index.vue:450-459, wrapping the
loadGlobalStatsTrend and loadOnboardingFunnel calls. Apply the same guard to
both watchers in src/pages/admin/dashboard/onboarding/cohorts.vue:213-220 around
loadOnboardingFunnel, src/pages/admin/dashboard/onboarding/sources.vue:238-249
around all three loader calls,
src/pages/admin/dashboard/revenue/upgrades.vue:183-189 around
loadGlobalStatsTrend, and src/pages/admin/dashboard/product/cli.vue:103-109
around loadCliUsage.
- Around line 104-118: Remove the debug console.log calls that dump fetched
stats payloads while preserving the console.error calls: in
src/pages/admin/dashboard/onboarding/index.vue lines 104-118, remove the log in
loadGlobalStatsTrend and the matching log in loadOnboardingFunnel; in
src/pages/admin/dashboard/onboarding/cohorts.vue lines 48-62, remove the
loader’s payload log; and in src/pages/admin/dashboard/onboarding/sources.vue
lines 68-82, remove its payload log.
- Around line 140-149: Update the series label in the chart data returned by the
visible computed flow to use the existing `t('daily-registrations')` translation
key instead of the hardcoded “Daily Registrations” string, matching the
`ChartCard` title and keeping the legend localized.

In `@src/pages/admin/dashboard/platform/capacity.vue`:
- Around line 154-205: Replace all inline English user-facing labels in the
three admin pages with i18n keys, without passing fallback text to translation
calls, and add the corresponding entries to messages/en.json. In
src/pages/admin/dashboard/platform/capacity.vue lines 154-205, use the existing
admin-pulse-builders-* and admin-pulse-builder-unreachable keys for the five
cards and add keys for the chart title, description, and Workers/Used/Free
series labels. In src/pages/admin/dashboard/product/plugins.vue lines 239-259,
add keys for the three device cards, Version Ladder headers at lines 331-341,
chart titles/descriptions, Min share, and Device Share. In
src/pages/admin/dashboard/product/updates.vue lines 78-152, add keys for the
four chart series labels and the Total Updates Today and Success Rate card text
at lines 206-240.

In `@src/pages/admin/dashboard/product/cli.vue`:
- Around line 138-160: Replace all hardcoded user-facing strings in the CLI
dashboard, including the three AdminStatsCard titles/subtitles, chart titles,
section heading/description, table headers, and empty state, with translation
keys via the existing t function. Add corresponding English entries to
messages/en.json, and do not use inline fallback text in translation calls;
preserve the existing t('cli') navigation localization.

In `@src/pages/admin/dashboard/product/plugins.vue`:
- Around line 211-226: Remove the redundant displayStore.NavTitle assignment
from the onMounted callback in
src/pages/admin/dashboard/product/plugins.vue#L211-L226, retaining the
setup-scope assignment. Apply the same change in
src/pages/admin/dashboard/product/updates.vue#L169-L184 by removing the
onMounted assignment for the updates title and keeping its setup-scope
assignment.
- Around line 400-427: Add accessible names to both FormKit controls in the
threshold filter: update the select bound to thresholdSelection with a label or
aria-label describing the minimum share, and update the customThreshold number
input with a distinct label or aria-label describing the custom threshold
percentage.

In `@src/pages/admin/dashboard/product/updates.vue`:
- Line 61: Remove the debug console.log statement that logs the complete stats
payload from the dashboard updates data-loading flow, while leaving the
surrounding statistics and date-range behavior unchanged.
- Around line 57-71: Update loadGlobalStatsTrend to use a trendRequestSeq-style
sequence guard matching notifications.vue: increment the request sequence when
starting a fetch, capture that value locally, and only apply success or error
results when the response belongs to the latest request. Keep loading-state
cleanup from stale requests from overriding the current request’s state.

In `@src/pages/admin/dashboard/pulse.vue`:
- Around line 18-54: Define canonical admin stats response types in
src/services/adminStatsTypes.ts, including OnboardingFunnelData,
GlobalStatsTrendPoint, BuilderCapacityLive, and BuilderCapacity, then remove
duplicate declarations and import required types. In
src/pages/admin/dashboard/pulse.vue#L18-L54, import OnboardingFunnelData,
GlobalStatsTrendPoint, and BuilderCapacity. In
src/pages/admin/dashboard/onboarding/index.vue#L28-L100, import
OnboardingFunnelData and GlobalStatsTrendPoint; in
src/pages/admin/dashboard/onboarding/cohorts.vue#L26-L43 and
src/pages/admin/dashboard/onboarding/sources.vue#L32-L59, import
OnboardingFunnelData while retaining only page-specific breakdown types in
sources.vue.
- Around line 137-142: Update the payingOrgs computed value to use nullish
coalescing when selecting stats.paying_orgs_total, so a legitimate zero is
preserved and only null or undefined falls back to stats.paying or zero.

In `@src/pages/admin/dashboard/retention/churn.vue`:
- Around line 103-149: Add a module-scope monotonic sequence counter for
loadCancelledOrganizations in src/pages/admin/dashboard/retention/churn.vue
(lines 103-149), increment and capture it per request, and guard writes to
cancelledOrganizations, cancelledOrganizationsTotal, and
isLoadingCancelledOrganizations so stale responses cannot update state or clear
the loading flag. Apply the same counter and guards to loadTrialOrganizations in
src/pages/admin/dashboard/retention/index.vue (lines 166-213), covering
trialOrganizations, trialOrganizationsTotal, and isLoadingTrialOrganizations.

In `@src/pages/admin/dashboard/retention/inactive.vue`:
- Around line 95-102: Update the organization_insights loading flow around the
request body and current-page handling to paginate the complete paid
organization set before applying inactivity filtering, or apply the inactivity
filter server-side before LIMIT/OFFSET. Ensure inactiveOrganizationsTotal
reflects the full filtered result and current-page supports page changes instead
of remaining fixed at 1.

In `@src/pages/admin/dashboard/retention/index.vue`:
- Line 252: Replace the hard-coded labels at the chart series definitions and
KPI card title/subtitle in the retention dashboard with `t(...)` calls. Add
corresponding translation keys and English values to `messages/en.json`, and do
not pass inline fallback text to `t`; preserve the existing label and card text
through the new keys.
- Around line 109-164: Update src/pages/admin/dashboard/retention/index.vue
lines 109-164 by changing trialOrganizationsColumns from
ref<TableColumn[]>([...]) to computed<TableColumn[]>(() => [...]), preserving
its column definitions. Update src/pages/admin/dashboard/retention/churn.vue
lines 59-101 by wrapping cancelledOrganizationsColumns in
computed<TableColumn[]>(() => [...]) and adding computed to the Vue import, so
translated headers react to locale changes.

In `@src/pages/admin/dashboard/revenue/index.vue`:
- Line 105: Remove the full global_stats_trend payload debug logging from the
revenue dashboard loader in src/pages/admin/dashboard/revenue/index.vue at lines
105-105 and the retention dashboard loader in
src/pages/admin/dashboard/retention/index.vue at lines 219-219; leave the
surrounding data-loading behavior unchanged and follow the no-logging pattern
used by the risk dashboard.
- Line 761: Replace the truthiness fallbacks in both revenue cards with
nullish-coalescing fallbacks: update the expressions at the “Total Paid
Organizations” and “Paid via Subscription” values to use `??` so a legitimate
zero is preserved while null or undefined still falls back to the alternate
metric and then zero.

In `@src/pages/admin/dashboard/revenue/risk.vue`:
- Line 59: Replace the hard-coded series labels in the chart configuration near
“New Subscriptions” and the corresponding label at line 67 with translation keys
resolved through the page’s existing t(...) helper. Add the new keys and English
values to messages/en.json, and apply the same translated labels in the
corresponding chart configuration in revenue/index.vue; do not use inline
fallback text as a translation argument.
- Around line 59-67: Add a shared pair of subscription-flow label keys to
messages/en.json, then update subscriptionFlowSeries in
src/pages/admin/dashboard/revenue/risk.vue (59-67) and
src/pages/admin/dashboard/revenue/index.vue (148-156) to use t(...) with those
keys for both labels. Do not pass inline fallback text; use the same keys in
both files to keep the chart labels localized and synchronized.

In `@src/pages/admin/dashboard/revenue/upgrades.vue`:
- Around line 136-146: Update the `need-upgrade` card’s `title` to use the
existing `t(...)` translation pattern, add the corresponding title key with its
English text to `messages/en.json`, and do not pass inline fallback text to the
translation call.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ad6fed9a-49d1-492c-87b0-60f3dcdb03af

📥 Commits

Reviewing files that changed from the base of the PR and between dea082a and 3fd1769.

📒 Files selected for processing (47)
  • docs/pr-assets/admin-intention-ia/real-customers.webp
  • docs/pr-assets/admin-intention-ia/real-onboarding-cohorts.webp
  • docs/pr-assets/admin-intention-ia/real-onboarding-funnel.webp
  • docs/pr-assets/admin-intention-ia/real-onboarding-sources.webp
  • docs/pr-assets/admin-intention-ia/real-product-updates.webp
  • docs/pr-assets/admin-intention-ia/real-pulse.webp
  • docs/pr-assets/admin-intention-ia/real-retention.webp
  • docs/proposals/admin-dashboard-intention-ia.md
  • messages/en.json
  • scripts/capture-admin-screens.mjs
  • src/auto-imports.d.ts
  • src/components.d.ts
  • src/constants/adminCustomersTabs.ts
  • src/constants/adminOnboardingTabs.ts
  • src/constants/adminPlatformTabs.ts
  • src/constants/adminProductTabs.ts
  • src/constants/adminRetentionTabs.ts
  • src/constants/adminRevenueTabs.ts
  • src/constants/adminTabs.ts
  • src/layouts/admin.vue
  • src/main.ts
  • src/modules/sso-enforcement.ts
  • src/pages/admin/dashboard/customers/credits.vue
  • src/pages/admin/dashboard/customers/organizations.vue
  • src/pages/admin/dashboard/index.vue
  • src/pages/admin/dashboard/onboarding/cohorts.vue
  • src/pages/admin/dashboard/onboarding/index.vue
  • src/pages/admin/dashboard/onboarding/sources.vue
  • src/pages/admin/dashboard/platform/capacity.vue
  • src/pages/admin/dashboard/platform/debug.vue
  • src/pages/admin/dashboard/platform/replication.vue
  • src/pages/admin/dashboard/product/builder.vue
  • src/pages/admin/dashboard/product/cli.vue
  • src/pages/admin/dashboard/product/notifications.vue
  • src/pages/admin/dashboard/product/plugins.vue
  • src/pages/admin/dashboard/product/updates.vue
  • src/pages/admin/dashboard/pulse.vue
  • src/pages/admin/dashboard/retention/churn.vue
  • src/pages/admin/dashboard/retention/inactive.vue
  • src/pages/admin/dashboard/retention/index.vue
  • src/pages/admin/dashboard/revenue/index.vue
  • src/pages/admin/dashboard/revenue/risk.vue
  • src/pages/admin/dashboard/revenue/upgrades.vue
  • src/pages/admin/dashboard/users.vue
  • src/route-map.d.ts
  • tests/admin-registration-source-dashboard.unit.test.ts
  • tests/email-preferences-public.unit.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)
💤 Files with no reviewable changes (2)
  • src/pages/admin/dashboard/index.vue
  • src/pages/admin/dashboard/users.vue

Comment thread scripts/capture-admin-screens.mjs Outdated
Comment thread src/layouts/admin.vue
Comment thread src/layouts/admin.vue
Comment thread src/modules/sso-enforcement.ts
Comment thread src/pages/admin/dashboard/onboarding/cohorts.vue Outdated
Comment thread src/pages/admin/dashboard/retention/index.vue Outdated
Comment thread src/pages/admin/dashboard/retention/index.vue Outdated
Comment thread src/pages/admin/dashboard/revenue/risk.vue Outdated
Comment thread src/pages/admin/dashboard/revenue/risk.vue Outdated
Comment thread src/pages/admin/dashboard/revenue/upgrades.vue Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 27

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/capture-admin-screens.mjs`:
- Around line 7-11: Update waitForAdmin to accept a route-specific ready
locator, verify new URL(page.url()).pathname matches the requested path after
navigation, and wait for that locator instead of the generic admin navigation
button. Update each caller to provide the expected content locator before
capturing its screenshot.

In `@src/layouts/admin.vue`:
- Around line 98-117: Update the fallback in activeSecondaryTab to return the
first key from secondaryTabs.value when no exact or prefix match exists, instead
of hubConfig[hub].base; preserve undefined when no secondary tabs are available.
- Around line 66-96: Remove the hardcoded hub conditions from activeTab and
centralize each hub’s primary route in the existing admin tab configuration.
Derive the active tab from that single mapping, ensuring every primary route is
represented in adminTabs while preserving exact, prefix, and pulse fallback
behavior.

In `@src/modules/sso-enforcement.ts`:
- Around line 60-65: Update the SSO bypass condition in the enforcement guard to
require both import.meta.env.DEV and VITE_BRANCH === 'local' before returning
next(). Preserve the existing fail-closed behavior for all production builds and
non-local branches.

In `@src/pages/admin/dashboard/customers/credits.vue`:
- Around line 245-249: Update searchOrgs so queries shorter than two characters
invalidate the active search by clearing or changing currentSearchQuery and
resetting isSearching to false before returning; preserve the existing empty
searchResults behavior and prevent any in-flight longer-query response from
passing the currentSearchQuery check and repopulating results.
- Around line 141-165: Update the monthlyCreditSummary aggregation to make
monthEndMrr order-independent: track the date associated with the selected MRR
for each month and only replace it when the current row.date is later than the
stored date. Preserve the existing creditsBought and creditsConsumed
accumulation and return shape.

In `@src/pages/admin/dashboard/onboarding/cohorts.vue`:
- Around line 114-211: Extract the shared onboarding funnel logic from
onboardingFunnelRates, onboardingFunnelConversionSummaries, and
onboardingFunnelConversionGridClass into a composable such as
useOnboardingFunnel, preserving the existing calculations, labels, activation
telemetry handling, and grid classes. Update both cohorts.vue and index.vue to
consume the composable and remove their duplicated implementations.

In `@src/pages/admin/dashboard/onboarding/index.vue`:
- Around line 450-459: Add the mainStore.isAdmin guard to both reload watchers
in src/pages/admin/dashboard/onboarding/index.vue:450-459, wrapping the
loadGlobalStatsTrend and loadOnboardingFunnel calls. Apply the same guard to
both watchers in src/pages/admin/dashboard/onboarding/cohorts.vue:213-220 around
loadOnboardingFunnel, src/pages/admin/dashboard/onboarding/sources.vue:238-249
around all three loader calls,
src/pages/admin/dashboard/revenue/upgrades.vue:183-189 around
loadGlobalStatsTrend, and src/pages/admin/dashboard/product/cli.vue:103-109
around loadCliUsage.
- Around line 104-118: Remove the debug console.log calls that dump fetched
stats payloads while preserving the console.error calls: in
src/pages/admin/dashboard/onboarding/index.vue lines 104-118, remove the log in
loadGlobalStatsTrend and the matching log in loadOnboardingFunnel; in
src/pages/admin/dashboard/onboarding/cohorts.vue lines 48-62, remove the
loader’s payload log; and in src/pages/admin/dashboard/onboarding/sources.vue
lines 68-82, remove its payload log.
- Around line 140-149: Update the series label in the chart data returned by the
visible computed flow to use the existing `t('daily-registrations')` translation
key instead of the hardcoded “Daily Registrations” string, matching the
`ChartCard` title and keeping the legend localized.

In `@src/pages/admin/dashboard/platform/capacity.vue`:
- Around line 154-205: Replace all inline English user-facing labels in the
three admin pages with i18n keys, without passing fallback text to translation
calls, and add the corresponding entries to messages/en.json. In
src/pages/admin/dashboard/platform/capacity.vue lines 154-205, use the existing
admin-pulse-builders-* and admin-pulse-builder-unreachable keys for the five
cards and add keys for the chart title, description, and Workers/Used/Free
series labels. In src/pages/admin/dashboard/product/plugins.vue lines 239-259,
add keys for the three device cards, Version Ladder headers at lines 331-341,
chart titles/descriptions, Min share, and Device Share. In
src/pages/admin/dashboard/product/updates.vue lines 78-152, add keys for the
four chart series labels and the Total Updates Today and Success Rate card text
at lines 206-240.

In `@src/pages/admin/dashboard/product/cli.vue`:
- Around line 138-160: Replace all hardcoded user-facing strings in the CLI
dashboard, including the three AdminStatsCard titles/subtitles, chart titles,
section heading/description, table headers, and empty state, with translation
keys via the existing t function. Add corresponding English entries to
messages/en.json, and do not use inline fallback text in translation calls;
preserve the existing t('cli') navigation localization.

In `@src/pages/admin/dashboard/product/plugins.vue`:
- Around line 211-226: Remove the redundant displayStore.NavTitle assignment
from the onMounted callback in
src/pages/admin/dashboard/product/plugins.vue#L211-L226, retaining the
setup-scope assignment. Apply the same change in
src/pages/admin/dashboard/product/updates.vue#L169-L184 by removing the
onMounted assignment for the updates title and keeping its setup-scope
assignment.
- Around line 400-427: Add accessible names to both FormKit controls in the
threshold filter: update the select bound to thresholdSelection with a label or
aria-label describing the minimum share, and update the customThreshold number
input with a distinct label or aria-label describing the custom threshold
percentage.

In `@src/pages/admin/dashboard/product/updates.vue`:
- Line 61: Remove the debug console.log statement that logs the complete stats
payload from the dashboard updates data-loading flow, while leaving the
surrounding statistics and date-range behavior unchanged.
- Around line 57-71: Update loadGlobalStatsTrend to use a trendRequestSeq-style
sequence guard matching notifications.vue: increment the request sequence when
starting a fetch, capture that value locally, and only apply success or error
results when the response belongs to the latest request. Keep loading-state
cleanup from stale requests from overriding the current request’s state.

In `@src/pages/admin/dashboard/pulse.vue`:
- Around line 18-54: Define canonical admin stats response types in
src/services/adminStatsTypes.ts, including OnboardingFunnelData,
GlobalStatsTrendPoint, BuilderCapacityLive, and BuilderCapacity, then remove
duplicate declarations and import required types. In
src/pages/admin/dashboard/pulse.vue#L18-L54, import OnboardingFunnelData,
GlobalStatsTrendPoint, and BuilderCapacity. In
src/pages/admin/dashboard/onboarding/index.vue#L28-L100, import
OnboardingFunnelData and GlobalStatsTrendPoint; in
src/pages/admin/dashboard/onboarding/cohorts.vue#L26-L43 and
src/pages/admin/dashboard/onboarding/sources.vue#L32-L59, import
OnboardingFunnelData while retaining only page-specific breakdown types in
sources.vue.
- Around line 137-142: Update the payingOrgs computed value to use nullish
coalescing when selecting stats.paying_orgs_total, so a legitimate zero is
preserved and only null or undefined falls back to stats.paying or zero.

In `@src/pages/admin/dashboard/retention/churn.vue`:
- Around line 103-149: Add a module-scope monotonic sequence counter for
loadCancelledOrganizations in src/pages/admin/dashboard/retention/churn.vue
(lines 103-149), increment and capture it per request, and guard writes to
cancelledOrganizations, cancelledOrganizationsTotal, and
isLoadingCancelledOrganizations so stale responses cannot update state or clear
the loading flag. Apply the same counter and guards to loadTrialOrganizations in
src/pages/admin/dashboard/retention/index.vue (lines 166-213), covering
trialOrganizations, trialOrganizationsTotal, and isLoadingTrialOrganizations.

In `@src/pages/admin/dashboard/retention/inactive.vue`:
- Around line 95-102: Update the organization_insights loading flow around the
request body and current-page handling to paginate the complete paid
organization set before applying inactivity filtering, or apply the inactivity
filter server-side before LIMIT/OFFSET. Ensure inactiveOrganizationsTotal
reflects the full filtered result and current-page supports page changes instead
of remaining fixed at 1.

In `@src/pages/admin/dashboard/retention/index.vue`:
- Line 252: Replace the hard-coded labels at the chart series definitions and
KPI card title/subtitle in the retention dashboard with `t(...)` calls. Add
corresponding translation keys and English values to `messages/en.json`, and do
not pass inline fallback text to `t`; preserve the existing label and card text
through the new keys.
- Around line 109-164: Update src/pages/admin/dashboard/retention/index.vue
lines 109-164 by changing trialOrganizationsColumns from
ref<TableColumn[]>([...]) to computed<TableColumn[]>(() => [...]), preserving
its column definitions. Update src/pages/admin/dashboard/retention/churn.vue
lines 59-101 by wrapping cancelledOrganizationsColumns in
computed<TableColumn[]>(() => [...]) and adding computed to the Vue import, so
translated headers react to locale changes.

In `@src/pages/admin/dashboard/revenue/index.vue`:
- Line 105: Remove the full global_stats_trend payload debug logging from the
revenue dashboard loader in src/pages/admin/dashboard/revenue/index.vue at lines
105-105 and the retention dashboard loader in
src/pages/admin/dashboard/retention/index.vue at lines 219-219; leave the
surrounding data-loading behavior unchanged and follow the no-logging pattern
used by the risk dashboard.
- Line 761: Replace the truthiness fallbacks in both revenue cards with
nullish-coalescing fallbacks: update the expressions at the “Total Paid
Organizations” and “Paid via Subscription” values to use `??` so a legitimate
zero is preserved while null or undefined still falls back to the alternate
metric and then zero.

In `@src/pages/admin/dashboard/revenue/risk.vue`:
- Line 59: Replace the hard-coded series labels in the chart configuration near
“New Subscriptions” and the corresponding label at line 67 with translation keys
resolved through the page’s existing t(...) helper. Add the new keys and English
values to messages/en.json, and apply the same translated labels in the
corresponding chart configuration in revenue/index.vue; do not use inline
fallback text as a translation argument.
- Around line 59-67: Add a shared pair of subscription-flow label keys to
messages/en.json, then update subscriptionFlowSeries in
src/pages/admin/dashboard/revenue/risk.vue (59-67) and
src/pages/admin/dashboard/revenue/index.vue (148-156) to use t(...) with those
keys for both labels. Do not pass inline fallback text; use the same keys in
both files to keep the chart labels localized and synchronized.

In `@src/pages/admin/dashboard/revenue/upgrades.vue`:
- Around line 136-146: Update the `need-upgrade` card’s `title` to use the
existing `t(...)` translation pattern, add the corresponding title key with its
English text to `messages/en.json`, and do not pass inline fallback text to the
translation call.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ad6fed9a-49d1-492c-87b0-60f3dcdb03af

📥 Commits

Reviewing files that changed from the base of the PR and between dea082a and 3fd1769.

📒 Files selected for processing (47)
  • docs/pr-assets/admin-intention-ia/real-customers.webp
  • docs/pr-assets/admin-intention-ia/real-onboarding-cohorts.webp
  • docs/pr-assets/admin-intention-ia/real-onboarding-funnel.webp
  • docs/pr-assets/admin-intention-ia/real-onboarding-sources.webp
  • docs/pr-assets/admin-intention-ia/real-product-updates.webp
  • docs/pr-assets/admin-intention-ia/real-pulse.webp
  • docs/pr-assets/admin-intention-ia/real-retention.webp
  • docs/proposals/admin-dashboard-intention-ia.md
  • messages/en.json
  • scripts/capture-admin-screens.mjs
  • src/auto-imports.d.ts
  • src/components.d.ts
  • src/constants/adminCustomersTabs.ts
  • src/constants/adminOnboardingTabs.ts
  • src/constants/adminPlatformTabs.ts
  • src/constants/adminProductTabs.ts
  • src/constants/adminRetentionTabs.ts
  • src/constants/adminRevenueTabs.ts
  • src/constants/adminTabs.ts
  • src/layouts/admin.vue
  • src/main.ts
  • src/modules/sso-enforcement.ts
  • src/pages/admin/dashboard/customers/credits.vue
  • src/pages/admin/dashboard/customers/organizations.vue
  • src/pages/admin/dashboard/index.vue
  • src/pages/admin/dashboard/onboarding/cohorts.vue
  • src/pages/admin/dashboard/onboarding/index.vue
  • src/pages/admin/dashboard/onboarding/sources.vue
  • src/pages/admin/dashboard/platform/capacity.vue
  • src/pages/admin/dashboard/platform/debug.vue
  • src/pages/admin/dashboard/platform/replication.vue
  • src/pages/admin/dashboard/product/builder.vue
  • src/pages/admin/dashboard/product/cli.vue
  • src/pages/admin/dashboard/product/notifications.vue
  • src/pages/admin/dashboard/product/plugins.vue
  • src/pages/admin/dashboard/product/updates.vue
  • src/pages/admin/dashboard/pulse.vue
  • src/pages/admin/dashboard/retention/churn.vue
  • src/pages/admin/dashboard/retention/inactive.vue
  • src/pages/admin/dashboard/retention/index.vue
  • src/pages/admin/dashboard/revenue/index.vue
  • src/pages/admin/dashboard/revenue/risk.vue
  • src/pages/admin/dashboard/revenue/upgrades.vue
  • src/pages/admin/dashboard/users.vue
  • src/route-map.d.ts
  • tests/admin-registration-source-dashboard.unit.test.ts
  • tests/email-preferences-public.unit.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)
💤 Files with no reviewable changes (2)
  • src/pages/admin/dashboard/index.vue
  • src/pages/admin/dashboard/users.vue
🛑 Comments failed to post (9)
src/pages/admin/dashboard/customers/credits.vue (2)

141-165: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

monthEndMrr depends on the row order returned by the API.

The loop assigns current.monthEndMrr = Number(row.mrr || 0) for every row in a month, so the last row processed wins. This equals the month-end value only when global_stats_trend returns rows in ascending date order. Compare dates before you overwrite the value.

♻️ Proposed change to make the month-end value order independent
   const monthlyBuckets = new Map<string, {
     date: string
+    monthEndDate: string
     creditsBought: number
     creditsConsumed: number
     monthEndMrr: number
   }>()
 
   for (const row of globalStatsTrendData.value) {
     const monthKey = toMonthKey(row.date)
     const current = monthlyBuckets.get(monthKey) ?? {
       date: monthKey,
+      monthEndDate: '',
       creditsBought: 0,
       creditsConsumed: 0,
       monthEndMrr: 0,
     }
 
     current.creditsBought += Number(row.credits_bought || 0)
     current.creditsConsumed += Number(row.credits_consumed || 0)
-    current.monthEndMrr = Number(row.mrr || 0)
+    if (row.date >= current.monthEndDate) {
+      current.monthEndDate = row.date
+      current.monthEndMrr = Number(row.mrr || 0)
+    }
     monthlyBuckets.set(monthKey, current)
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const monthlyCreditSummary = computed(() => {
  const monthlyBuckets = new Map<string, {
    date: string
    monthEndDate: string
    creditsBought: number
    creditsConsumed: number
    monthEndMrr: number
  }>()

  for (const row of globalStatsTrendData.value) {
    const monthKey = toMonthKey(row.date)
    const current = monthlyBuckets.get(monthKey) ?? {
      date: monthKey,
      monthEndDate: '',
      creditsBought: 0,
      creditsConsumed: 0,
      monthEndMrr: 0,
    }

    current.creditsBought += Number(row.credits_bought || 0)
    current.creditsConsumed += Number(row.credits_consumed || 0)
    if (row.date >= current.monthEndDate) {
      current.monthEndDate = row.date
      current.monthEndMrr = Number(row.mrr || 0)
    }
    monthlyBuckets.set(monthKey, current)
  }

  return Array.from(monthlyBuckets.values())
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/customers/credits.vue` around lines 141 - 165,
Update the monthlyCreditSummary aggregation to make monthEndMrr
order-independent: track the date associated with the selected MRR for each
month and only replace it when the current row.date is later than the stored
date. Preserve the existing creditsBought and creditsConsumed accumulation and
return shape.

245-249: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Invalidate the in-flight search when the query drops below two characters.

The early return clears searchResults but leaves currentSearchQuery at the previous longer query. A request that is still in flight for that longer query then passes the currentSearchQuery === query check at Line 268 and repopulates the dropdown after the user erased the input. isSearching also stays true in that window.

🐛 Proposed fix to invalidate stale searches
 async function searchOrgs(query: string) {
   if (query.length < 2) {
+    currentSearchQuery = query
     searchResults.value = []
+    isSearching.value = false
     return
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

async function searchOrgs(query: string) {
  if (query.length < 2) {
    currentSearchQuery = query
    searchResults.value = []
    isSearching.value = false
    return
  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/customers/credits.vue` around lines 245 - 249,
Update searchOrgs so queries shorter than two characters invalidate the active
search by clearing or changing currentSearchQuery and resetting isSearching to
false before returning; preserve the existing empty searchResults behavior and
prevent any in-flight longer-query response from passing the currentSearchQuery
check and repopulating results.
src/pages/admin/dashboard/product/cli.vue (1)

138-160: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Replace the hardcoded English strings with translation keys.

This page renders user-facing text directly: the three card titles and subtitles here, the chart titles on Lines 164, 179, 194, and 210, the section heading and description on Lines 223 and 226, the table headers on Lines 234 and 237, and the empty state on Line 244. The navigation title already uses t('cli'), so the page mixes localized and unlocalized text. Add keys for each string and update messages/en.json.

🌐 Example for the summary cards
             <AdminStatsCard
-              title="Total invocations"
+              :title="t('admin-cli-total-invocations')"
               :value="totalInvocations"
               color-class="text-primary"
               :is-loading="isLoadingStats"
-              subtitle="Selected period"
+              :subtitle="t('selected-period')"
             />

As per coding guidelines: "Never pass inline fallback text as the second argument to translation calls; use translation keys and update messages/en.json."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/product/cli.vue` around lines 138 - 160, Replace
all hardcoded user-facing strings in the CLI dashboard, including the three
AdminStatsCard titles/subtitles, chart titles, section heading/description,
table headers, and empty state, with translation keys via the existing t
function. Add corresponding English entries to messages/en.json, and do not use
inline fallback text in translation calls; preserve the existing t('cli')
navigation localization.

Source: Coding guidelines

src/pages/admin/dashboard/product/plugins.vue (2)

211-226: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Both pages assign displayStore.NavTitle twice. Each page sets the title at setup scope and again at the end of onMounted. The second assignment has no effect and duplicates the same expression.

  • src/pages/admin/dashboard/product/plugins.vue#L211-L226: delete displayStore.NavTitle = t('plugins') from onMounted and keep the setup-scope assignment.
  • src/pages/admin/dashboard/product/updates.vue#L169-L184: delete displayStore.NavTitle = t('updates') from onMounted and keep the setup-scope assignment.
📍 Affects 2 files
  • src/pages/admin/dashboard/product/plugins.vue#L211-L226 (this comment)
  • src/pages/admin/dashboard/product/updates.vue#L169-L184
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/product/plugins.vue` around lines 211 - 226, Remove
the redundant displayStore.NavTitle assignment from the onMounted callback in
src/pages/admin/dashboard/product/plugins.vue#L211-L226, retaining the
setup-scope assignment. Apply the same change in
src/pages/admin/dashboard/product/updates.vue#L169-L184 by removing the
onMounted assignment for the updates title and keeping its setup-scope
assignment.

400-427: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add accessible names to the threshold select and the custom threshold input.

The <span>Min share</span> element is not associated with either control. Screen reader users receive no name for the select or the number input. Add label or aria-label to both FormKit controls.

♿ Proposed fix
                     <FormKit
                       v-model="thresholdSelection"
                       type="select"
+                      :label="t('admin-plugins-min-share')"
+                      label-class="sr-only"
                       :options="[
                       <FormKit
                         v-model="customThreshold"
                         type="number"
+                        :label="t('admin-plugins-min-share-custom')"
+                        label-class="sr-only"
                         number="float"

Based on the coding guideline "Every input, select, and textarea must have an associated accessible label or aria-label."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

                  <div class="flex flex-wrap items-center gap-2 text-xs text-slate-500 dark:text-slate-400">
                    <span>Min share</span>
                    <FormKit
                      v-model="thresholdSelection"
                      type="select"
                      :label="t('admin-plugins-min-share')"
                      label-class="sr-only"
                      :options="[
                        { label: '0%', value: '0' },
                        { label: '0.1%', value: '0.1' },
                        { label: '0.5%', value: '0.5' },
                        { label: '1%', value: '1' },
                        { label: '2%', value: '2' },
                        { label: '5%', value: '5' },
                        { label: 'Custom', value: 'custom' },
                      ]"
                      :classes="{ outer: 'mb-0! w-[92px]', input: 'd-select d-select-sm' }"
                    />
                    <div v-if="thresholdSelection === 'custom'" class="flex items-center gap-1">
                      <FormKit
                        v-model="customThreshold"
                        type="number"
                        :label="t('admin-plugins-min-share-custom')"
                        label-class="sr-only"
                        number="float"
                        :min="0"
                        :max="100"
                        :step="0.1"
                        :classes="{ outer: 'mb-0! w-[80px]', input: 'd-input d-input-sm' }"
                      />
                      <span>%</span>
                    </div>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/product/plugins.vue` around lines 400 - 427, Add
accessible names to both FormKit controls in the threshold filter: update the
select bound to thresholdSelection with a label or aria-label describing the
minimum share, and update the customThreshold number input with a distinct label
or aria-label describing the custom threshold percentage.

Source: Coding guidelines

src/pages/admin/dashboard/product/updates.vue (2)

57-71: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Discard stale responses in loadGlobalStatsTrend.

The watchers on lines 160-167 can start a second request before the first resolves. Without a sequence guard, an older response can overwrite a newer one, and the charts then show data for the previous date range. src/pages/admin/dashboard/product/notifications.vue lines 43-68 already implements this guard with trendRequestSeq. Apply the same pattern here.

🐛 Proposed fix
 const isLoadingGlobalStatsTrend = ref(false)
+let trendRequestSeq = 0
 async function loadGlobalStatsTrend() {
+  const requestSeq = ++trendRequestSeq
   isLoadingGlobalStatsTrend.value = true
   try {
     const data = await adminStore.fetchStats('global_stats_trend')
+    if (requestSeq !== trendRequestSeq)
+      return
     globalStatsTrendData.value = data || []
   }
   catch (error) {
+    if (requestSeq !== trendRequestSeq)
+      return
     console.error('[Admin Dashboard Updates] Error loading global stats trend:', error)
     globalStatsTrendData.value = []
   }
   finally {
-    isLoadingGlobalStatsTrend.value = false
+    if (requestSeq === trendRequestSeq)
+      isLoadingGlobalStatsTrend.value = false
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

let trendRequestSeq = 0

async function loadGlobalStatsTrend() {
  const requestSeq = ++trendRequestSeq
  isLoadingGlobalStatsTrend.value = true
  try {
    const data = await adminStore.fetchStats('global_stats_trend')
    if (requestSeq !== trendRequestSeq)
      return
    console.log('[Admin Dashboard Updates] Global stats trend data:', data)
    globalStatsTrendData.value = data || []
  }
  catch (error) {
    if (requestSeq !== trendRequestSeq)
      return
    console.error('[Admin Dashboard Updates] Error loading global stats trend:', error)
    globalStatsTrendData.value = []
  }
  finally {
    if (requestSeq === trendRequestSeq)
      isLoadingGlobalStatsTrend.value = false
  }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/product/updates.vue` around lines 57 - 71, Update
loadGlobalStatsTrend to use a trendRequestSeq-style sequence guard matching
notifications.vue: increment the request sequence when starting a fetch, capture
that value locally, and only apply success or error results when the response
belongs to the latest request. Keep loading-state cleanup from stale requests
from overriding the current request’s state.

61-61: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the debug console.log.

This statement logs the complete platform statistics payload on every load and on every date-range change. Delete it.

♻️ Proposed fix
     const data = await adminStore.fetchStats('global_stats_trend')
-    console.log('[Admin Dashboard Updates] Global stats trend data:', data)
     globalStatsTrendData.value = data || []
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    const data = await adminStore.fetchStats('global_stats_trend')
    globalStatsTrendData.value = data || []
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/product/updates.vue` at line 61, Remove the debug
console.log statement that logs the complete stats payload from the dashboard
updates data-loading flow, while leaving the surrounding statistics and
date-range behavior unchanged.
src/pages/admin/dashboard/revenue/index.vue (2)

105-105: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Debug logging of the full global_stats_trend payload remains in two dashboards. Each loader logs the entire response on every mount, date-range change, and refresh, which writes aggregate revenue, MRR, LTV, and customer counts to the browser console. src/pages/admin/dashboard/revenue/risk.vue loads the same metric without logging, which is the pattern to follow.

  • src/pages/admin/dashboard/revenue/index.vue#L105-L105: delete the console.log('[Admin Dashboard Revenue] Global stats trend data:', data) statement.
  • src/pages/admin/dashboard/retention/index.vue#L219-L219: delete the console.log('[Admin Dashboard Retention Trials] Global stats trend data:', data) statement.
📍 Affects 2 files
  • src/pages/admin/dashboard/revenue/index.vue#L105-L105 (this comment)
  • src/pages/admin/dashboard/retention/index.vue#L219-L219
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/revenue/index.vue` at line 105, Remove the full
global_stats_trend payload debug logging from the revenue dashboard loader in
src/pages/admin/dashboard/revenue/index.vue at lines 105-105 and the retention
dashboard loader in src/pages/admin/dashboard/retention/index.vue at lines
219-219; leave the surrounding data-loading behavior unchanged and follow the
no-logging pattern used by the risk dashboard.

761-761: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use ?? so a real count of zero is not replaced by a different metric.

latestGlobalStats.paying_orgs_total || latestGlobalStats.paying || 0 treats a genuine 0 as missing and falls back to paying. The card then reports the total paying count under the "Total Paid Organizations" heading. Line 777 has the same defect for "Paid via Subscription". Use ??, which only falls back when the field is null or undefined.

🐛 Proposed fix for both cards
-                  {{ formatNumberValue(latestGlobalStats.paying_orgs_total || latestGlobalStats.paying || 0) }}
+                  {{ formatNumberValue(latestGlobalStats.paying_orgs_total ?? latestGlobalStats.paying ?? 0) }}
@@
-                  {{ formatNumberValue(latestGlobalStats.paying_orgs_subscription || latestGlobalStats.paying || 0) }}
+                  {{ formatNumberValue(latestGlobalStats.paying_orgs_subscription ?? latestGlobalStats.paying ?? 0) }}

Also applies to: 777-777

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/revenue/index.vue` at line 761, Replace the
truthiness fallbacks in both revenue cards with nullish-coalescing fallbacks:
update the expressions at the “Total Paid Organizations” and “Paid via
Subscription” values to use `??` so a legitimate zero is preserved while null or
undefined still falls back to the alternate metric and then zero.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 47 files

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread src/pages/admin/dashboard/retention/inactive.vue Outdated
Comment thread src/pages/admin/dashboard/retention/churn.vue
Comment thread src/pages/admin/dashboard/retention/index.vue
Comment thread src/modules/sso-enforcement.ts Outdated
Comment thread scripts/capture-admin-screens.mjs Outdated
Comment thread src/pages/admin/dashboard/retention/index.vue Outdated
Comment thread src/pages/admin/dashboard/retention/index.vue Outdated
Comment thread src/pages/admin/dashboard/revenue/upgrades.vue Outdated
Comment thread src/pages/admin/dashboard/onboarding/index.vue Outdated
Comment thread src/pages/admin/dashboard/platform/capacity.vue Outdated
Gate local SSO bypass on DEV, centralize hub primary routes, and fall
back secondary tabs to the first key. Extract shared onboarding funnel
metrics and organization insight types. Guard admin reload watchers,
reset churn pagination, page inactive orgs, drop debug logs, and move
hardcoded labels into i18n keys.

Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Add request-sequence guards for capacity and revenue risk stats.
Avoid starting capacity polling after unmount. Remove unreachable
trailing-slash admin dashboard redirect.

Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: medium. Left a non-blocking comment — broad admin IA reorg (50 files) with SSO-gate and routing changes exceeds the low-risk auto-approve threshold; Cursor Bugbot was not present on this head after the first poll. Human review is needed; reviewers were already assigned, so none were added.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver External

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 24 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/pages/admin/dashboard/retention/churn.vue Outdated
Comment thread src/pages/admin/dashboard/retention/inactive.vue Outdated
Comment thread src/pages/admin/dashboard/revenue/index.vue Outdated
Comment thread src/pages/admin/dashboard/platform/capacity.vue Outdated
Comment thread src/pages/admin/dashboard/retention/inactive.vue Outdated
Comment thread src/constants/adminHubs.ts Outdated
Comment thread src/pages/admin/dashboard/customers/organizations.vue Outdated
Extract shared revenue panels/composables and admin stats types.
Harden loaders, fix a11y/i18n/watchers, and migrate trend loaders
onto useAdminGlobalStatsTrend so new-code duplication drops under
the Sonar gate.

Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
@cursor
cursor Bot deployed to deepsec-pr August 11, 2026 20:43 Active

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: medium. Left a non-blocking comment — broad admin IA reorg (56 files) with SSO-gate and routing changes exceeds the low-risk auto-approve threshold; Cursor Bugbot was not present on this head after the first poll. Human review is needed; reviewers were already assigned, so none were added.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver External

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/pages/admin/dashboard/onboarding/index.vue (1)

40-52: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Prevent stale onboarding funnel responses from replacing current data.

A prior request can finish after a newer date-range request. It then replaces the funnel data and clears the loading state for the current selection. Add a per-page request sequence and ignore stale success, error, and finally updates, as useAdminGlobalStatsTrend already does.

  • src/pages/admin/dashboard/onboarding/index.vue#L40-L52: increment and validate a funnel request sequence before each state update.
  • src/pages/admin/dashboard/onboarding/cohorts.vue#L30-L43: apply the same sequence guard to funnel state and loading updates.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/onboarding/index.vue` around lines 40 - 52, In
src/pages/admin/dashboard/onboarding/index.vue lines 40-52, add a per-page
funnel request sequence in loadOnboardingFunnel, increment it for each request,
and guard success, catch, and finally state updates so stale requests cannot
replace data or clear loading for the current selection. Apply the same sequence
guard to funnel data and loading updates in
src/pages/admin/dashboard/onboarding/cohorts.vue lines 30-43, following the
pattern used by useAdminGlobalStatsTrend.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/admin/AdminStatsCard.vue`:
- Around line 61-62: Update the interactive root element in AdminStatsCard,
including its conditional clickable class binding, to add the project-standard
DaisyUI d- button or card class while preserving the existing Tailwind layout
and interaction utilities.
- Around line 58-62: Update the root component in AdminStatsCard so the
clickable button variant contains only valid phrasing-content descendants:
replace nested div and paragraph wrappers with appropriate span elements while
preserving the existing layout, styling, and non-clickable div behavior.

In `@src/composables/useOnboardingFunnelMetrics.ts`:
- Around line 111-118: Update onboardingFunnelConversionGridClass so five
conversion summaries use five columns at the sm breakpoint, keeping the
subscribed summary on the same row; preserve the existing six- and seven-summary
layouts and the two-column base layout.

In `@src/pages/admin/dashboard/customers/organizations.vue`:
- Around line 270-280: Merge the separate watchers for
adminStore.activeDateRange and adminStore.refreshTrigger into one combined
watcher, following the existing pattern in the credits page. Preserve the admin
check, resetting to the first page for date-range changes and loading
immediately for refresh-only changes, while ensuring a single refresh triggers
only one request through loadOrganizationsImmediately.

In `@src/pages/admin/dashboard/onboarding/sources.vue`:
- Around line 233-243: Prevent stale dashboard requests from overwriting current
state by adding a request sequence or AbortController to the loader flows. In
src/pages/admin/dashboard/onboarding/sources.vue#L233-L243, guard all three
loader result updates; in src/pages/admin/dashboard/product/cli.vue#L103-L111,
guard cliUsage.value and isLoadingStats.value; and in
src/pages/admin/dashboard/product/plugins.vue#L198-L206, guard
pluginBreakdown.value and isLoadingBreakdown.value. Only commit results and
loading-state changes when the request remains current.

---

Outside diff comments:
In `@src/pages/admin/dashboard/onboarding/index.vue`:
- Around line 40-52: In src/pages/admin/dashboard/onboarding/index.vue lines
40-52, add a per-page funnel request sequence in loadOnboardingFunnel, increment
it for each request, and guard success, catch, and finally state updates so
stale requests cannot replace data or clear loading for the current selection.
Apply the same sequence guard to funnel data and loading updates in
src/pages/admin/dashboard/onboarding/cohorts.vue lines 30-43, following the
pattern used by useAdminGlobalStatsTrend.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: cab3fa21-749e-4d8f-9763-2035d06fa404

📥 Commits

Reviewing files that changed from the base of the PR and between 3fd1769 and 3d546f0.

📒 Files selected for processing (32)
  • messages/en.json
  • scripts/capture-admin-screens.mjs
  • src/auto-imports.d.ts
  • src/components.d.ts
  • src/components/admin/AdminRevenueRiskPanel.vue
  • src/components/admin/AdminRevenueUpgradesPanel.vue
  • src/components/admin/AdminStatsCard.vue
  • src/composables/useAdminGlobalStatsTrend.ts
  • src/composables/useAdminRevenueDashboard.ts
  • src/composables/useOnboardingFunnelMetrics.ts
  • src/constants/adminHubs.ts
  • src/layouts/admin.vue
  • src/main.ts
  • src/modules/sso-enforcement.ts
  • src/pages/admin/dashboard/customers/credits.vue
  • src/pages/admin/dashboard/customers/organizations.vue
  • src/pages/admin/dashboard/onboarding/cohorts.vue
  • src/pages/admin/dashboard/onboarding/index.vue
  • src/pages/admin/dashboard/onboarding/sources.vue
  • src/pages/admin/dashboard/platform/capacity.vue
  • src/pages/admin/dashboard/product/cli.vue
  • src/pages/admin/dashboard/product/plugins.vue
  • src/pages/admin/dashboard/product/updates.vue
  • src/pages/admin/dashboard/pulse.vue
  • src/pages/admin/dashboard/retention/churn.vue
  • src/pages/admin/dashboard/retention/inactive.vue
  • src/pages/admin/dashboard/retention/index.vue
  • src/pages/admin/dashboard/revenue/index.vue
  • src/pages/admin/dashboard/revenue/risk.vue
  • src/pages/admin/dashboard/revenue/upgrades.vue
  • src/services/adminOrganizationInsights.ts
  • src/services/adminStatsTypes.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)
💤 Files with no reviewable changes (1)
  • src/main.ts

Comment thread src/components/admin/AdminStatsCard.vue Outdated
Comment thread src/components/admin/AdminStatsCard.vue Outdated
Comment thread src/composables/useOnboardingFunnelMetrics.ts
Comment thread src/pages/admin/dashboard/customers/organizations.vue Outdated
Comment thread src/pages/admin/dashboard/onboarding/sources.vue

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 26 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/components/admin/AdminStatsCard.vue Outdated
Comment thread src/components/admin/AdminRevenueRiskPanel.vue
Comment thread src/components/admin/AdminRevenueUpgradesPanel.vue Outdated
Comment thread src/pages/admin/dashboard/retention/inactive.vue
Comment thread src/components/admin/AdminRevenueUpgradesPanel.vue Outdated
Comment thread src/services/adminStatsTypes.ts
Comment thread src/components/admin/AdminStatsCard.vue
Re-export onboarding funnel types from backend pg utils, share org
insight columns and admin reload helpers, and fix AdminStatsCard
keyboard/DaisyUI semantics so duplication stays under the gate.

Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
@cursor
cursor Bot deployed to deepsec-pr August 11, 2026 20:59 Active

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: medium. Left a non-blocking comment — broad admin IA reorg (56 files) with SSO-gate and routing changes exceeds the low-risk auto-approve threshold; Cursor Bugbot was not present on this head after the first poll. Human review is needed; reviewers were already assigned, so none were added.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver External

Share chart series types, clear stale inactive truncation, localize
upgrade empty-rate display, and keep AdminStatsCard keyboard-safe.

Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
@cursor
cursor Bot deployed to deepsec-pr August 11, 2026 21:00 Active

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/composables/useAdminStatsReload.ts`:
- Around line 37-42: Update the loading flow in the useAdminStatsReload
composable so the isLoading ref is always reset to false in a finally block,
including when the optional load function rejects. Preserve the existing
behavior of setting isLoading to true before invoking load and only invoke load
when provided.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7ec7e7a3-a1b8-4fbb-8a3f-974e0936bafc

📥 Commits

Reviewing files that changed from the base of the PR and between 3d546f0 and 864b5d3.

📒 Files selected for processing (19)
  • src/auto-imports.d.ts
  • src/components/admin/AdminRevenueRiskPanel.vue
  • src/components/admin/AdminRevenueUpgradesPanel.vue
  • src/components/admin/AdminStatsCard.vue
  • src/composables/useAdminGlobalStatsTrend.ts
  • src/composables/useAdminRevenueDashboard.ts
  • src/composables/useAdminStatsReload.ts
  • src/composables/useOnboardingFunnelMetrics.ts
  • src/pages/admin/dashboard/customers/organizations.vue
  • src/pages/admin/dashboard/onboarding/sources.vue
  • src/pages/admin/dashboard/product/cli.vue
  • src/pages/admin/dashboard/product/plugins.vue
  • src/pages/admin/dashboard/product/updates.vue
  • src/pages/admin/dashboard/retention/inactive.vue
  • src/pages/admin/dashboard/revenue/index.vue
  • src/pages/admin/dashboard/revenue/risk.vue
  • src/pages/admin/dashboard/revenue/upgrades.vue
  • src/services/adminOrganizationInsightColumns.ts
  • src/services/adminStatsTypes.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

Comment thread src/composables/useAdminStatsReload.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 19 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/services/adminOrganizationInsightColumns.ts
Comment thread src/composables/useAdminStatsReload.ts Outdated
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
@cursor
cursor Bot deployed to deepsec-pr August 11, 2026 21:09 Active
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
@cursor
cursor Bot deployed to deepsec-pr August 11, 2026 21:22 Active
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
@cursor
cursor Bot deployed to deepsec-pr August 11, 2026 21:40 Active

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Risk: medium. Left a non-blocking comment — broad admin IA reorg (62 files) with SSO-gate and routing changes exceeds the low-risk auto-approve threshold, so human review is needed. Reviewers were already assigned; none added.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver External

Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
@cursor
cursor Bot deployed to deepsec-pr August 11, 2026 21:43 Active

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
messages/en.json (1)

2072-2072: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the internal TODO from the rendered translation.

This string is user-visible in the admin dashboard. Replace TODO — with a user-facing status message.

Proposed copy
-  "plans-analytics-checkout-completion-description": "TODO — this graph will be implemented after reliable checkout-completion tracking is available.",
+  "plans-analytics-checkout-completion-description": "Checkout completion data is not available yet. This graph will be added after reliable tracking is available.",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@messages/en.json` at line 2072, Update the
plans-analytics-checkout-completion-description translation to remove the
internal “TODO —” prefix and replace it with user-facing wording, while
preserving the message’s explanation about checkout-completion tracking
availability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pages/admin/dashboard/onboarding/frontend.vue`:
- Around line 67-68: Update the funnel data used by funnelStages and
funnelSummaries, plus the largest-drop-off rendering around the referenced
sections, to derive labels from each stage.key through the i18n translation
system instead of using the fixed stage.label. Add the corresponding English
stage-label entries to messages/en.json and propagate those keys and
translations through the locale catalogs, preserving existing chart and summary
behavior.

In `@src/pages/admin/dashboard/revenue/plans.vue`:
- Around line 307-314: Update the documentation anchor in the plans page by
adding the configured DaisyUI d-link class to its existing class list, while
preserving the existing hover:no-underline utility and other styling.

---

Outside diff comments:
In `@messages/en.json`:
- Line 2072: Update the plans-analytics-checkout-completion-description
translation to remove the internal “TODO —” prefix and replace it with
user-facing wording, while preserving the message’s explanation about
checkout-completion tracking availability.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4f5d0cac-3117-4993-88c9-af42c348924f

📥 Commits

Reviewing files that changed from the base of the PR and between 864b5d3 and 259d201.

📒 Files selected for processing (13)
  • messages/en.context.json
  • messages/en.json
  • src/auto-imports.d.ts
  • src/composables/useAdminStatsReload.ts
  • src/constants/adminOnboardingTabs.ts
  • src/constants/adminRevenueTabs.ts
  • src/main.ts
  • src/modules/sso-enforcement.ts
  • src/pages/admin/dashboard/onboarding/frontend.vue
  • src/pages/admin/dashboard/revenue/plans.vue
  • src/route-map.d.ts
  • tests/admin-frontend-onboarding-dashboard.unit.test.ts
  • tests/admin-plans-analytics-dashboard.unit.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
messages/en.json (1)

2072-2072: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the internal TODO from the rendered translation.

This string is user-visible in the admin dashboard. Replace TODO — with a user-facing status message.

Proposed copy
-  "plans-analytics-checkout-completion-description": "TODO — this graph will be implemented after reliable checkout-completion tracking is available.",
+  "plans-analytics-checkout-completion-description": "Checkout completion data is not available yet. This graph will be added after reliable tracking is available.",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@messages/en.json` at line 2072, Update the
plans-analytics-checkout-completion-description translation to remove the
internal “TODO —” prefix and replace it with user-facing wording, while
preserving the message’s explanation about checkout-completion tracking
availability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pages/admin/dashboard/onboarding/frontend.vue`:
- Around line 67-68: Update the funnel data used by funnelStages and
funnelSummaries, plus the largest-drop-off rendering around the referenced
sections, to derive labels from each stage.key through the i18n translation
system instead of using the fixed stage.label. Add the corresponding English
stage-label entries to messages/en.json and propagate those keys and
translations through the locale catalogs, preserving existing chart and summary
behavior.

In `@src/pages/admin/dashboard/revenue/plans.vue`:
- Around line 307-314: Update the documentation anchor in the plans page by
adding the configured DaisyUI d-link class to its existing class list, while
preserving the existing hover:no-underline utility and other styling.

---

Outside diff comments:
In `@messages/en.json`:
- Line 2072: Update the plans-analytics-checkout-completion-description
translation to remove the internal “TODO —” prefix and replace it with
user-facing wording, while preserving the message’s explanation about
checkout-completion tracking availability.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4f5d0cac-3117-4993-88c9-af42c348924f

📥 Commits

Reviewing files that changed from the base of the PR and between 864b5d3 and 259d201.

📒 Files selected for processing (13)
  • messages/en.context.json
  • messages/en.json
  • src/auto-imports.d.ts
  • src/composables/useAdminStatsReload.ts
  • src/constants/adminOnboardingTabs.ts
  • src/constants/adminRevenueTabs.ts
  • src/main.ts
  • src/modules/sso-enforcement.ts
  • src/pages/admin/dashboard/onboarding/frontend.vue
  • src/pages/admin/dashboard/revenue/plans.vue
  • src/route-map.d.ts
  • tests/admin-frontend-onboarding-dashboard.unit.test.ts
  • tests/admin-plans-analytics-dashboard.unit.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)
🛑 Comments failed to post (2)
src/pages/admin/dashboard/onboarding/frontend.vue (1)

67-68: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Localize funnel stage labels before rendering.

FrontendOnboardingAnalytics.funnel[].label contains fixed English text. These lines send that text to the funnel chart, summary cards, and largest-drop-off message. The page therefore shows English stage labels in non-English locales.

Map stage.key to translation keys before rendering these values. Add the English values to messages/en.json and update the locale catalogs.

Also applies to: 84-92, 186-195

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/onboarding/frontend.vue` around lines 67 - 68,
Update the funnel data used by funnelStages and funnelSummaries, plus the
largest-drop-off rendering around the referenced sections, to derive labels from
each stage.key through the i18n translation system instead of using the fixed
stage.label. Add the corresponding English stage-label entries to
messages/en.json and propagate those keys and translations through the locale
catalogs, preserving existing chart and summary behavior.
src/pages/admin/dashboard/revenue/plans.vue (1)

307-314: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- target file context ---'
sed -n '285,325p' src/pages/admin/dashboard/revenue/plans.vue

printf '%s\n' '--- DaisyUI/config references ---'
rg -n --hidden -g '!node_modules' -g '!dist' -g '!build' 'd-link|DaisyUI|daisyui|link-primary|class="[^"]*\blink\b' . | head -200

printf '%s\n' '--- package/config files ---'
find . -maxdepth 2 -type f \( -name 'package.json' -o -name 'bunfig.toml' -o -name 'vite.config.*' -o -name 'tailwind.config.*' -o -name 'postcss.config.*' \) -print

Repository: Cap-go/capgo.app

Length of output: 9296


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- DaisyUI prefix configuration ---'
sed -n '25,95p' src/styles/style.css

printf '%s\n' '--- project guidance ---'
sed -n '745,775p' AGENTS.md
sed -n '155,175p' .github/copilot-instructions.md
sed -n '205,218p' DESIGN.md

printf '%s\n' '--- existing d-link usage ---'
sed -n '30,50p' src/components/PaymentRequiredModal.vue

printf '%s\n' '--- anchor class patterns ---'
rg -n --glob 'src/**/*.{vue,ts,tsx}' '<a\b|class="[^"]*(d-link|d-btn-link|link)' src | head -160

Repository: Cap-go/capgo.app

Length of output: 10991


🌐 Web query:

DaisyUI 5 link component class prefix d-link documentation

💡 Result:

In daisyUI 5, there is no specific link component called "d-link" by default. The standard link component uses the class name "link" [1][2]. If you are seeing "d-link" in your project, it is likely because you have configured a custom class prefix for daisyUI [3]. In daisyUI 5, you can set a global prefix for all daisyUI component classes (e.g., "d-") within your CSS file using the @plugin directive [3][4]. For example, if you configure your daisyUI plugin as follows: @plugin "daisyui" { prefix: "d-"; } Then the standard "link" component class becomes "d-link", "link-primary" becomes "d-link-primary", and so on [3]. You can find the official documentation for the link component at the daisyUI website [1][5]. While the documentation typically displays the default class names (e.g., "link"), these will automatically reflect your configured prefix if you are using a version of the documentation or setup that supports it, or you can manually apply the prefix to the class names provided in the examples [3][4].

Citations:


Use the configured DaisyUI link class.

Add d-link to the anchor’s existing class list. Keep the existing hover:no-underline utility.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/admin/dashboard/revenue/plans.vue` around lines 307 - 314, Update
the documentation anchor in the plans page by adding the configured DaisyUI
d-link class to its existing class list, while preserving the existing
hover:no-underline utility and other styling.

Source: Coding guidelines

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants