192 lines
5.8 KiB
Markdown
192 lines
5.8 KiB
Markdown
# 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)
|