File-Based Routing (TanStack Router)
Both apps use TanStack Router’s file-based routing. The router tree is auto-generated by the Vite plugin — you only create/delete/rename files in src/routes/.
Never manually edit src/routeTree.gen.ts. It’s auto-generated on every save. Editing it will be overwritten immediately.
Route File Naming Conventions
Creating a New Route
Route with Dynamic Parameter
Accessing Router Context
Server State (TanStack Query)
All data fetched from the backend lives in TanStack Query. Never store API data in Zustand — that’s for local UI state only.
Standard Query Hook Pattern
Standard Mutation Pattern
Polling for Live Data
Used for scan status updates:
Query Keys Convention
Use arrays to namespace query keys by feature:
Client State (Zustand)
Use Zustand for UI state that doesn’t come from the server: modal open/closed, selected tab, pending selections.
Store Pattern
Rule of Thumb: Zustand vs Query
All forms use react-hook-form with Zod validation via @hookform/resolvers.
Reusable Validation Schemas
Common schemas are in packages/common/src/utils/validations.ts. Import from there:
API Service Pattern
API calls live in src/model/ (service files). They are plain async functions, not hooks — hooks live in src/store/server/.
Authentication
Auth token is read from the access_token cookie on every request:
Styling (Tailwind CSS)
Tailwind Prefix
All utilities use the wy- prefix to avoid conflicts with third-party styles:
Conditional Classes
Use clsx and tailwind-merge together:
Theme Colours
Defined in each app’s tailwind.config.js:
Dark mode uses CSS variables (HSL-based), toggled via a dark class on <html>.
Component Development Rules
- Shared = goes in
packages/common — never duplicate across apps
- App-specific = stays in
apps/<name>/src/components/
- Use Radix UI via
packages/common/src/components/shadcn/ — never install Radix directly in an app
- No inline styles — Tailwind classes only
- All icons from
packages/common/src/components/icons/ — add new icons there if missing
- Forms always use Zod resolver — no manual validation logic