From d0d335d82922d0c19fbae2e6bc716bf189db19eb Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Mon, 6 Apr 2026 13:56:00 +0200 Subject: [PATCH] Add Plan 1: Monorepo Foundation implementation plan 8 tasks covering: root workspace files, shared TypeScript config, shared ESLint config, placeholder packages, placeholder apps, Docker Compose, dependency installation + verification, test dirs. --- .../2026-04-06-plan-1-monorepo-foundation.md | 965 ++++++++++++++++++ 1 file changed, 965 insertions(+) create mode 100644 docs/superpowers/plans/2026-04-06-plan-1-monorepo-foundation.md diff --git a/docs/superpowers/plans/2026-04-06-plan-1-monorepo-foundation.md b/docs/superpowers/plans/2026-04-06-plan-1-monorepo-foundation.md new file mode 100644 index 0000000..0b2ce84 --- /dev/null +++ b/docs/superpowers/plans/2026-04-06-plan-1-monorepo-foundation.md @@ -0,0 +1,965 @@ +# Plan 1: Monorepo Foundation — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Scaffold a Turborepo + pnpm monorepo with shared TypeScript and ESLint configs, placeholder packages for all planned workspaces, and Docker Compose for local development. + +**Architecture:** Turborepo orchestrates builds across pnpm workspaces. Shared config packages (`@repo/typescript-config`, `@repo/eslint-config`) provide consistent tooling. All apps and packages are created as empty placeholders with correct `package.json` files so the workspace graph is valid from the start. Docker Compose provides PostgreSQL for local development. + +**Tech Stack:** Turborepo 2.x, pnpm 9.x, TypeScript 5.x, ESLint 9.x (flat config), Vitest, Docker Compose, PostgreSQL 16 + +--- + +## File Map + +| File | Responsibility | +|---|---| +| `package.json` | Root workspace manifest, delegates to turbo | +| `pnpm-workspace.yaml` | Declares workspace packages | +| `turbo.json` | Task pipeline (build, dev, lint, test, typecheck) | +| `.npmrc` | pnpm workspace settings | +| `.gitignore` | Ignore patterns for Turborepo + pnpm + Node.js | +| `packages/typescript-config/package.json` | Shared TS config package manifest | +| `packages/typescript-config/base.json` | Base TypeScript config | +| `packages/typescript-config/nextjs.json` | Next.js TypeScript config | +| `packages/typescript-config/react-library.json` | React library TypeScript config | +| `packages/eslint-config/package.json` | Shared ESLint config package manifest | +| `packages/eslint-config/base.js` | Base ESLint flat config | +| `packages/eslint-config/next.js` | Next.js ESLint config | +| `packages/eslint-config/react-internal.js` | React library ESLint config | +| `packages/core/package.json` | Placeholder — clean architecture core | +| `packages/core/tsconfig.json` | Extends @repo/typescript-config/base | +| `packages/api/package.json` | Placeholder — tRPC routers | +| `packages/api/tsconfig.json` | Extends @repo/typescript-config/base | +| `packages/api-client/package.json` | Placeholder — React Query hooks | +| `packages/api-client/tsconfig.json` | Extends @repo/typescript-config/react-library | +| `packages/cms-core/package.json` | Placeholder — Payload CMS definition | +| `packages/cms-core/tsconfig.json` | Extends @repo/typescript-config/base | +| `packages/cms-client/package.json` | Placeholder — Dual-mode Payload client | +| `packages/cms-client/tsconfig.json` | Extends @repo/typescript-config/base | +| `packages/ui/package.json` | Placeholder — shadcn/ui + Atomic Design | +| `packages/ui/tsconfig.json` | Extends @repo/typescript-config/react-library | +| `apps/web-next/package.json` | Placeholder — Next.js reference app | +| `apps/web-next/tsconfig.json` | Extends @repo/typescript-config/nextjs | +| `apps/web-tanstack/package.json` | Placeholder — TanStack Start reference app | +| `apps/web-tanstack/tsconfig.json` | Extends @repo/typescript-config/base | +| `apps/cms/package.json` | Placeholder — Payload admin shell | +| `apps/cms/tsconfig.json` | Extends @repo/typescript-config/nextjs | +| `apps/storybook/package.json` | Placeholder — Storybook instance | +| `apps/storybook/tsconfig.json` | Extends @repo/typescript-config/react-library | +| `docker-compose.yml` | PostgreSQL service for local dev | +| `.env.example` | Environment variable template | + +--- + +### Task 1: Root workspace files + +**Files:** +- Create: `package.json` +- Create: `pnpm-workspace.yaml` +- Create: `turbo.json` +- Create: `.npmrc` +- Create: `.gitignore` +- Create: `.env.example` + +- [ ] **Step 1: Create root package.json** + +```json +{ + "name": "template", + "private": true, + "packageManager": "pnpm@9.15.4", + "engines": { + "node": ">=20" + }, + "scripts": { + "build": "turbo run build", + "dev": "turbo run dev", + "lint": "turbo run lint", + "test": "turbo run test", + "typecheck": "turbo run typecheck", + "format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"", + "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md}\"" + }, + "devDependencies": { + "prettier": "^3.5.0", + "turbo": "^2.4.0", + "typescript": "^5.8.0" + } +} +``` + +- [ ] **Step 2: Create pnpm-workspace.yaml** + +```yaml +packages: + - "apps/*" + - "packages/*" +``` + +- [ ] **Step 3: Create turbo.json** + +```json +{ + "$schema": "https://turborepo.dev/schema.json", + "tasks": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist/**", ".next/**", "!.next/cache/**"] + }, + "dev": { + "cache": false, + "persistent": true + }, + "lint": { + "dependsOn": ["^lint"] + }, + "test": { + "dependsOn": ["^build"] + }, + "typecheck": { + "dependsOn": ["^typecheck"] + } + } +} +``` + +- [ ] **Step 4: Create .npmrc** + +``` +auto-install-peers=true +enable-pre-post-scripts=true +``` + +- [ ] **Step 5: Create .gitignore** + +``` +# Dependencies +node_modules + +# Turbo +.turbo + +# Build outputs +dist +build +.next +out +storybook-static + +# Environment +.env +.env.local +.env.*.local + +# Testing +coverage + +# OS +.DS_Store +Thumbs.db + +# IDE +.vscode +.idea +*.swp + +# Debug +npm-debug.log* +pnpm-debug.log* + +# Superpowers brainstorm sessions +.superpowers/ +``` + +- [ ] **Step 6: Create .env.example** + +``` +# Database +DATABASE_URL=postgresql://postgres:postgres@localhost:5432/template + +# Payload CMS +PAYLOAD_SECRET=your-secret-here + +# App URLs +NEXT_PUBLIC_APP_URL=http://localhost:3000 +CMS_URL=http://localhost:3001 +``` + +- [ ] **Step 7: Commit** + +```bash +git add package.json pnpm-workspace.yaml turbo.json .npmrc .gitignore .env.example +git commit -m "feat: scaffold root workspace files (Turborepo + pnpm)" +``` + +--- + +### Task 2: Shared TypeScript config package + +**Files:** +- Create: `packages/typescript-config/package.json` +- Create: `packages/typescript-config/base.json` +- Create: `packages/typescript-config/nextjs.json` +- Create: `packages/typescript-config/react-library.json` + +- [ ] **Step 1: Create package.json** + +```json +{ + "name": "@repo/typescript-config", + "private": true, + "version": "0.0.0" +} +``` + +- [ ] **Step 2: Create base.json** + +This is the base TypeScript config used by all packages. Includes `experimentalDecorators` and `emitDecoratorMetadata` required by InversifyJS. + +```json +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022"], + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "declaration": true, + "declarationMap": true, + "isolatedModules": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "noUncheckedIndexedAccess": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true + }, + "exclude": ["node_modules", "dist"] +} +``` + +- [ ] **Step 3: Create nextjs.json** + +```json +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./base.json", + "compilerOptions": { + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "jsx": "preserve", + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "incremental": true, + "plugins": [{ "name": "next" }] + } +} +``` + +- [ ] **Step 4: Create react-library.json** + +```json +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./base.json", + "compilerOptions": { + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "jsx": "react-jsx" + } +} +``` + +- [ ] **Step 5: Commit** + +```bash +git add packages/typescript-config/ +git commit -m "feat: add shared TypeScript config package (@repo/typescript-config)" +``` + +--- + +### Task 3: Shared ESLint config package + +**Files:** +- Create: `packages/eslint-config/package.json` +- Create: `packages/eslint-config/base.js` +- Create: `packages/eslint-config/next.js` +- Create: `packages/eslint-config/react-internal.js` + +- [ ] **Step 1: Create package.json** + +```json +{ + "name": "@repo/eslint-config", + "private": true, + "version": "0.0.0", + "type": "module", + "exports": { + "./base": "./base.js", + "./next": "./next.js", + "./react-internal": "./react-internal.js" + }, + "devDependencies": { + "@eslint/js": "^9.20.0", + "@typescript-eslint/eslint-plugin": "^8.25.0", + "@typescript-eslint/parser": "^8.25.0", + "eslint": "^9.20.0", + "eslint-config-prettier": "^10.1.0", + "eslint-plugin-turbo": "^2.4.0", + "typescript-eslint": "^8.25.0" + } +} +``` + +- [ ] **Step 2: Create base.js** + +```javascript +import js from "@eslint/js"; +import eslintConfigPrettier from "eslint-config-prettier"; +import tseslint from "typescript-eslint"; +import turboPlugin from "eslint-plugin-turbo"; + +export default [ + { ignores: ["dist/**", "node_modules/**"] }, + js.configs.recommended, + ...tseslint.configs.recommended, + eslintConfigPrettier, + { + plugins: { turbo: turboPlugin }, + rules: { + "turbo/no-undeclared-env-vars": "warn", + }, + }, +]; +``` + +- [ ] **Step 3: Create next.js** + +```javascript +import baseConfig from "./base.js"; + +export default [ + ...baseConfig, + { ignores: [".next/**", "out/**"] }, +]; +``` + +- [ ] **Step 4: Create react-internal.js** + +```javascript +import baseConfig from "./base.js"; + +export default [...baseConfig]; +``` + +- [ ] **Step 5: Commit** + +```bash +git add packages/eslint-config/ +git commit -m "feat: add shared ESLint config package (@repo/eslint-config)" +``` + +--- + +### Task 4: Placeholder packages (core, api, api-client, cms-core, cms-client, ui) + +**Files:** +- Create: `packages/core/package.json` +- Create: `packages/core/tsconfig.json` +- Create: `packages/core/src/index.ts` +- Create: `packages/api/package.json` +- Create: `packages/api/tsconfig.json` +- Create: `packages/api/src/index.ts` +- Create: `packages/api-client/package.json` +- Create: `packages/api-client/tsconfig.json` +- Create: `packages/api-client/src/index.ts` +- Create: `packages/cms-core/package.json` +- Create: `packages/cms-core/tsconfig.json` +- Create: `packages/cms-core/src/index.ts` +- Create: `packages/cms-client/package.json` +- Create: `packages/cms-client/tsconfig.json` +- Create: `packages/cms-client/src/index.ts` +- Create: `packages/ui/package.json` +- Create: `packages/ui/tsconfig.json` +- Create: `packages/ui/src/index.ts` + +- [ ] **Step 1: Create packages/core/package.json** + +```json +{ + "name": "@repo/core", + "private": true, + "version": "0.0.0", + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "scripts": { + "build": "tsc --noEmit", + "lint": "eslint .", + "test": "vitest run", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*" + } +} +``` + +- [ ] **Step 2: Create packages/core/tsconfig.json** + +```json +{ + "extends": "@repo/typescript-config/base.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + "types": ["reflect-metadata"] + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} +``` + +- [ ] **Step 3: Create packages/core/src/index.ts** + +```typescript +// @repo/core — Clean Architecture core package +// Layers: entities, application, infrastructure, interface-adapters, di +export {}; +``` + +- [ ] **Step 4: Create packages/api/package.json** + +```json +{ + "name": "@repo/api", + "private": true, + "version": "0.0.0", + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "scripts": { + "build": "tsc --noEmit", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*" + } +} +``` + +- [ ] **Step 5: Create packages/api/tsconfig.json** + +```json +{ + "extends": "@repo/typescript-config/base.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} +``` + +- [ ] **Step 6: Create packages/api/src/index.ts** + +```typescript +// @repo/api — tRPC router definitions +export {}; +``` + +- [ ] **Step 7: Create packages/api-client/package.json** + +```json +{ + "name": "@repo/api-client", + "private": true, + "version": "0.0.0", + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "scripts": { + "build": "tsc --noEmit", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*" + } +} +``` + +- [ ] **Step 8: Create packages/api-client/tsconfig.json** + +```json +{ + "extends": "@repo/typescript-config/react-library.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "dist"] +} +``` + +- [ ] **Step 9: Create packages/api-client/src/index.ts** + +```typescript +// @repo/api-client — Shared React Query hooks +export {}; +``` + +- [ ] **Step 10: Create packages/cms-core/package.json** + +```json +{ + "name": "@repo/cms-core", + "private": true, + "version": "0.0.0", + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "scripts": { + "build": "tsc --noEmit", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*" + } +} +``` + +- [ ] **Step 11: Create packages/cms-core/tsconfig.json** + +```json +{ + "extends": "@repo/typescript-config/base.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} +``` + +- [ ] **Step 12: Create packages/cms-core/src/index.ts** + +```typescript +// @repo/cms-core — Payload CMS config, collections, hooks, globals +export {}; +``` + +- [ ] **Step 13: Create packages/cms-client/package.json** + +```json +{ + "name": "@repo/cms-client", + "private": true, + "version": "0.0.0", + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "scripts": { + "build": "tsc --noEmit", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*" + } +} +``` + +- [ ] **Step 14: Create packages/cms-client/tsconfig.json** + +```json +{ + "extends": "@repo/typescript-config/base.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} +``` + +- [ ] **Step 15: Create packages/cms-client/src/index.ts** + +```typescript +// @repo/cms-client — Dual-mode Payload client (local + HTTP) +export {}; +``` + +- [ ] **Step 16: Create packages/ui/package.json** + +```json +{ + "name": "@repo/ui", + "private": true, + "version": "0.0.0", + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "scripts": { + "build": "tsc --noEmit", + "lint": "eslint .", + "test": "vitest run", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*" + } +} +``` + +- [ ] **Step 17: Create packages/ui/tsconfig.json** + +```json +{ + "extends": "@repo/typescript-config/react-library.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "dist"] +} +``` + +- [ ] **Step 18: Create packages/ui/src/index.ts** + +```typescript +// @repo/ui — shadcn/ui + Atomic Design component library +export {}; +``` + +- [ ] **Step 19: Commit** + +```bash +git add packages/core/ packages/api/ packages/api-client/ packages/cms-core/ packages/cms-client/ packages/ui/ +git commit -m "feat: add placeholder packages (core, api, api-client, cms-core, cms-client, ui)" +``` + +--- + +### Task 5: Placeholder apps (web-next, web-tanstack, cms, storybook) + +**Files:** +- Create: `apps/web-next/package.json` +- Create: `apps/web-next/tsconfig.json` +- Create: `apps/web-tanstack/package.json` +- Create: `apps/web-tanstack/tsconfig.json` +- Create: `apps/cms/package.json` +- Create: `apps/cms/tsconfig.json` +- Create: `apps/storybook/package.json` +- Create: `apps/storybook/tsconfig.json` + +- [ ] **Step 1: Create apps/web-next/package.json** + +```json +{ + "name": "@repo/web-next", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "echo 'placeholder'", + "dev": "echo 'placeholder'", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@repo/api-client": "workspace:*", + "@repo/ui": "workspace:*" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*" + } +} +``` + +- [ ] **Step 2: Create apps/web-next/tsconfig.json** + +```json +{ + "extends": "@repo/typescript-config/nextjs.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "next-env.d.ts"], + "exclude": ["node_modules"] +} +``` + +- [ ] **Step 3: Create apps/web-tanstack/package.json** + +```json +{ + "name": "@repo/web-tanstack", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "echo 'placeholder'", + "dev": "echo 'placeholder'", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@repo/api-client": "workspace:*", + "@repo/ui": "workspace:*" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*" + } +} +``` + +- [ ] **Step 4: Create apps/web-tanstack/tsconfig.json** + +```json +{ + "extends": "@repo/typescript-config/base.json", + "compilerOptions": { + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "jsx": "react-jsx", + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules"] +} +``` + +- [ ] **Step 5: Create apps/cms/package.json** + +```json +{ + "name": "@repo/cms", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "echo 'placeholder'", + "dev": "echo 'placeholder'", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@repo/cms-core": "workspace:*" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*" + } +} +``` + +- [ ] **Step 6: Create apps/cms/tsconfig.json** + +```json +{ + "extends": "@repo/typescript-config/nextjs.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "next-env.d.ts"], + "exclude": ["node_modules"] +} +``` + +- [ ] **Step 7: Create apps/storybook/package.json** + +```json +{ + "name": "@repo/storybook", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "echo 'placeholder'", + "dev": "echo 'placeholder'", + "lint": "eslint ." + }, + "dependencies": { + "@repo/ui": "workspace:*" + }, + "devDependencies": { + "@repo/eslint-config": "workspace:*", + "@repo/typescript-config": "workspace:*" + } +} +``` + +- [ ] **Step 8: Create apps/storybook/tsconfig.json** + +```json +{ + "extends": "@repo/typescript-config/react-library.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules"] +} +``` + +- [ ] **Step 9: Commit** + +```bash +git add apps/ +git commit -m "feat: add placeholder apps (web-next, web-tanstack, cms, storybook)" +``` + +--- + +### Task 6: Docker Compose + +**Files:** +- Create: `docker-compose.yml` + +- [ ] **Step 1: Create docker-compose.yml** + +```yaml +services: + postgres: + image: postgres:16-alpine + restart: unless-stopped + ports: + - "5432:5432" + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: template + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + +volumes: + postgres_data: +``` + +- [ ] **Step 2: Commit** + +```bash +git add docker-compose.yml +git commit -m "feat: add Docker Compose with PostgreSQL for local dev" +``` + +--- + +### Task 7: Install dependencies and verify workspace + +- [ ] **Step 1: Install pnpm if not available** + +Run: `corepack enable && corepack prepare pnpm@9.15.4 --activate` +Expected: pnpm is available + +- [ ] **Step 2: Run pnpm install** + +Run: `pnpm install` +Expected: Installs all workspace dependencies, creates `pnpm-lock.yaml`, no errors. + +- [ ] **Step 3: Verify Turborepo sees all workspaces** + +Run: `pnpm turbo run build --dry` +Expected: Output lists all 10 packages/apps: +- `@repo/typescript-config` +- `@repo/eslint-config` +- `@repo/core` +- `@repo/api` +- `@repo/api-client` +- `@repo/cms-core` +- `@repo/cms-client` +- `@repo/ui` +- `@repo/web-next` +- `@repo/web-tanstack` +- `@repo/cms` +- `@repo/storybook` + +- [ ] **Step 4: Run turbo build** + +Run: `pnpm build` +Expected: All workspaces build successfully (placeholder builds echo 'placeholder' or tsc --noEmit with no errors on empty src/index.ts). + +- [ ] **Step 5: Verify Docker Compose** + +Run: `docker compose up -d postgres && docker compose ps` +Expected: PostgreSQL container running, healthy. + +Run: `docker compose down` +Expected: Clean shutdown. + +- [ ] **Step 6: Commit lockfile** + +```bash +git add pnpm-lock.yaml +git commit -m "chore: add pnpm lockfile" +``` + +--- + +### Task 8: Create test directory structure + +**Files:** +- Create: `tests/unit/.gitkeep` +- Create: `tests/integration/.gitkeep` +- Create: `tests/e2e/.gitkeep` + +- [ ] **Step 1: Create test directories** + +```bash +mkdir -p tests/unit tests/integration tests/e2e +touch tests/unit/.gitkeep tests/integration/.gitkeep tests/e2e/.gitkeep +``` + +- [ ] **Step 2: Commit** + +```bash +git add tests/ +git commit -m "feat: add test directory structure (unit, integration, e2e)" +```