- 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>
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 definingbuild,dev,lint,testtasks and their dependenciespackage.json— workspace root with pnpm workspaces pointing toapps/*andpackages/*.gitignore— covering node_modules, dist, .turbo cacheapps/product/package.json— Next.js app skeletonapps/website/package.json— Astro or Next.js skeletonapps/admin/package.json— Next.js app skeletonpackages/ui/package.json— shared component library stubpackages/types/package.json— shared types stubpackages/config/— sharedtsconfig.jsonandeslintbase configs
Notes:
- Templates should be stack-agnostic at the shell level — the
turbo.jsonpipeline 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 }>fromProjectRecord(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):
- Validate request (name, tenant_id, optional app selections)
- Create Gitea repo via Gitea API
- Scaffold Turborepo structure from templates, push initial commit
- Register webhook: Gitea repo → control plane
/webhooks/gitea - Create Coolify project
- Create one Coolify service per app (with correct build filter)
- Save project record to storage
- 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— fromGITEA_URLenv var (e.g.https://git.vibnai.com)giteaToken— fromGITEA_TOKENenv 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— fromCOOLIFY_URLenv varcoolifyToken— fromCOOLIFY_TOKENenv 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_namein the input payload (e.g."product","website","admin") - Build command becomes
turbo run build --filter={app_name}instead ofnpm 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_idtoChatRequest - 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.jsonpipeline 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.jsonto 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