Context
After ADR-0010 split the original monorepo into eigenoid/core and eigenoid/studio (renamed app-studio per ADR-0011), Studio still lives as a single repo containing both the React/Vite frontend and the FastAPI backend in one tree. The implementation plan in app-studio/SAAS_PLAN.md (v3) recommended keeping the monorepo with a "future split path documented".
ADR-0015 commits Studio to the same hosting topology and operational model as svc-access + app-access-admin: Pages frontend, Cloud Run backend, CF Workers gateway, dev → main branch model. The rest of the org already follows the app- / svc- / iac- naming convention from ADR-0011 with one repo per category, per surface:
| Surface | Repo |
|---|---|
| Access control backend | svc-access |
| Access control admin frontend | app-access-admin |
| Foundation infra (org-level) | iac-foundation |
Keeping Studio frontend + backend in one repo diverges from this pattern and creates concrete costs as the project grows:
- CODEOWNERS and CI secrets blast-radius: a backend deploy secret is reachable from the frontend pipeline and vice versa.
- Coupled release cadence: a frontend revert requires coordinating with any in-flight backend work in the same branch.
- Path-filter fragility in CI: every workflow has to remember which subdirectory it's scoped to; one missing filter and a frontend PR triggers backend tests (or worse, the deploy).
- Cross-stack PRs become hard to review: frontend and backend changes mixed in one branch.
- Infra (Terraform) does not belong in either: when
iac-studioTerraform lands, putting it in the same repo as the backend couples deploys of infra to deploys of code.
The cost of splitting now is one bounded refactor with git filter-repo (history preserved). The cost of splitting later, after the repo grows further, only goes up.
Decision
Split Studio into three repos, following ADR-0011 naming:
| Repo | Surface | Hosting | Branches |
|---|---|---|---|
eigenoid/app-studio | React/Vite/TS/Tailwind frontend | Cloudflare Pages → studio.eigenoid.com | dev → main |
eigenoid/svc-studio | FastAPI backend | Cloud Run in eigenoid-prd, behind CF Workers gateway per ADR-0014 | dev → main |
eigenoid/iac-studio | Terraform for Studio's GCP/CF resources, OpenAPI contract, Studio-specific docs that don't belong in docs-internal | n/a (CI applies via WIF per ADR-0009) | dev → main |
The current eigenoid/app-studio repo is not archived — it is reused for the frontend (already named correctly per ADR-0011 since Studio's user-facing surface is an "app", and its dev branch already holds the recent frontend + plan work). The backend code is extracted out of it into the new eigenoid/svc-studio repo.
Migration plan
svc-studioinitialization: from the currentapp-studiodevbranch (which already contains the merged backend Dockerfile, OPENAI_API_KEY validation, and frontendVITE_BACKEND_URLwork — PRs #8/#9/#10), rungit filter-repo --subdirectory backend. History ofbackend/is preserved with full blame. Push aseigenoid/svc-studio. Repository creation goes through the standard "Request new repository" issue template per ADR-0007 so safe-settings and suborg config apply automatically.app-studiocleanup: inapp-studio'sdevbranch, remove thebackend/directory (the code now lives insvc-studio). Updatestart.shso the local dev loop pulls/runs the backend from the siblingsvc-studiocheckout (auto-detection like ADR-0010'sEIGENOID_CORE_ROOTpattern, withEIGENOID_STUDIO_BACKEND_ROOT).iac-studioinitialization: created fresh (no historical Terraform or OpenAPI worth preserving yet).- CI bootstrap: each repo gets its own
pr-title.yml(Conventional Commits enforcement, copied fromplatform-actions) andci.yml(frontend:npm ci && npm run build; backend: import smoke test + planned pytest scaffold; iac:terraform fmt -check && terraform validate). - Cutover: only after
svc-studiohas its first green CI build and the local dev loop works end-to-end against the sibling layout, the backend directory is removed fromapp-studiomain. Until then, both copies coexist ondev.
Why this naming and not studio-frontend / studio-backend
The earlier draft of this ADR used studio-frontend / studio-backend. That violates ADR-0011's category-prefix convention. app-, svc-, and iac- prefixes are required so safe-settings suborg globs (app-*, svc-*, iac-*) and CODEOWNERS patterns work cleanly. Following the convention is mandatory; the convention determines the structure.
Consequences
- Aligned with org convention:
app-/svc-/iac-prefixes per ADR-0011; one repo per category per surface, likesvc-access+app-access-admin. - CODEOWNERS, CI secrets, and branch protection are per surface. Blast-radius of credentials is reduced; a frontend repo cannot leak a backend Cloud Run deploy key.
- Independent release cadence between frontend, backend, and infra.
- Per-repo CI is simpler — fewer path filters, less workflow coordination.
- History is preserved for the backend (filter-repo on
backend/subdirectory). Blame survives. - Each cross-stack feature is now two PRs (and three when infra is touched). Accepted as the price of the other gains.
- OpenAPI contract drift becomes a real concern: the contract lives in
iac-studio, is generated and published bysvc-studioCI, and consumed byapp-studiofor typed TS clients. Discipline + a CI check that the published contract matches the backend's generated one is required. Versioning by SHA or release tag. - Three new CI workflow setups (one per repo) instead of one. Manageable via copy/adapt from
platform-actionstemplates. - safe-settings suborg routing happens automatically because the prefixes match existing globs in
platform-settings. - Existing Studio open PRs (#6 UI accessibility on
feat/ui-non-tech-accessibility, #7 SAAS_PLAN ondocs/saas-plan) need to land before the backend extraction starts, or be rebased after. Coordinate with @andylow92.
Alternatives considered
- Keep monorepo with documented future-split path (the SAAS_PLAN v3 recommendation): rejected. The repo only grows; the cost of the split is monotonically increasing. Today is the cheapest moment to do it.
- Two repos only —
app-studio(frontend) +svc-studio(backend), noiac-studio: rejected. Terraform doesn't naturally live in either; folding it intosvc-studiocouples infra deploys to code deploys, and folding intoiac-org-sharedmixes Studio-specific resources with org-wide ones. A dedicatediac-studiokeeps the boundaries clean. - Use
app-studiofor backend and rename frontend to something else: rejected. The user-facing surface is the "app" by convention; the backend is the supporting service ("svc-"). - Names like
studio-frontend/studio-backend/studio-infra(the earlier draft): rejected for violating ADR-0011's category-prefix rule. Suborg globs (app-*,svc-*,iac-*) would not match. - Monorepo with Turborepo / Nx: rejected as overengineering for the team size and as further divergence from the rest of the org.
References
- ADR-0007 — Declarative repo lifecycle governance — issue template for repo creation
- ADR-0009 — GCP multi-project architecture — where
iac-studiodeploys - ADR-0010 — Split monorepo into core + studio — the previous split that produced
app-studio; this ADR continues that refactor - ADR-0011 — Repository naming convention —
app-/svc-/iac-prefixes - ADR-0014 — Cloudflare Workers as API Gateway — gateway pattern in front of
svc-studio - ADR-0015 — Studio multi-tenant SaaS aligned with svc-access — the strategic ADR this split supports
eigenoid/svc-accessandeigenoid/app-access-admin— reference structure