Frontend
The frontend is a Vite + React + TypeScript SPA. It consumes the backend through typed helpers and shares a custom Tome visual system.
Routing
web/src/App.tsx owns the top-level route tree:
- Public auth routes: login, signup, reset, verification, invite landing, OAuth callback.
- Authenticated app shell routes: campaign list, campaign detail, profile, upcoming sessions, platform settings.
- Campaign routes use
/campaigns/:id/:tab/:sub?soCampaignDetailstays mounted while users move between campaign tabs.
RequireAuth protects the app shell. GuestOnly keeps signed-in users out of
login/signup flows.
API Layer
All network calls go through web/src/lib/api.ts. This file also contains the
SSE streaming client for Rules Chat.
DTOs live in web/src/types.ts. Keep these synchronized with backend
serializers. Do not call fetch from components.
State Boundaries
Global user/session state comes from web/src/lib/auth.tsx. Campaign navigation
state is published through web/src/lib/campaign-nav.tsx so the chrome can show
campaign tabs in the rail or mobile bottom bar.
Most feature screens keep local state and refetch through API helpers after
mutations. Realtime campaign events use web/src/lib/useCampaignEvents.ts.
Screens
| Screen | Responsibility |
|---|---|
Campaigns.tsx | Campaign list and campaign creation entry points. |
CampaignDetail.tsx | Campaign shell, tab selection, campaign-level data load. |
RulesChat.tsx | Sage chat UI and streamed card rendering. |
CampaignDocuments.tsx | Campaign document upload/index management. |
CampaignCoreSources.tsx | Campaign core-rule opt-ins. |
CampaignCodex.tsx | Story entities, recap review, Codex search/results. |
CampaignNpcs.tsx | NPC roster and relationship editing. |
PlatformSettings.tsx | Admin users, core rules, ingestion settings. |
Upcoming.tsx | Cross-campaign session feed. |
Components
Feature widgets live in web/src/components/: combat tracker, encounter list,
session list/editor, roll call, NPC cards, stat blocks, loot/table/dice cards,
modals, shared form controls, and layout chrome.
Icons must go through web/src/components/Icon.tsx, which maps names to
FontAwesome glyphs.
Styling
The visual system lives in web/src/styles/tome.css, with theme values in
web/src/lib/theme.ts and theme-provider.tsx.
Prefer existing classes and components. Avoid one-off style systems in feature screens. Keep loading, empty, and error states explicit for every fetch.