# 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` - `getProject(projectId: string): Promise` - `listProjects(tenantId: string): Promise` - `updateProjectApp(projectId: string, app: AppRecord): Promise` --- ### 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