Ollis Turborepo Test

A full-stack TypeScript monorepo demonstrating modern development practices with automatic API client generation and type-safe end-to-end data flow.

Architecture Overview

This monorepo showcases a type-safe, auto-generated API contract between backend and frontend:

Backend (Fastify) → OpenAPI Spec → Generated API Client → Frontend (SolidJS)

Key Design Decisions

  1. Schema-First API Design: Backend schemas (TypeBox/JSONSchema) are the single source of truth. The OpenAPI specification is automatically generated from these schemas and actual route definitions using Fastify's @fastify/swagger, ensuring the API contract always reflects the actual backend implementation.

  2. Automatic Client Generation: The api-client-backend package uses @hey-api/openapi-ts to generate a fully typed API client from the OpenAPI spec, ensuring type safety across the stack.

  3. Turborepo Watch Mode: Development workflow uses Turborepo's watch feature to orchestrate the entire pipeline automatically - when you change an API schema, the OpenAPI spec is regenerated, the client is regenerated, and the frontend picks up changes via HMR.

  4. Bare Metal Development: Apps and packages run directly on the host machine (not containerized) for faster iteration, better debugging, and native tool integration. Only external dependencies like PostgreSQL run in Docker containers via docker-compose.

What's inside?

This Turborepo includes the following packages/apps:

Apps

  • frontend: a SolidJS app with CRUD UI for persons and pets
  • backend: a Fastify REST API with PostgreSQL and Kysely ORM

Packages

  • @olli/api-client-backend: Auto-generated TypeScript API client based on backend's OpenAPI spec
  • @olli/ts-config: Shared TypeScript configurations

Utilities

Development Workflow

Initial Setup

  1. Copy environment files:
cp .env.example .env
cp apps/frontend/.env.example apps/frontend/.env
cp apps/backend/.env.example apps/backend/.env
  1. Start local dependencies (PostgreSQL):
docker compose up -d
  1. Install dependencies:
pnpm install

Running Development Servers

The recommended way to develop is using Turborepo's watch mode:

pnpm run dev:watch

Or with global Turbo:

turbo watch dev:watch export-openapi generate

turbo watch only works for non-persistent tasks. So dev tasks are not affected, therefore we need to run the dev:watch task here, so the apps actually watch changes by themselves.

What dev:watch Does

This single command orchestrates the entire development workflow:

  1. Starts Development Servers (dev:watch task):

  2. Watches for API Changes (export-openapi task):

    • Monitors backend source files (src/**/*.ts)
    • When API schemas change, automatically exports updated OpenAPI spec to packages/api-client-backend/openapi.json
  3. Regenerates API Client (generate task):

    • Watches the OpenAPI spec file
    • When spec changes, regenerates TypeScript client in packages/api-client-backend/generated/
    • Thanks to PNPM workspace linking, frontend immediately sees the updated types
  4. Updates Frontend (automatic via Vite HMR):

    • Vite detects changes in workspace dependencies
    • Frontend auto-refreshes with new API types and methods

The Flow:

Backend code change
  ↓
Nodemon restarts backend server
  ↓
Turbo watch detects file change
  ↓
export-openapi script runs → generates openapi.json
  ↓
Turbo runs generate task → regenerates API client
  ↓
Vite HMR detects api-client-backend change
  ↓
Frontend reloads with updated types ✨

This workflow ensures zero manual steps - just change your API schema and watch it propagate through the entire stack!

Alternative Development Commands

Develop all apps and packages:

turbo dev

Develop a specific package:

turbo dev --filter=backend
turbo dev --filter=frontend

Build

Build all apps and packages:

turbo build

Build a specific package:

turbo build --filter=backend

Testing

Run all tests:

turbo test

Run tests in watch mode:

turbo test:watch

Project Structure

apps/
  backend/               # Fastify API server
    src/
      features/         # Feature-based organization
        demo/
          *.routes.ts   # API route handlers
          *.schema.ts   # Zod/TypeBox schemas
          *.repository.ts
      db/               # Database setup and migrations
    scripts/
      export-openapi.ts # OpenAPI spec generator
  frontend/            # SolidJS web app
    src/
      person-crud.tsx  # Person management UI
      pet-crud.tsx     # Pet management UI
      api.ts           # Configured API client
packages/
  api-client-backend/  # Generated API client
    generated/         # Auto-generated (don't edit!)
    openapi.json       # Source of truth from backend

Learn more about the power of Turborepo:

Description
No description provided
Readme 329 KiB
Languages
TypeScript 97.4%
Dockerfile 2%
HTML 0.6%