# Turborepo Monorepo Best Practices — MeshiTrack

> Instruction file for managing the monorepo workspace.

## Workspace Structure

```
MeshiTrack/
├── packages/
│   ├── api/          # NestJS backend       → @meshitrack/api
│   ├── web/          # Next.js frontend     → @meshitrack/web
│   └── shared/       # Shared types & DTOs  → @meshitrack/shared
├── docker/           # Docker configs (not a package)
├── docs/             # Documentation (not a package)
├── turbo.json        # Turborepo pipeline config
├── package.json      # Root workspace config
├── tsconfig.base.json
├── .eslintrc.js
├── .prettierrc
└── .gitignore
```

## Root package.json

```json
{
  "name": "meshitrack",
  "private": true,
  "workspaces": ["packages/*"],
  "scripts": {
    "dev": "turbo run dev",
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test",
    "typecheck": "turbo run typecheck",
    "clean": "turbo run clean"
  },
  "devDependencies": {
    "turbo": "^2.x",
    "typescript": "^5.x",
    "eslint": "^9.x",
    "prettier": "^3.x"
  }
}
```

## turbo.json Configuration

```json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
    },
    "dev": {
      "dependsOn": ["^build"],
      "cache": false,
      "persistent": true
    },
    "lint": {
      "dependsOn": ["^build"]
    },
    "test": {
      "dependsOn": ["^build"]
    },
    "typecheck": {
      "dependsOn": ["^build"]
    },
    "clean": {
      "cache": false
    }
  }
}
```

### Key concepts

- **`dependsOn: ["^build"]`**: Before running a task in a package, first build all its dependencies. This ensures `shared` is built before `api` or `web` run.
- **`outputs`**: What Turborepo caches. If outputs haven't changed, Turborepo replays from cache.
- **`persistent: true`**: For long-running dev servers that shouldn't be cached.
- **`cache: false`**: Disables caching for tasks that should always run.

## Package Dependencies

### Shared package is the foundation

```
@meshitrack/shared  ←  @meshitrack/api
                    ←  @meshitrack/web
```

Both `api` and `web` depend on `shared`, but never on each other.

### Reference shared in package.json

```json
// packages/api/package.json
{
  "name": "@meshitrack/api",
  "dependencies": {
    "@meshitrack/shared": "workspace:*"
  }
}

// packages/web/package.json
{
  "name": "@meshitrack/web",
  "dependencies": {
    "@meshitrack/shared": "workspace:*"
  }
}
```

### Import from shared

```typescript
// In packages/api or packages/web
import { Product, NutritionInfo, ProductCategory } from '@meshitrack/shared';
import { CreateProductSchema } from '@meshitrack/shared/validation';
```

## Shared Package Setup

### packages/shared/package.json

```json
{
  "name": "@meshitrack/shared",
  "version": "0.0.1",
  "private": true,
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    },
    "./validation": {
      "types": "./dist/validation/index.d.ts",
      "default": "./dist/validation/index.js"
    }
  },
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch",
    "clean": "rm -rf dist",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "zod": "^3.x"
  },
  "devDependencies": {
    "typescript": "^5.x"
  }
}
```

### packages/shared/tsconfig.json

```json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"]
}
```

### Shared package must be platform-agnostic

Rules for code in `packages/shared`:

- **No** Node.js imports (`fs`, `path`, `http`, etc.)
- **No** NestJS decorators or imports
- **No** Next.js imports
- **No** DOM/browser APIs
- Only pure TypeScript: types, interfaces, enums, Zod schemas, utility functions

## TypeScript Configuration

### Root tsconfig.base.json

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022"],
    "module": "commonjs",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "incremental": true
  },
  "exclude": ["node_modules", "dist"]
}
```

Each package extends this and overrides as needed (e.g., `web` uses `"jsx": "preserve"`, `"module": "esnext"`).

## Development Workflow

### Start all packages in dev mode

```bash
npm run dev
# Turborepo runs: shared (build) → then api (dev) + web (dev) in parallel
```

### Build all packages

```bash
npm run build
# Turborepo builds shared first, then api and web in parallel
```

### Run tasks for a specific package

```bash
npx turbo run dev --filter=@meshitrack/api
npx turbo run test --filter=@meshitrack/web
```

### Add a dependency to a specific package

```bash
cd packages/api
npm install @nestjs/schedule
# Or from root:
npm install @nestjs/schedule --workspace=packages/api
```

## Caching

### Turborepo remote caching (optional)

For CI, consider enabling remote caching to share build cache across machines:

```bash
npx turbo login
npx turbo link
```

Or use a self-hosted cache server for full self-hosted setup.

### Local caching

Turborepo caches locally in `node_modules/.cache/turbo` by default. It's fast and requires no setup.

## CI Integration

```yaml
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
      - run: npm ci
      - run: npx turbo run build lint test typecheck
```

## Common Pitfalls

1. **Forgetting to build shared**: If `api` or `web` can't find types from `shared`, run `npm run build` from root. The `dependsOn: ["^build"]` config handles this in Turborepo tasks.

2. **Circular dependencies**: Never import from `api` in `web` or vice versa. Only import from `shared`.

3. **Version mismatches**: Keep TypeScript versions aligned across all packages. Pin in root `devDependencies`.

4. **Large `node_modules`**: Use `npm` workspaces hoisting. Most dependencies are installed at root level. Only package-specific versions go in package-level `node_modules`.
