Skip to content

Navigation & Dashboard Restructure — Design Spec

Date: 2026-07-09 Status: Approved by Brent (2026-07-09) Branch: claude/ui-navigation-settings-771007

Goal

Restructure the LGS Forge app navigation and landing experience for the launch userbase:

  • Small/new stores (500–2,000 products, low/mid tier) watch their product count and import only what they need. Singles-level browsing and syncing must be the most accessible surface.
  • Higher-end accounts sync by whole sets or one-click flows and spend little time in the app. Bulk set syncing stays one click deep under each game's Sets page.
  • Growth: settings are grouped so new catalogs (FAB, Lorcana, board games, supplies like penny sleeves) slot in without another nav redesign.

Scope

In scope (this pass):

  1. Sidebar/navigation restructure with real routes for every view.
  2. New Dashboard "Store Overview" landing page with live data.
  3. Store Settings split into General / Catalog / Billing.
  4. New Queue page (unified job history).
  5. Per-game catalog sections: Singles, Sealed, Sets, Settings (Pricing / Sync Settings / Metafields).
  6. One backend change: per-store enabledCatalogs preference.

Out of scope (future work):

  • Real announcements/mailbox system (new collection, admin authoring, per-store read state). This pass ships a static placeholder card.
  • Buylist feature. This pass ships a "coming soon" sidebar entry only.
  • New games beyond MTG and Pokemon.

1. Sidebar & URL Map

Three sidebar groups in RadixShell.jsx. Every item is a real route. Embedded mode preserves the ?shop= param on all navigation (existing handleNavClick pattern).

Account
  Dashboard            /dashboard
  Store Settings       ▸ expands
    General            /settings/general
    Catalog            /settings/catalog
    Billing            /settings/billing
  Queue                /queue
Catalog                (one entry per enabled game, from enabledCatalogs preference)
  Magic: The Gathering ▸ expands
    Singles            /catalog/mtg/singles
    Sealed             /catalog/mtg/sealed
    Sets               /catalog/mtg/sets
    Settings           ▸ expands
      Pricing          /catalog/mtg/settings/pricing
      Sync Settings    /catalog/mtg/settings/sync
      Metafields       /catalog/mtg/settings/metafields
  Pokemon              ▸ same structure under /catalog/pokemon/...
  + Add catalog        → navigates to /settings/catalog
Tools
  Buylist              "coming soon" (same disabled treatment as FAB/Lorcana today)

Expansion behavior

  • Clicking a game (or Store Settings) toggles an indented submenu in the sidebar.
  • The group containing the active route is auto-expanded on load.
  • Game Settings is a third nesting level, matching the approved structure. If it proves cramped, it can later collapse to tabs inside one settings page — the routes stay the same either way.

Legacy redirects

Old routeNew route
/sync/catalog/mtg/sets
/sync/pokemon/catalog/pokemon/sets
/settings/settings/general
/catalog/catalog/mtg/singles
/ (embedded)/dashboard

/catalog/:game (no sub-view) redirects to /catalog/:game/singles — Singles is the default landing per game. The embedded catch-all redirect (preserving shop) stays.

2. Dashboard — Store Overview (landing page)

Replaces the current Dashboard content. Header: "Store Overview" + "Managing {shop}". Built entirely from existing endpoints — no new backend.

  • Store Info card (rows, with room to add more):
    • Plan name + products used / remaining — /api/billing/status + /api/variant-budget
    • Last product sync (most recent completed job) — /api/sync/history?limit=1
    • Last price sync — /api/price-sync/history?limit=1
  • Announcements / Mailbox card: static placeholder ("You're all caught up") with layout ready for a future feed. No backend.
  • Activity section: last 5 jobs, merged from /api/sync/history and /api/price-sync/history, sorted by date descending. Status badges; row click opens the existing SyncJobDetailModal; "View all" links to /queue.
  • Existing banners stay: welcome, connection success/error, billing status.
  • Standalone mode additionally keeps the ConnectedStores multi-store management on this page; embedded mode hides it (as today).

Data calls run in parallel; each card renders independently with its own loading/error state so one failed call doesn't blank the page.

3. Store Settings

/settings/general

NotificationSettings + SalesChannelSettings, moved from the old Settings tab. No metafields here — metafields are per-game (section 5).

/settings/catalog

Toggle list of catalogs:

  • MTG, Pokemon: real toggles driving the enabledCatalogs store preference. Toggling off hides that game from the sidebar; it deletes nothing (synced products, schedules, and settings are untouched and reappear when re-enabled).
  • FAB, Lorcana, board games, supplies: shown as coming soon, not toggleable.

Existing stores default to both MTG and Pokemon enabled.

/settings/billing

Current plan + usage (reusing SubscriptionCard / billing status data) and a change-plan action linking to Shopify's managed-pricing plan selection page.

4. Queue — /queue

Unified job history: product syncs and price updates merged into one paginated table (job type, status, item counts, timestamps). Row click opens the existing detail modal. Built from SyncHistory / SyncJobDetailModal + /api/price-sync/history; no new backend.

5. Per-Game Catalog Pages

All routes take the game from the URL param (mtg | pokemon) — no more game-selector dropdown.

  • /catalog/:game/singles — today's catalog Singles view (search/filters, grid/list toggle, prices, per-card sync controls). Primary surface for small/mid-tier stores.
  • /catalog/:game/sealed — existing sealed browse/import views.
  • /catalog/:game/sets — existing set browser plus the set-sync controls moved from the old MTG/Pokemon Sync pages (set selection, sync button, live sync status). Bulk set syncing for high-end accounts lives here.
  • /catalog/:game/settings/pricing — pricing pipeline config (moved out of the old sync settings view).
  • /catalog/:game/settings/sync — sync schedule + price update scheduling.
  • /catalog/:game/settings/metafieldsSetupMetafields, scoped per game.

6. Backend Changes

One change: per-store enabledCatalogs preference.

  • Add to the store preferences shape (array of game ids, e.g. ["mtg", "pokemon"]).
  • Expose in GET /api/preferences; accept updates via the existing preferences update path.
  • Zod schema updated in server/schemas/; validated via server/middleware/validate.js.
  • Missing/absent field is treated as all-enabled (backward compatible — no migration needed).

Everything else reuses existing endpoints.

7. Implementation Notes

  • Dismantle Home.jsx (~1,100 lines): SyncTab, SyncSettingsView, and SettingsTab contents get extracted into the new page components; the route-selection-by-prop pattern (initialTab) is removed. Home.jsx is deleted when nothing routes to it.
  • Split CatalogTab.jsx views so each new route mounts the right view directly.
  • New page components live in client/src/pages/ and compose extracted feature components; presentational pieces continue to use retroui primitives.
  • RadixShell.jsx gains collapsible nav groups; the Catalog group is driven by the enabledCatalogs preference (via StoreContext).
  • Follow existing patterns: API calls through client/src/utils/api.js, no Polaris, Tailwind + retroui styling.

8. Error Handling

  • Overview cards degrade independently (per-card loading/error states).
  • Unknown :game param (or a disabled catalog's deep link) renders the game pages normally — the sidebar just won't highlight a group. Truly unknown games (not in /api/games) redirect to /dashboard.
  • All existing sync/billing error banners keep their current behavior.

9. Testing

Vitest (client config), keeping 70%+ coverage on touched files:

  • RadixShell: group rendering, expansion/collapse, active-route auto-expand, enabledCatalogs-driven visibility, coming-soon items.
  • Routing: each legacy redirect lands on the right new route with shop param preserved.
  • Store Overview: data assembly (merge/sort of last-5 activity), independent card error states.
  • Settings > Catalog: toggle round-trip against mocked preferences API; default-all-enabled fallback.
  • Queue: merged pagination of sync + price-sync histories.
  • Server: preferences schema accepts/rejects enabledCatalogs values correctly.