Appearance
Tier System
All features live in their access tier, not by component type. This enables code splitting (admin code never ships to a logged-out visitor), security isolation, and predictable structure.
src/tiers/
landing/ ← Marketing / landing pages (eager-loaded)
user/ ← Authenticated dashboard features — LARGEST TIER
admin/ ← Admin-only (role admin / super_admin)
public/ ← Unauthenticated public renderers (/b /s /w)Features by tier (current)
| Tier | Features |
|---|---|
| user | biolink, business-card, dashboard, digital-menu, engagements, onboarding, profile, qr-generator, reminders, settings, website-builder |
| public | digital-menu, feedback-forms |
| admin | (tier scaffolded; features being built) |
| landing | pages/ only (no feature dirs) |
A feature with both a dashboard and a public display owns both halves in parallel dirs (e.g. tiers/user/features/digital-menu + tiers/public/features/digital-menu); shared data-model types go in the shared core.
Feature directory structure
Every feature is tiers/{tier}/features/{name}/:
pages/ ← Route-level page components
components/ ← Feature-specific UI
hooks/ ← Feature data hooks (supabase.rpc reads live here)
services/ ← EF call wrappers (supabase.functions.invoke lives here)
utils/ ← Pure computation
tests/ ← Co-located Vitest suites
types/ ← (TS-first) domain types
schemas/ ← (TS-first) Zod schemas
constants/ ← (TS-first) incl. the EDGE_FN map
digital-menuis the reference feature — model new features on it.
Routing
Top-level routing in src/routes/index.jsx:
| Route | Loading | Guard |
|---|---|---|
/, /login, /signup, /admin/login | eager | — |
/b/:slug, /s/:slug, /w/:slug | lazy | public |
/onboarding | lazy | ProtectedRoute |
/dashboard/* | eager shell, lazy features | ProtectedRoute → user tier |
/admin/* | lazy | AdminRoute (admin / super_admin) |
Public feature routes are mounted from tiers/public/features/{feature}/routes/index.jsx — follow this pattern for new public routes.
Cross-tier import rules [ENFORCED]
public/⇏user/,admin/user/⇏admin/- All tiers may import global
src/components,src/lib. - Features import UI from their tier's
components/ui/, not the global directly.
Auth & route guards (current)
src/contexts/SupabaseAuthContext.jsx—useAuth/useSupabaseAuth:user,session,loading,userRole,roleLoading,signIn/Up/Out. Role fromprofiles.role(fallback metadata, default'user').src/components/ProtectedRoute.jsx— gates/dashboard/*; admins bypass the onboarding redirect.src/components/AdminRoute.jsx— gates/admin/*.
Two "shared" locations [TRANSITIONAL]
src/shared/ (intended-canonical) vs legacy top-level src/{components,contexts,hooks,lib,pages,stores}/ (still live — SupabaseAuthContext.jsx, ProtectedRoute.jsx, AdminRoute.jsx are here). Prefer src/shared/; reconcile the two .../components/ui folders into the UI Hybrid System during retrofit.