Uh oh!
There was an error while loading. Please reload this page.
fix(console): a Setup-only environment lands on /home, not the all-zero System Overview - #4255
Merged
Merged
Conversation
…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
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
yinlianghui
marked this pull request as ready for review
August 11, 2026 09:22
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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-checkedbefore 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
callbackURLor SSO surface in this repo at all (grep overapps/console/src+packages/app-shell/srcfinds only a verify-email usage), so theconsole-side question is purely the default-route resolution. For an authenticated
arrival with no explicit target:
That last address is the one the card reported, and it is independently recorded in
setupRedirectTarget.test.tsx:17as where objectui#2794 landed. The symptom is reachableon this tip whenever the viewer's visible app set is exactly Setup —
accountishidden: true, andstudiois withheld from anyone withoutstudio.access, so a viewerholding
setup.accessalone sees exactly one app. That also explains the 07-17non-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-objectsships into every deployment, so "the only appthis 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 thathome. Setup is excluded from the single-app outcome, never from the visible count:
[setup]/apps/setup→ System Overview/home[setup]withisDefault: 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
/homeand into the product app — a far larger change than this cardasks 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.
isPlatformSetupAppresolves Setup by package id first and app name second — the sameorder
resolveSetupAppPathuses — so the/landing policy and the/setupdeep linkcannot disagree about which app Setup is.
#4180 / #4186 interaction
/setupdeep link is untouched and pinned as a control on the very app listthis fix redirects:
/is "an arrival with no target" (the env home),/setupis anexplicit target and still resolves to
/apps/com.objectstack.setup.(
SetupPage.tsx:43,POST_BOOTSTRAP_EXIT = '/'), so a freshly bootstrapped owner alsostops landing on the all-zero dashboard. Same direction, no conflict.
Half 2 — premise disproven, real cause already shipped
The card asks for Total Users to become "a real
sys_usercount, 统计口径基于审计事件?".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:sys_user_metrics, notsys_audit_log_metrics— the audit-derived widgets are the otherones (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 liftedto a range, so
buildFilterConditionfell into its "a bare string date means equality onthat day" branch and the backend compiled
verified against a live server, with an actual
sys_usercount 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".
normalizeDateDefaultinpackages/core/src/utils/dashboard-filters.tsnowapplies the same lift the sibling
dateRangedeclaration always received (commit b414983,objectstack#4475), pinned by
dashboard-filters.test.ts"[#4475] lifts a date filter'spreset-name default to { preset }" and
DashboardFilterBar.dateDefault.test.tsx"shows thedeclared 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 anythingvitest run apps/console packages/app-shell— 374 files, 3596 passed, 1 skipped, 0 failedpnpm --filter @object-ui/console --filter @object-ui/app-shell type-check— Done, botheslinton the three changed files — 0 errors (1 pre-existingreact-refreshwarning: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 thefour touched files, clean
No copy changed, so the i18n gates have no new surface. Changeset: patch for
@object-ui/console.Generated by Claude Code