Repository navigation
refactor(web): feature state moves into its feature; outside code imports only root entries - #502
Merged
Merged
Conversation
…orts only root entries
Compare becomes a frontend feature. It takes the sync store (`app/store/useSyncStore`,
`sync-helpers` → `syncHelpers`, `sync-types` → `syncTypes`), all of `object-detail` (used
only by the Compare shell), the connection chips, `sameDatabase` and the workspace.
The SQL editor store and its slices move to `features/sql-editor/state/`.
A feature's public API is now the files at its root. `index.ts` stays light enough for
the first screen; heavier pieces get their own entry:
- `ui.ts`: schema-diff renderers; sql-editor components and clone-table SQL
- `state.ts`: the SQL editor store, which Home and the palette must not load
- `monaco.ts`: the Monaco setup, moved from the frontend root
- `view.ts` / `toolbar.ts`: shell entries
Lazy components are `load…` functions in `index.ts`: auth screens, connections dialogs,
migration history, the admin panel and the SQL editors.
The top toolbar is registry-driven. A view declares `toolbar: { start, end, below }`;
the shell keeps the activity indicator and the command palette. Compare's controls are
`CompareToolbar` in the feature, and Snapshots' history bar is `HistoryToolbar`. The DOM
and test IDs are unchanged.
`architecture.test.ts` now resolves relative specifiers too. It enforces:
- outside a feature, only its root files may be imported (`vi.mock` is exempt)
- no static import cycle may cross a feature boundary
- `shared/` never imports a feature (this caught `shared/api/bodyless-requests.test.ts`
importing a migrations API; its migration cases moved to
`features/migrations/api/migrationApi.test.ts`)
`relativeTime` and the generic Access form controls move to `shared/`. RISK_STYLE stays
with its one user.
Three naming exceptions are gone: `sync-types`, `sync-helpers` and `monaco-setup`.
First visit: 144.1 KB gzip, up from 141.5 KB, across 21 files instead of 10. The modules
are the same; Rolldown splits more of what the entry shares with lazy chunks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: 1fb6e203-39c4-4e7a-88b2-c432a626f3fe) |
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 free
to 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.
Step 4 of the feature-architecture schedule (
docs/plans/2026-10-10-feature-architecture.md).What moves
features/compare/):useSyncStore, plussyncHelpersandsyncTypes, renamed from kebab-case)object-detail(used only by the Compare shell)sameDatabaseand the workspacefeatures/sql-editor/state/.monaco-setup.tsmoves into sql-editor (lib/monacoSetup.ts, public asmonaco.ts).relativeTimeand the generic Access form controls move toshared/.Public API = root files
Outside a feature, code imports only the files at its root:
index.tsload…functions for lazy componentsview.tstoolbar.tsui.tsstate.tsMeasured, not assumed: one barrel import from the eager toolbar took the first visit from 141.5 to 195.7 KB gzip. Rolldown does not drop unused re-exports here.
Toolbar from the registry
A view declares
toolbar: { start, end, below }. The shell keeps the activity indicator and the command palette. The DOM and test IDs are unchanged (same ID set in the catalog). One difference: the connection modal now unmounts when you leave Compare, and it can only be opened from there.Boundary test
architecture.test.tsnow resolves relative paths too (../../features/xwas invisible before). It enforces:vi.mockis exempt)shared/never imports a featureVerification
tsc --noEmit: 0 errors. ESLint and security lint: clean.vitest run: 6071 passed (495 files).npm run test-ids: the same 1717 IDs.index.ts) did not change that.backup-restore-ui(needs SQL Server)🤖 Generated with Claude Code
Note
Medium Risk
Large structural refactor across Compare, SQL editor, and shell wiring; behavior is heavily tested but mistakes in store/toolbar boundaries could break schema compare, migrations, or first-load bundles.
Overview
Refactors the web frontend around feature-owned state and a registry-driven toolbar, so the shell no longer embeds Compare/Snapshots controls directly.
Compare becomes a first-class feature:
useSyncStoreand helpers move out ofapp/store, formerobject-detailUI is folded in, and Compare/Sync workspace loads viafeatures/compare/view. Compare and Snapshots registertoolbar.tsentries (start/end/below);TopToolbaronly renders shell chrome (activity + ⌘K) plus those slots. Compare toolbar behavior is unchanged in substance but lives inCompareToolbar.tsx.Cross-feature imports are narrowed to feature root entries (
index.ts,view.ts,toolbar.ts,ui.ts,state.ts) with lazyload…helpers instead of barrel re-exports that pulled Monaco into the first paint. SQL editor store and recent-queries mirror move underfeatures/sql-editor/state; shared bits (relativeTime, access form controls) move toshared/.architecture.test.tsnow resolves paths, blocks deep feature imports, and forbids static import cycles across features.E2e test IDs are regrouped under a
comparenamespace matching the new component ownership.Reviewed by Cursor Bugbot for commit 4523a79. Bugbot is set up for automated code reviews on this repo. Configure here.