8 tasks covering: root workspace files, shared TypeScript config, shared ESLint config, placeholder packages, placeholder apps, Docker Compose, dependency installation + verification, test dirs.
22 KiB
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
{
"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
packages:
- "apps/*"
- "packages/*"
- Step 3: Create turbo.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
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
{
"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.
{
"$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
{
"$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
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "./base.json",
"compilerOptions": {
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"jsx": "react-jsx"
}
}
- Step 5: Commit
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
{
"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
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
import baseConfig from "./base.js";
export default [
...baseConfig,
{ ignores: [".next/**", "out/**"] },
];
- Step 4: Create react-internal.js
import baseConfig from "./base.js";
export default [...baseConfig];
- Step 5: Commit
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
{
"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
{
"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
// @repo/core — Clean Architecture core package
// Layers: entities, application, infrastructure, interface-adapters, di
export {};
- Step 4: Create packages/api/package.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
{
"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
// @repo/api — tRPC router definitions
export {};
- Step 7: Create packages/api-client/package.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
{
"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
// @repo/api-client — Shared React Query hooks
export {};
- Step 10: Create packages/cms-core/package.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
{
"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
// @repo/cms-core — Payload CMS config, collections, hooks, globals
export {};
- Step 13: Create packages/cms-client/package.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
{
"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
// @repo/cms-client — Dual-mode Payload client (local + HTTP)
export {};
- Step 16: Create packages/ui/package.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
{
"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
// @repo/ui — shadcn/ui + Atomic Design component library
export {};
- Step 19: Commit
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
{
"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
{
"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
{
"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
{
"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
{
"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
{
"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
{
"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
{
"extends": "@repo/typescript-config/react-library.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["node_modules"]
}
- Step 9: Commit
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
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
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
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
mkdir -p tests/unit tests/integration tests/e2e
touch tests/unit/.gitkeep tests/integration/.gitkeep tests/e2e/.gitkeep
- Step 2: Commit
git add tests/
git commit -m "feat: add test directory structure (unit, integration, e2e)"