Skip to content

fix(console): a Setup-only environment lands on /home, not the all-zero System Overview - #4255

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-4048-sso-landing-home
Aug 11, 2026
Merged

fix(console): a Setup-only environment lands on /home, not the all-zero System Overview#4255
yinlianghui merged 1 commit into
mainfrom
claude/issue-4048-sso-landing-home

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#4048

The card is 25 days old and carries a standing injunction from its source thread
(objectstack-ai/objectstack#3083): a 2026-07-17 local prod-like rig failed to reproduce the
landing symptom for either a fresh user or a platform admin, and every triage round since
repeated ⛔ 不要盲改 RootRedirect / sso-exchange. So both halves were premise-checked
before any edit, and they resolved differently: half 1 reproduces and is fixed here;
half 2's stated cause is disproven and its real cause already shipped.

Half 1 — the measured resolution chain

There is no callbackURL or SSO surface in this repo at all (grep over
apps/console/src + packages/app-shell/src finds only a verify-email usage), so the
console-side question is purely the default-route resolution. For an authenticated
arrival with no explicit target:

/ apps/console/src/App.tsx:349
→ RootLandingRedirect apps/console/src/components/RootLandingRedirect.tsx
→ resolveLandingPath([setup])
rule 1 isDefault — no match: platform-objects ships setup/studio/account
all with `isDefault: false`
rule 2 single visible app — MATCHES → `/apps/setup`
→ AppContent.resolveLandingRoute() packages/app-shell/src/console/AppContent.tsx:944
→ the app's first navigation item
→ dashboard/system_overview platform-objects setup-nav.contributions.ts:38
(`group_overview` → `nav_system_overview`)

That last address is the one the card reported, and it is independently recorded in
setupRedirectTarget.test.tsx:17 as where objectui#2794 landed. The symptom is reachable
on this tip whenever the viewer's visible app set is exactly Setup — account is
hidden: true, and studio is withheld from anyone without studio.access, so a viewer
holding setup.access alone sees exactly one app. That also explains the 07-17
non-reproduction without contradicting it: the rig's users saw Setup and Studio, i.e.
two visible apps, which rule 3 already sends to /home.

The fix, and why it is this narrow

Rule 2 is right — a one-app product deployment should not have to click through a
one-tile launcher (#2027). Setup is not that app: it is the platform administration
console that @objectstack/platform-objects ships into every deployment, so "the only app
this viewer can see is Setup" means this environment has no product apps yet, not Setup
is the product
. Under ADR-0075 the environment layer's home is the environment's own
responsibility, and /home — build with AI, start from a template, Your apps — is that
home. Setup is excluded from the single-app outcome, never from the visible count:

visible appsbeforeafter
[setup]/apps/setup → System Overview/home
[setup] with isDefault: true/apps/setup/apps/setup (unchanged — a declared landing wins)
[crm]/apps/crm/apps/crm (unchanged — rule 2 intact)
[crm, setup]/home/home (unchanged)
[studio]/apps/studio/apps/studio (unchanged — deliberate, see below)
[]/home/home (unchanged)

Dropping Setup from the count instead would re-route every ordinary [product, setup]
deployment out of /home and into the product app — a far larger change than this card
asks for, and one nobody measured. Studio alone is deliberately left landing in Studio:
the workbench IS a builder surface, so that is defensible where an all-zero audit
dashboard is not, and widening this to every platform app is a judgment call this card
does not authorize.

isPlatformSetupApp resolves Setup by package id first and app name second — the same
order resolveSetupAppPath uses — so the / landing policy and the /setup deep link
cannot disagree about which app Setup is.

#4180 / #4186 interaction

Half 2 — premise disproven, real cause already shipped

The card asks for Total Users to become "a real sys_user count, 统计口径基于审计事件?".
It already is one, and always was. The widget is authored in the framework, not here —
packages/platform-objects/src/apps/dashboards/system_overview.dashboard.ts:31-39:

id: 'widget_total_users',dataset: 'sys_user_metrics',values: ['user_count'],

sys_user_metrics, not sys_audit_log_metrics — the audit-derived widgets are the other
ones (Login Events, Permission Changes, Config Changes, the pies and the table). So the
count was never audit-derived and there is nothing to re-point.

The reason it read 0 is a different defect, and it is already fixed in this repo: the
dashboard declares globalFilters: [{ field: 'created_at', type: 'date', defaultValue: 'last_7_days' }], and that bare preset name was passed through raw instead of being lifted
to a range, so buildFilterCondition fell into its "a bare string date means equality on
that day" branch and the backend compiled

SELECT COUNT(*) AS "user_count" FROM "sys_user" WHERE created_at = $1

verified against a live server, with an actual sys_user count of 4 — 200 OK, zero rows,
no error anywhere, which is also why every KPI tile read 0 and the period selector said
"All time". normalizeDateDefault in packages/core/src/utils/dashboard-filters.ts now
applies the same lift the sibling dateRange declaration always received (commit b414983,
objectstack#4475), pinned by dashboard-filters.test.ts "[#4475] lifts a date filter's
preset-name default to { preset }" and DashboardFilterBar.dateDefault.test.tsx "shows the
declared preset, not All time".

Both of the card's symptoms — the all-zeros dashboard and Total Users reading 0 — are that
one bug. No change is made for half 2 because none is needed, in either repo.

Tests

Red-first, then reverse-verified by reverting only the source and keeping the tests:
4 red exactly (the 3 fix pins plus the new deep-link control), 27 green — every
control held, which is what proves they are not passing because of the fix.

  • pnpm --filter '@object-ui/console^...' build — build closure green before judging anything
  • vitest run apps/console packages/app-shell374 files, 3596 passed, 1 skipped, 0 failed
  • pnpm --filter @object-ui/console --filter @object-ui/app-shell type-check — Done, both
  • eslint on the three changed files — 0 errors (1 pre-existing react-refresh warning:
    the file already exported both the resolver and the component on main)
  • pnpm check:control-bytes — OK, 3965 files; plus a direct escape-range self-scan of the
    four touched files, clean

No copy changed, so the i18n gates have no new surface. Changeset: patch for
@object-ui/console.


Generated by Claude Code

…ro System Overview (#4048)
A new builder arriving on a just-created environment (platform SSO, no explicit
target) landed on Setup's System Overview — a platform-health/audit dashboard
reading all zeros, because a fresh environment has no audit history yet.
Measured chain:
/ -> RootLandingRedirect -> resolveLandingPath([setup])
-> rule 2 "single visible app" -> /apps/setup
-> AppContent.resolveLandingRoute() -> the app's first nav item
-> dashboard/system_overview
Rule 2 is right for a one-app PRODUCT deployment. Setup is not that app: it is
the platform administration console @objectstack/platform-objects ships into
every deployment, so "the only visible app is Setup" means the environment has
no product apps yet. Under ADR-0075 the environment layer's home is the
environment's own responsibility, so that case now resolves /home.
Narrow by construction: rule 1 (isDefault) untouched so a declared landing still
wins; a one-app product deployment still lands in its app; [product, setup] is
unchanged because Setup is excluded from the single-app OUTCOME, never from the
visible COUNT; and the /setup deep link still resolves into Setup.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
@vercel

vercelBot commented Aug 11, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectuiIgnoredIgnoredAug 11, 2026 9:09am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)28.3 KB350 KB
Entry fileindex-CCBoswwI.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)8.88KB3.25KB
app-shell (runtime-config.js)7.42KB2.32KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)7.57KB2.97KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)22.10KB4.37KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.13KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.64KB2.21KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)35.76KB9.11KB
auth (createAuthenticatedFetch.js)4.37KB1.69KB
auth (index.js)2.35KB1.07KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)4.91KB0.87KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)26.07KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.65KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)488.60KB108.25KB
core (index.js)3.04KB1.15KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)144.34KB37.61KB
fields (index.js)228.43KB56.61KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.32KB1.77KB
i18n (index.js)2.65KB1.06KB
i18n (pickLocalized.js)1.70KB0.83KB
i18n (provider.js)9.48KB3.27KB
i18n (useObjectLabel.js)27.59KB6.63KB
i18n (useSafeTranslation.js)4.52KB1.96KB
layout (index.js)38.98KB10.85KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)8.75KB3.06KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)3.67KB1.12KB
permissions (evaluator.js)4.41KB1.44KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.55KB0.71KB
plugin-ai (index.js)15.71KB3.79KB
plugin-calendar (index.js)45.23KB12.45KB
plugin-charts (index.js)61.52KB17.49KB
plugin-chatbot (index.js)180.33KB42.79KB
plugin-dashboard (index.js)118.58KB30.71KB
plugin-designer (index.js)210.91KB42.67KB
plugin-detail (index.js)238.87KB59.70KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)114.58KB27.68KB
plugin-gantt (index.js)164.14KB39.98KB
plugin-grid (index.js)187.97KB49.90KB
plugin-kanban (index.js)48.60KB13.41KB
plugin-list (index.js)110.31KB26.76KB
plugin-map (index.js)17.00KB5.32KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)40.58KB10.58KB
plugin-timeline (index.js)26.21KB7.52KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)84.03KB20.55KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.71KB3.53KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.67KB2.37KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)23.71KB7.96KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.23KB0.66KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)4.09KB1.74KB
sdui-parser (index.js)4.47KB2.03KB
sdui-parser (parse.js)10.04KB2.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)4.69KB1.48KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-retry.js)4.32KB2.02KB
types (index.js)3.05KB1.52KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@yinlianghui
yinlianghui marked this pull request as ready for review August 11, 2026 09:22
@yinlianghui
yinlianghui added this pull request to the merge queueAug 11, 2026
Merged via the queue into main with commit 234238eAug 11, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-4048-sso-landing-home branch August 11, 2026 09:22
Sign up for freeto 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.

ux(setup): 平台 SSO 后落地 Setup System Overview(全 0 审计仪表盘)— 新 builder 应落 /_console/home;Total Users 显示 0

2 participants

@yinlianghui@claude