Skip to content

🔄 Synced from castyou-frontend/docs/ARCHITECTURE.md — edit it there, not here.

CastYou Frontend — Architecture

Overview

The CastYou frontend is a pnpm monorepo managed with Turborepo. It contains two apps and a shared design system package.

castyou-frontend/
├── apps/
│   ├── landing/      # Next.js 15 (App Router) — public marketing site
│   └── app/          # React 18 + Vite — authenticated product app
└── packages/
    ├── design-system/ # Tailwind + Radix UI component library
    └── tsconfig/      # Shared TypeScript configurations

Apps

@castyou/landing — Next.js 15 (App Router)

The public-facing marketing site at castyou.app (and www.castyou.app). Responsibilities:

  • SEO-optimised landing pages (SSR/SSG)
  • Sign-up funnels directing users to i.castyou.app
  • Blog, pricing, about pages
  • Social sharing and OG metadata

Port: 3002

@castyou/app — React 18 + Vite + React Query

The authenticated product application at i.castyou.app. Responsibilities:

  • Talent / producer dashboards
  • Discover feed (AI-powered talent cards with swipe UX)
  • Job posting and management
  • Profile editor
  • Demo reel builder
  • Group management

Port: 3001


Packages

@castyou/design-system

The single source of truth for all UI. Both apps import from here — no local component duplication.

Contents:

  • Tokens (src/tokens/) — colors, spacing, typography, radius as TypeScript constants + Tailwind config extension
  • Components (src/components/ui/) — Button, Input, Badge, Card, Avatar, and more
  • Utilities (src/utils/cn.ts) — cn() helper merging clsx + tailwind-merge
  • Tailwind config (tailwind.config.ts) — extends base config; consumer apps spread this and add their own content paths

Consumers use it via workspace protocol:

json
"@castyou/design-system": "workspace:*"

@castyou/tsconfig

Shared TypeScript base config (base.json) extended by all apps and packages to ensure consistent compiler settings.


Tech Stack

ConcernChoiceReason
Monorepo toolingpnpm workspaces + TurborepoFast installs, parallel task pipelines, build caching
LandingNext.js 15 App RouterSSR/SSG for SEO; React Server Components
AppReact 18 + ViteFast HMR, SPA suited for rich interactive dashboard
Data fetchingTanStack Query v5Server-state management, caching, background refetch
GraphQL clientgraphql-requestLightweight; pairs naturally with React Query
State (client)ZustandMinimal global state (auth, UI preferences)
Routing (app)React Router v6Client-side routing with lazy-loaded routes
StylingTailwind CSS v3Utility-first; shared via design-system package
ComponentsRadix UI primitivesAccessible headless components wrapped by design-system
Form variantsclass-variance-authorityType-safe variant API for design-system components

Data Flow (App)

User interaction
  → React component (page or feature component)
  → useQuery / useMutation (TanStack Query)
  → gqlClient.request() (graphql-request)
  → CastYou Backend GraphQL API
  → Response cached in QueryClient
  → Component re-renders with fresh data

Global state (auth tokens, user session) lives in Zustand (src/stores/auth.ts). Server state lives in React Query cache — never duplicated in Zustand.


Authentication Flow (App)

  1. User submits login form → Mutation.login resolves on backend
  2. accessToken stored in localStorage (key: castyou_access_token); user object persisted in Zustand
  3. gqlClient reads the token from localStorage on every request via a dynamic headers function
  4. ProtectedRoute in App.tsx redirects unauthenticated users to /login
  5. On token expiry, the 401 response triggers a token refresh or redirects to login

Adding a New Page (App)

  1. Create src/pages/<domain>/<PageName>.tsx
  2. Add a lazy import and <Route> in src/App.tsx
  3. Add any GraphQL queries/mutations to src/lib/queries/<domain>.ts
  4. Wrap data fetching in a custom hook src/hooks/use<Domain>.ts

Adding a New Design System Component

  1. Create packages/design-system/src/components/ui/<Component>.tsx
  2. Export it from packages/design-system/src/index.ts
  3. Both apps get it immediately via the workspace symlink

Build Pipeline (Turborepo)

turbo build
  → @castyou/tsconfig  (no-op, config only)
  → @castyou/design-system (tsc typecheck)
  → @castyou/landing (next build)  ─┐  parallel
  → @castyou/app (vite build)      ─┘

turbo.json declares "dependsOn": ["^build"] so packages always build before the apps that consume them.