Skip to content

Monorepo Guide

import { Aside, FileTree } from ‘@astrojs/starlight/components’;

Overview

Status: Current structure is sound — optimization opportunities documented below. Project type: Multi-subdomain platform (7 independent deployable units) Package manager: pnpm (workspace protocol) Build tool: Turborepo


What’s Working Well

  • Scoped package naming@brettjohnson/www, @brettjohnson/lib, etc. — prevents namespace collisions and enables clean cross-package imports
  • Turbo integration — task pipeline with dependency ordering; global cache for faster builds; filter support (--filter=@brettjohnson/www)
  • Shared packagesconfig-eslint, config-tailwind, config-typescript, lib, ui — reduces drift across apps
  • pnpm workspacesworkspace:* protocol correctly used throughout

Folder Structure

- apps/ - www/ brettjohnson.xyz — main marketing site - api/ api.brettjohnson.xyz — status + booking API - docs/ docs.brettjohnson.xyz — this Astro Starlight site - book/ book.brettjohnson.xyz — booking portal (stub) - media/ media.brettjohnson.xyz — press kit (stub) - podcast/ podcast.brettjohnson.xyz — podcast hub (stub) - training/ training.brettjohnson.xyz — LE training (stub) - admin/ admin.brettjohnson.xyz — CMS dashboard (stub) - packages/ - ui/ React component library (Button; Card/Nav/Footer pending M1-T4) - lib/ Business types, Zod schemas, utilities - config-eslint/ Shared ESLint config - config-tailwind/ Shared Tailwind theme tokens - config-typescript/ Shared tsconfig bases - .github/ - workflows/ CI/CD pipelines - docs/ Source markdown docs (mirrored as Astro content) - project/ PM living documents — roadmap, sprint board, audits - turbo.json - pnpm-workspace.yaml - package.json

Shared Packages — What Goes Where

PackagePurposeUsed by
@brettjohnson/uiReact component library (Button, Card, Nav, etc.)www, book, media, podcast, training, admin
@brettjohnson/libTypeScript types, Zod schemas, utilitieswww, api, book, admin
@brettjohnson/config-eslintESLint rulesAll apps
@brettjohnson/config-tailwindTailwind theme + CSS tokensAll frontend apps
@brettjohnson/config-typescriptTypeScript compiler optionsAll apps

What belongs in @brettjohnson/lib

  • TypeScript types used across apps (InquiryFormData, ServiceTier, etc.)
  • Zod validation schemas (add before M4-T1)
  • Supabase client wrapper
  • External API client utilities (HubSpot, Resend)
  • Shared constants (fee ranges, engagement types)

What belongs in @brettjohnson/ui

  • Reusable React components (Button, Card, Nav, Footer, etc.)
  • Shared hooks used across apps
  • Brand design token re-exports

What stays in the app

  • Page-specific components (Hero, Services grid, Testimonials)
  • App-specific business logic
  • Internal admin-only code

Dependency Management

Adding a dependency to a specific app

Terminal window
pnpm add <package> --filter @brettjohnson/www

Adding a shared dev dependency (all packages)

Terminal window
pnpm add -D <package> -w

Using a workspace package

{
"dependencies": {
"@brettjohnson/ui": "workspace:*"
}
}

Turborepo Task Pipeline

The turbo.json task graph ensures correct build ordering:

type-check ──► build
lint ──────────►
test ──────────► (requires ^build)

Running tasks

Terminal window
pnpm dev # All apps in parallel
pnpm dev:www # Main site only (port 3000)
pnpm dev:api # API only (port 3001)
pnpm build # Full production build (all apps)
pnpm lint # ESLint across all apps
pnpm type-check # tsc --noEmit across all apps
pnpm test # Jest across all apps

Selective builds (faster in CI)

Terminal window
# Build only changed packages + their dependents
turbo build --filter=...[HEAD^1]
# Build a specific app and its dependencies
turbo build --filter=@brettjohnson/www...

Remote caching

Set TURBO_TOKEN and TURBO_TEAM in Vercel/GitHub Actions to enable shared remote cache across CI runs.


Adding a New App

  1. Create the directory under apps/:

    Terminal window
    cp -r apps/book apps/newapp
    # Update package.json name + port
  2. Add a dev:newapp script to root package.json

  3. Add a project entry to apps/api/lib/milestones.ts status tracker

  4. Create a vercel.json in the new app pointing to its dist or .next directory

  5. Add the subdomain to apps/docs/src/content/docs/architecture/infrastructure.md


Versioning Strategy

All apps release together — unified versioning (v1.0.0-mvp bumps every package simultaneously). semantic-release runs on merge to main and determines the next version from Conventional Commits.

See Versioning Policy for details.