# 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)" ```