Files
master-ai/TURBOREPO_MIGRATION_PLAN.md
mawkone 2c3e7f9dfb feat: add Turborepo per-project monorepo scaffold and project API
- Add Turborepo scaffold templates (apps: product, website, admin, storybook; packages: ui, tokens, types, config)
- Add ProjectRecord and AppRecord types to control plane
- Add Gitea integration service (repo creation, scaffold push, webhooks)
- Add Coolify integration service (project + per-app service provisioning with turbo --filter)
- Add project routes: GET/POST /projects, GET /projects/:id/apps, POST /projects/:id/deploy
- Update chat route to inject project/monorepo context into AI requests
- Add deploy_app and scaffold_app tools to Gemini tool set
- Update deploy executor with monorepo-aware /execute/deploy endpoint
- Add TURBOREPO_MIGRATION_PLAN.md documenting rationale and scope

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-21 15:07:35 -08:00

9.5 KiB

Turborepo Monorepo Per-Project Migration Plan

Why We Are Making This Change

The core thesis of this platform is that one AI controls everything in one project. For that to work, the AI needs a complete mental model of the project — all apps, all shared code, all dependencies — in a single coherent context.

The current architecture creates separate Gitea repos per app (frontend repo, API repo, etc.), which fragments that context. The AI has to context-switch across repos, cross-repo dependencies are manual and brittle, and shared code has no clean home.

By adopting Turborepo monorepo per project, every project becomes a single repo containing all of its apps (product, website, admin) and shared packages (ui, types, config). The AI operates across the entire project simultaneously. Build orchestration, deployment, and shared code all become coherent automatically.

The structure every project will have:

{project-slug}/
  apps/
    product/        ← the core user-facing app
    website/        ← marketing / landing site
    admin/          ← internal admin tool
  packages/
    ui/             ← shared component library
    types/          ← shared TypeScript types
    config/         ← shared eslint, tsconfig
  turbo.json
  package.json      ← workspace root (pnpm workspaces)
  .gitignore
  README.md

This is not a Vercel dependency. Turborepo is MIT-licensed, runs anywhere, and costs nothing. Remote caching is optional and can be self-hosted on Coolify.


Scope of Changes

1. Project Scaffold Templates

What: Create a set of template files that get written into a new Gitea repo when a project is created.

Files to create: platform/scripts/templates/turborepo/

  • turbo.json — pipeline config defining build, dev, lint, test tasks and their dependencies
  • package.json — workspace root with pnpm workspaces pointing to apps/* and packages/*
  • .gitignore — covering node_modules, dist, .turbo cache
  • apps/product/package.json — Next.js app skeleton
  • apps/website/package.json — Astro or Next.js skeleton
  • apps/admin/package.json — Next.js app skeleton
  • packages/ui/package.json — shared component library stub
  • packages/types/package.json — shared types stub
  • packages/config/ — shared tsconfig.json and eslint base configs

Notes:

  • Templates should be stack-agnostic at the shell level — the turbo.json pipeline is what matters, inner frameworks can vary
  • Stack choices (Next.js vs Astro, etc.) can be parameterised later when we add a project creation wizard

2. Control Plane — Project Data Model Update

What: The current data model stores multiple Gitea repos per project. This changes to one repo per project.

File: platform/backend/control-plane/src/types.ts

Changes:

  • Remove repos: Array<{ gitea_repo, path }> from ProjectRecord (or update it)
  • Add repo: string — single Gitea repo URL for the project
  • Add apps: Array<{ name: string; path: string; coolify_service_uuid?: string }> — tracks each app inside the monorepo and its Coolify service
  • Add turbo: { version: string } — tracks which Turborepo version the project was scaffolded with

3. Control Plane — New Project Routes

What: Add project management endpoints to the control plane API.

File to create: platform/backend/control-plane/src/routes/projects.ts

Endpoints:

Method Path Purpose
POST /projects Create project — scaffold Turborepo repo in Gitea, register in DB
GET /projects/:project_id Get project record
GET /projects/:project_id/apps List apps within the monorepo
POST /projects/:project_id/apps Add a new app to the monorepo
POST /projects/:project_id/deploy Trigger Turbo build + Coolify deploy for one or all apps

Project creation flow (POST /projects):

  1. Validate request (name, tenant_id, optional app selections)
  2. Create Gitea repo via Gitea API
  3. Scaffold Turborepo structure from templates, push initial commit
  4. Register webhook: Gitea repo → control plane /webhooks/gitea
  5. Create Coolify project
  6. Create one Coolify service per app (with correct build filter)
  7. Save project record to storage
  8. Return project record with repo URL and app list

4. Control Plane — Storage Layer Updates

What: Add project storage operations alongside existing runs/tools storage.

File to update: platform/backend/control-plane/src/storage/memory.ts
File to update: platform/backend/control-plane/src/storage/firestore.ts
File to update: platform/backend/control-plane/src/storage/index.ts

New operations to add:

  • saveProject(project: ProjectRecord): Promise<void>
  • getProject(projectId: string): Promise<ProjectRecord | null>
  • listProjects(tenantId: string): Promise<ProjectRecord[]>
  • updateProjectApp(projectId: string, app: AppRecord): Promise<void>

5. Gitea Integration Service

What: New service to abstract all Gitea API calls. Currently there is no Gitea integration in the control plane.

File to create: platform/backend/control-plane/src/gitea.ts

Responsibilities:

  • Create repo for a project
  • Push initial scaffolded files (initial commit)
  • Register webhooks
  • Read file tree (so AI can understand the project structure)
  • Read/write individual files (so AI can make edits)

Config needed in config.ts:

  • giteaUrl — from GITEA_URL env var (e.g. https://git.vibnai.com)
  • giteaToken — from GITEA_TOKEN env var (admin token for repo creation)

6. Coolify Integration Service

What: New service to abstract all Coolify API calls. Currently the deploy executor calls Coolify but there is no central integration.

File to create: platform/backend/control-plane/src/coolify.ts

Responsibilities:

  • Create a Coolify project
  • Create a Coolify application service linked to a Gitea repo
  • Set the build command to turbo run build --filter={app-name}
  • Set the publish directory per app
  • Trigger a deployment
  • Get deployment status

Config needed in config.ts:

  • coolifyUrl — from COOLIFY_URL env var
  • coolifyToken — from COOLIFY_TOKEN env var

7. Deploy Executor — Monorepo Awareness

What: The existing deploy executor (platform/backend/executors/deploy) currently deploys a single service. It needs to understand the monorepo structure and use turbo run build --filter to target the right app.

File to update: platform/backend/executors/deploy/src/index.ts

Changes:

  • Accept app_name in the input payload (e.g. "product", "website", "admin")
  • Build command becomes turbo run build --filter={app_name} instead of npm run build
  • Pass the root of the monorepo as the build context, not an app subdirectory

8. AI Context — Project-Aware Prompting

What: The Gemini chat integration currently has no awareness of which project the user is in. It needs project context so the AI can reason across the whole monorepo.

File to update: platform/backend/control-plane/src/gemini.ts
File to update: platform/backend/control-plane/src/routes/chat.ts

Changes:

  • Add project_id to ChatRequest
  • On chat requests with a project_id, fetch the project record and inject:
    • Repo structure (app names, package names)
    • Recent deployment status per app
    • turbo.json pipeline config
  • Add a new Gemini tool: scaffold_app — lets the AI add a new app to the user's monorepo
  • Add a new Gemini tool: deploy_app — lets the AI trigger a Coolify deploy for a specific app by name

9. Theia Workspace — Single Repo Mode

What: The current Theia docker-compose opens a multi-root workspace across multiple repos. With one repo per project, this simplifies to a single workspace root.

File to update: theia-docker-compose.yml (and the Coolify service config for Theia)

Changes:

  • Workspace path points to the cloned monorepo root
  • Git remote is the project's single Gitea repo
  • Theia extensions should be aware of the turbo.json to surface run targets in the UI (future)

10. Local Dev — Replace start-all.sh with Turbo

What: The current platform/scripts/start-all.sh manually starts each service with &. Once the platform itself is in a Turborepo, this can be replaced with turbo run dev.

Note: This is a nice-to-have follow-on. The priority is getting user project scaffolding right first. The platform's own internal structure can be migrated to Turborepo in a separate pass.


Implementation Order

Step Task Depends On
1 Create scaffold templates Nothing
2 Add ProjectRecord type + storage ops Step 1
3 Build Gitea integration service Step 2
4 Build Coolify integration service Step 2
5 Add project routes to control plane Steps 2, 3, 4
6 Update deploy executor for monorepo Step 5
7 Update AI chat with project context Step 5
8 Update Theia workspace config Step 5
9 Migrate platform itself to Turborepo All of the above

What Does Not Change

  • Gitea as the source control host — same, just one repo per project instead of many
  • Coolify as the deployment host — same, just configured with Turbo build filters
  • Theia as the IDE — same, just opens one repo instead of multi-root
  • The control plane API architecture (Fastify, in-memory/Firestore storage) — same, just extended
  • Auth model — unchanged
  • No Vercel dependency anywhere in this plan