Structure
Routes, feature modules, and the shared UI kit.
Routes (src/app)
/auth (sign-in, sign-up, forgot-password) · /api/auth/[...all] (Better Auth proxy) · /api/health · /dashboard/* (the guarded shell) · /privacy, /terms. Access Denied is a component that ProtectedRoute renders, not a route.
Dashboard sections: overview, users (+new, routine-steps), orders (+checkout-sessions), products (+groups), content-management (carousel, campaigns, avatars), loyalty (campaigns, users, voucher-templates, audit), vouchers (templates, issued, issue, pools, audit), raya-campaign, ratings (pending, flagged, blocked, reports), notifications, webhooks, support, audit-log, profile.
Feature modules (src/features)
15 modules. The documented convention: components/{feature}-columns|filters|form|table|listing.tsx, hooks/use-{feature}.ts, utils/ with Zod schemas + types. No feature has a stores/ folder. Reality: large modules nest by domain (loyalty/components/{audit,campaigns,shake-to-win,…} with forms/sections/), and vouchers is organized per view (issue/, issued/, pools/, …). Tests live next to sources.
Shared UI (src/components/ui)
About 55 shadcn components plus domain composites: confirmation-dialog, empty-state, date-picker/date-time-picker/calendar-date-range-picker, channel-multi-select, tiptap-editor (DOMPurify-sanitized), and the data-table stack in ui/table/ (data table, column header, pagination, faceted filter, view options, skeleton). Media pieces live in src/components/media/: r2-image, image-upload-field and video-upload-field.
Layout pieces in src/components/layout/: dashboard-shell.tsx, app-sidebar.tsx (role-filtered nav), header.tsx, ConvexClientProvider.tsx. The sidebar is grouped into labeled sections (Overview, Commerce, Customers, Content & Engagement, Platform) — every navItems entry in src/constants/data.ts declares a group field matching navGroupLabels, and empty groups are hidden. Parent rows link to their landing page and toggle their sub-menu; items with external: true (footerNavItems: Documentation, Operations Manual) open in a new tab. The kbar command palette (src/components/kbar/) builds its actions from navItems + footerNavItems — add new pages there or they won't be reachable via ⌘K or the sidebar.