Files
agentic-dev/docs/superpowers/plans/2026-04-06-plan-1-monorepo-foundation.md
Danijel Martinek d0d335d829 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 13:56:00 +02:00

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