refactor(app): central routes/ module with paths registry#8546
Conversation
- router.tsx moves to src/routes/index.tsx (git mv, route config unchanged) - utils/paths.ts moves to src/routes/paths.ts and gains a paths registry — the single source of truth for app URLs (static routes, plotsFiltered builder, spec detail via specPath) - ~25 hardcoded route literals across 16 files replaced with paths.* - routes/paths.test.ts covers builders, reserved slugs, and the registry; routes/ added to coverage - Updated path references in spec-create.yml and docs/reference/seo.md Part 6 of the frontend modernization roadmap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
This PR continues the frontend modernization roadmap by consolidating routing into a dedicated src/routes/ module and introducing a centralized paths registry as the single source of truth for app URLs. It updates navigation/analytics call sites to reference the shared helpers, and adds focused unit tests for route building.
Changes:
- Moved router setup to
app/src/routes/index.tsxand updated app entrypoint import. - Expanded
app/src/routes/paths.tswith apathsregistry (static routes + builders) and updated call sites to use it. - Added unit tests for path builders and included
src/routes/**/*.tsin Vitest coverage; updated docs and workflow comments referencing the moved paths file.
Reviewed changes
Copilot reviewed 32 out of 33 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/reference/seo.md | Updates documentation references from utils/paths.ts to routes/paths.ts. |
| app/vitest.config.ts | Adds src/routes/**/*.ts to coverage include patterns. |
| app/src/routes/paths.ts | Adds paths registry alongside specPath, RESERVED_TOP_LEVEL, and langFromPath. |
| app/src/routes/paths.test.ts | Adds unit tests for specPath, langFromPath, reserved slugs, and the paths registry. |
| app/src/routes/index.tsx | Centralizes router creation under src/routes/ (moved router module). |
| app/src/pages/StatsPage.tsx | Replaces hardcoded routes with paths.* / paths.plotsFiltered for navigation and pageview tracking. |
| app/src/pages/SpecsListPage.tsx | Replaces hardcoded /specs pageview tracking with paths.specs. |
| app/src/pages/SpecPage.tsx | Uses paths.home (and imports from new routes/paths) for navigation. |
| app/src/pages/PlotsPage.tsx | Updates specPath import to new location. |
| app/src/pages/PalettePage.tsx | Replaces hardcoded /palette pageview tracking with paths.palette. |
| app/src/pages/NotFoundPage.tsx | Replaces hardcoded home link with paths.home. |
| app/src/pages/MapPage.tsx | Updates specPath import to new location. |
| app/src/pages/LibrariesPage.tsx | Replaces hardcoded routes with paths.* / paths.plotsFiltered for navigation and pageview tracking. |
| app/src/pages/LandingPage.tsx | Switches navigation to paths.* / paths.plotsFiltered and updates some route usages. |
| app/src/pages/DebugPage.tsx | Updates specPath import to new location. |
| app/src/pages/AboutPage.tsx | Replaces hardcoded internal links/pageview targets with paths.*. |
| app/src/hooks/useAnalytics.ts | Updates RESERVED_TOP_LEVEL import to new location. |
| app/src/components/ToolbarActions.tsx | Replaces hardcoded /plots link with paths.plots. |
| app/src/components/SpecTabs.tsx | Uses paths.plotsFiltered for tag navigation to plots. |
| app/src/components/SpecOverview.tsx | Updates specPath import to new location. |
| app/src/components/ScienceNote.tsx | Replaces hardcoded /palette link with paths.palette. |
| app/src/components/RouteErrorBoundary.tsx | Replaces hardcoded home link with paths.home. |
| app/src/components/RootLayout.tsx | Uses paths.plots when computing mastheadSticks. |
| app/src/components/RelatedSpecs.tsx | Updates specPath import to new location. |
| app/src/components/PlotOfTheDayTerminal.tsx | Updates specPath import to new location. |
| app/src/components/PlotOfTheDay.tsx | Updates specPath import to new location. |
| app/src/components/NavBar.tsx | Uses paths.plotsSearch, paths.debug, and paths.home for navigation. |
| app/src/components/MastheadRule.tsx | Updates RESERVED_TOP_LEVEL import to new location and uses paths.home. |
| app/src/components/HeroSection.tsx | Replaces CTA destinations and analytics targets with paths.*. |
| app/src/components/Footer.tsx | Replaces hardcoded internal links with paths.*. |
| app/src/components/FeedbackWidget.tsx | Updates RESERVED_TOP_LEVEL import to new location. |
| app/src/app.tsx | Updates router import to src/routes. |
| .github/workflows/spec-create.yml | Updates comment to reference app/src/routes/paths.ts as the source for RESERVED_TOP_LEVEL. |
Comments suppressed due to low confidence (1)
app/src/routes/paths.ts:65
paths.plotsFilteredencodes the value but not the query parameter name. Ifparamever contains&,=, or whitespace (even accidentally), it will generate an incorrect URL and can inject extra query params. Encode the key as well so both parts are safely serialized.
| const handleLibraryClick = (lib: string) => { | ||
| trackEvent('nav_click', { source: 'library_card', target: '/plots', value: lib }); | ||
| navigate(`/plots?lib=${encodeURIComponent(lib)}`); | ||
| navigate(paths.plotsFiltered('lib', lib)); | ||
| }; |
There was a problem hiding this comment.
Applied — all six hardcoded trackEvent targets (incl. two 'target: /' cases beyond the four flagged) now use the paths registry. See latest commit.
| component={RouterLink} | ||
| to="/map" | ||
| to={paths.map} | ||
| onClick={() => trackEvent('nav_click', { source: 'map_teaser_preview', target: '/map' })} |
There was a problem hiding this comment.
Applied — all six hardcoded trackEvent targets (incl. two 'target: /' cases beyond the four flagged) now use the paths registry. See latest commit.
| component={RouterLink} | ||
| to="/specs" | ||
| to={paths.specs} | ||
| onClick={() => trackEvent('nav_click', { source: 'specs_more_link', target: '/specs' })} |
There was a problem hiding this comment.
Applied — all six hardcoded trackEvent targets (incl. two 'target: /' cases beyond the four flagged) now use the paths registry. See latest commit.
Copilot review findings on the routes PR: trackEvent target strings stayed hardcoded where navigation already used paths.* — aligned all six (LandingPage x3, NavBar x2, MastheadRule x1) so analytics can't drift from the routing source of truth. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 32 out of 33 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
app/src/routes/paths.ts:65
paths.plotsFilteredinterpolates the query parameter key without encoding. Ifparamever contains characters like&or=(e.g. from refactors or caller mistakes), this produces a malformed URL and can inject additional query params. Encode the key the same way as the value.
| 'src/components/**/*.tsx', | ||
| 'src/pages/**/*.tsx', | ||
| 'src/constants/**/*.ts', | ||
| 'src/routes/**/*.ts', |
…tion (#8596) ## Summary Part 11 (final) of the frontend modernization roadmap. - **`app/ARCHITECTURE.md`**: directory layout (routes/layouts/pages/sections/components/hooks/lib/theme), conventions (`src/` alias imports, `paths.*` URL registry, `lib/api` client, theme tokens, feature folders), data flow, testing pattern, quality gates, and how-to-add recipes for pages/sections/hooks/endpoints - **`agentic/docs/project-guide.md`**: frontend section now lists the full gate (`lint`, `fm:check`, `type-check` incl. tests, `test`), mentions the dev-time checker overlay, and links the new architecture doc With this, the roadmap is complete: tooling baseline (#8519), src/ aliases (#8520), theme split (#8525), global-config (#8529), API client (#8531), routes registry (#8546), structure split (#8547), FilterBar (#8559), SpecTabs (#8564), MapPage hook (#8581). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
Part 6 of the frontend modernization roadmap.
router.tsxmoves tosrc/routes/index.tsx(git mv, route config unchanged — lazy pattern and error boundaries untouched)utils/paths.tsmoves tosrc/routes/paths.tsand gains apathsregistry — the single source of truth for app URLs: static routes,paths.plotsFiltered(param, value), spec detail via the existingspecPath(also exposed aspaths.spec)paths.*(Links,navigate(),trackPageview/trackEventtargets)routes/paths.test.ts(11 tests: builders, reserved slugs, registry);routes/added to coveragespec-create.yml(comment) anddocs/reference/seo.mdVerification
yarn lint✓ ·yarn fm:check✓ ·yarn type-check✓ ·yarn test547+ ✓ ·yarn build✓🤖 Generated with Claude Code