# 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/Zod) 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](https://www.solidjs.com/) app with CRUD UI for persons and pets - `backend`: a [Fastify](https://fastify.dev/) 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 - [TypeScript](https://www.typescriptlang.org/) for static type checking - [Biome](https://biomejs.dev/) for code formatting and linting - [Kysely](https://kysely.dev/) for type-safe SQL queries - [Vitest](https://vitest.dev/) for testing ## Development Workflow ### Initial Setup 1. **Copy environment files:** ```sh cp .env.example .env cp apps/frontend/.env.example apps/frontend/.env cp apps/backend/.env.example apps/backend/.env ``` 2. **Start local dependencies (PostgreSQL):** ```sh docker compose up -d ``` - PGAdmin: http://localhost:5050 3. **Install dependencies:** ```sh pnpm install ``` ### Running Development Servers The recommended way to develop is using Turborepo's watch mode: ```sh pnpm run dev:watch ``` Or with global Turbo: ```sh 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): - Backend: Runs on http://localhost:3000 with nodemon for auto-restart - Frontend: Runs on http://localhost:5173 with Vite HMR 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: ```sh turbo dev ``` Develop a specific package: ```sh turbo dev --filter=backend turbo dev --filter=frontend ``` ### Build Build all apps and packages: ```sh turbo build ``` Build a specific package: ```sh turbo build --filter=backend ``` ### Testing Run all tests: ```sh turbo test ``` Run tests in watch mode: ```sh 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 ``` ## Useful Links Learn more about the power of Turborepo: - [Tasks](https://turborepo.com/docs/crafting-your-repository/running-tasks) - [Caching](https://turborepo.com/docs/crafting-your-repository/caching) - [Remote Caching](https://turborepo.com/docs/core-concepts/remote-caching) - [Filtering](https://turborepo.com/docs/crafting-your-repository/running-tasks#using-filters) - [Configuration Options](https://turborepo.com/docs/reference/configuration) - [CLI Usage](https://turborepo.com/docs/reference/command-line-reference)