Technology
Application structure
lib/domain-types.ts (canonical) with transactional order types in lib/types.ts.
Bootstrap
main.tsx wraps the app in three providers:
SessionProvider(better-auth/react) providesuseSession()for auth stateQueryClientProviderprovidesuseQuery()/useMutation()for all API dataToaster(sonner) is the toast mount point
Routing
Routes are defined inApp.tsx and every page component is lazy-loaded:
Route guards
Route-level error boundaries isolate admin and manager segments so one failing screen does not whiteout the whole portal.
Route groups
State management
MUZE does not use Redux, Zustand, or any global client-side store. All state falls into five kinds:- Server state: TanStack React Query (
useQuery/useMutation) for all list, detail, and mutation data - Auth state:
better-auth/reactviauseSession()and theuseAuth()hook - Form state: React Hook Form with Zod schemas
- URL state: React Router’s
useSearchParams()anduseParams() - Local UI state:
useState()inside components (modals, toggles, filters)
ClientProvider + useActiveClient()), and every client-sensitive query embeds it in its query key so a client switch refetches cleanly. See React Query.
API communication
All API calls go through the fetch wrapper insrc/lib/api.ts. The wrapper:
- Prepends
VITE_API_BASE_URL - Includes
credentials: 'include'for session cookies - Parses error bodies into a typed
ApiErrorwith status, message, and optional details - Redirects to
/login?expired=trueon 401 responses, with a session-expired toast
Component patterns
- UI primitives live in
src/components/ui/: shadcn/ui components copied into the repo, not installed as a package - Feature components are co-located under
components/admin/,components/manager/, andcomponents/orders/next to the pages that use them - Shared building blocks live in
src/components/common/:ConfirmDialog,SearchInput,DataTableShell,TableSkeleton,TablePagination,EmptyState,ErrorState,SelectionBar - Class merging uses
cn()fromsrc/lib/utils.ts(clsx + tailwind-merge) - Status rendering goes through the central registry in
src/lib/status.ts(StatusBadge,StatusIndicator)
Build and bundle
Vite produces the production build infrontend/dist/, deployed to Firebase Hosting. All pages are code-split through lazy loading, keeping the initial bundle small.
SEO and metadata
The portal is an authenticated client application, so the indexable surface is limited to the public pages:/login, /forgot-password, and /reset-password. MUZE still keeps those pages discoverable and consistent:
- Per-route document titles.
src/hooks/use-document-title.tssets a unique<title>(and optional meta description and canonical link) per route. Public pages pass a description and canonical; authenticated pages set a title only. - Static metadata.
index.htmlcarries the base title, meta description, Open Graph and Twitter card tags, a canonical link, and Organization/WebSite JSON-LD structured data. The canonical domain is injected at build time fromVITE_APP_URL(%VITE_APP_URL%). - Canonical origin.
src/lib/seo.tsreadsVITE_APP_URLand exposesAPP_URL/absoluteUrl()so pages build absolute links from one source instead of hardcoding the domain. robots.txtandsitemap.xml. Vite copiespublic/verbatim without env substitution, so these are generated at build time byfrontend/scripts/generate-seo-files.cjsintodist/, driven byVITE_APP_URL.robots.txtis permissive and references the sitemap; the sitemap lists only the public pages.
External links
External URLs live in one place for tracking and updating:src/lib/constants.ts (currently USER_GUIDE_URL, pointing at the User Guide Mintlify site). The navbar exposes a Documents button next to the brand on larger screens, with the same item folded into the user menu on small screens, so the documentation is one click away on every viewport.