Skip to main content

Project structure

The frontend lives entirely under src/. Each top-level folder owns one responsibility.

src/
main.tsx # React root + BrowserRouter
App.tsx # router + auth gate
index.css # Tailwind entry
app/
AppShell.tsx # authenticated container for one workspace
providers/ # AppProviders (auth + workspaces composition)
auth/
AuthContext.tsx # useAuth() + provider selection
MockAuthProvider.tsx # local/dev provider (test account)
ArcGisAuthProvider.tsx # real ArcGIS OAuth, multi-connection
SignInPanel.tsx # sign-in UI
auth.config.ts # AUTH_MODE + storage keys
types.ts # AuthUser, ArcGisConfiguration, ...
userFromPortal.ts # portal user -> AuthUser
dialogs/ # connection add/manage dialogs
useConnectionDialogs.tsx
components/
header/ # AppHeader, UserMenu, ViewTabs
ui/ # shadcn/Radix primitives + Tailwind preset
CopLegend.tsx
lib/
utils.ts # genId(), nowIso()
test/
setup.ts # Vitest + jest-dom setup
widgets/
registry.tsx # WIDGET_DEFINITIONS + lookups
config.tsx # config-panel registry
index.ts # widget barrel exports
widgets/ # one folder per widget
internal/ # MapViewRegistry, WidgetPlaceholder, shells
actions/ # cross-widget action routing
schemas/ # shared Zod schemas
legacy/ # retained legacy widgets
workspaces/
types.ts # WorkspaceConfig, ViewConfig, WidgetInstance
canvas/ # ViewCanvas, WidgetFrame, WidgetConfigDrawer, picker
dialogs/ # name + settings dialogs
pages/ # WorkspacesPage (index)
persistence/ # WorkspacePersistenceProvider + ArcGIS item store
state/ # WorkspacesContext + auto-save

How responsibilities map

FolderOwns
app/Bootstrap, provider composition, the authenticated shell.
auth/The pluggable auth providers and sign-in UI.
components/Reusable UI: the header and the shadcn/ui design system.
lib/Tiny shared utilities (genId, nowIso).
widgets/The widget registry, the widgets themselves, and their config + actions.
workspaces/The data model, persistence, state, and the editing canvas.

Conventions

  • Colocated tests. Test files sit next to the code they cover as *.test.ts / *.test.tsx and run under Vitest. See Testing.
  • Schema-driven widgets. Each widget validates its config with a Zod schema and ships sample data used as a fallback. See Creating a widget.
  • Path alias. Imports use the @/ alias for src/ (for example @/auth/AuthContext).