E. Monorepo Evaluation
Decision Question
Should the Soreto/Reverb ecosystem remain as four separate repositories, or evolve toward a monorepo?
Short answer: Monorepo. The coupling already exists. The question is whether that coupling is visible and typed, or hidden and fragile.
The Core Argument
The four repositories are not genuinely independent. Direct evidence:
| Evidence | What it means |
|---|---|
soreto-zoe/local_modules/reverb HTTP client |
zoe cannot function without reverb-backend running |
soreto-melissa calls NEXT_PUBLIC_APP_API_URL |
melissa cannot function without reverb-backend running |
reverb-react links to melissa as "New Portal" |
the two portals are a single transitioning system |
| Both repos run Knex against the same PostgreSQL server | shared database, separate schema |
| Both repos use the same Redis instance | shared infrastructure |
These repos already form a single system. Managing them as separate repos means: - Cross-cutting changes require 2–4 separate PRs, reviews, and deploys - Type errors between repos are caught at runtime, not at compile time - New engineers must clone 4 repos to understand the full system - AI tools (Claude Code, Cursor) cannot see the full system in one session
A monorepo removes none of these technical dependencies — it just makes them visible and manageable.
Benefits of a Monorepo (Evidence-Based)
1. Atomic Cross-Repo Changes
Current: Adding a new API endpoint to reverb-backend requires:
1. PR to reverb-backend (service + route)
2. PR to soreto-melissa (service class + types)
3. PR to soreto-zoe (reverb client method, if needed)
Monorepo: One PR. One review. One deploy gate.
2. Typed API Contracts
The local_modules/reverb client in soreto-zoe has no type definitions. Changes to reverb-backend API endpoints silently break zoe processors at runtime. With a @soreto/api-client shared package in a monorepo:
- TypeScript catches breaking changes at compile time
- CI fails before the broken code reaches production
- AI tools can read the type definitions and produce correct implementations
3. Unified Tooling
Currently: - 3 different ESLint versions across 4 repos - 4 different Babel/TypeScript configurations - 2 CI providers (Travis) with 2 repos having no CI - 4 different Node versions
A monorepo enforces a single tooling baseline, reducing configuration drift automatically.
4. AI Development Readiness
A single repo checkout gives AI agents (Claude Code, Cursor, Copilot) the full system context. Currently, a session in reverb-backend has no awareness of how soreto-melissa consumes its endpoints, producing suboptimal suggestions. See J — AI Context for full analysis.
5. Shared Package Extraction
@soreto/types, @soreto/constants, @soreto/api-client become possible as first-class packages with their own versioning and changelogs. Currently these are either duplicated across repos or non-existent.
Risks of a Monorepo
| Risk | Probability | Mitigation |
|---|---|---|
| Build tool complexity (Turborepo learning curve) | MEDIUM | Start with npm workspaces only; add Turborepo incrementally |
| Migration effort underestimated | MEDIUM | Phased approach — apps migrate one at a time |
| Legacy code quality drags new code | LOW | Freeze reverb-react in apps/legacy-portal/ with no new features |
| PR scope expands uncontrollably | LOW | CODEOWNERS per package; enforce apps/ vs packages/ PR discipline |
| CI becomes slow if not scoped | LOW | Turborepo's affected-project detection (--filter=[HEAD^1]) |
| Node version conflicts during transition | MEDIUM | .nvmrc per workspace; standardize Node before migrating |
Three Concepts — One Decision
These three terms appear throughout this audit and are not alternatives to each other — they are layers:
┌─────────────────────────────────────────────────────┐
│ MONOREPO ← The structure (one repo, many apps) │
│ ┌───────────────────────────────────────────────┐ │
│ │ npm workspaces ← Package linking layer │ │
│ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ Turborepo ← Build orchestration layer │ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
| Layer | What it is | What it does |
|---|---|---|
| Monorepo | Repository structure | All four apps live in one git repo (soreto-platform/) |
| npm workspaces | npm built-in feature | Links local packages (@soreto/types) across apps without publishing to npm |
| Turborepo | Build tool | Runs build/test/lint only on affected packages; caches results |
The recommendation is all three, in layers. You can adopt them incrementally: monorepo first, npm workspaces from day one (it's just a field in package.json), Turborepo added once the structure is in place.
Tooling Comparison
Option A: Turborepo + npm Workspaces ✓ Recommended
Why npm workspaces (not pnpm):
- All four repos already use npm and package-lock.json — zero migration cost
- npm workspaces are built into npm 7+ (Node 16+), which the team already uses
- No new tooling to learn or install; engineers already know npm install
- pnpm's main advantages (disk deduplication, strict hoisting) are useful for very large teams but add friction for this team size
- Turborepo works natively with npm workspaces
Why Turborepo: - Lower learning curve than Nx — minimal configuration required - Build cache is the primary value — no code generation (Nx's main differentiator) is needed - Active Vercel support and community - Incremental adoption path — add Turborepo config to an existing npm workspace with minimal disruption
What it provides:
- turbo build — builds only affected packages
- turbo test — tests only affected packages
- Remote caching (Vercel Remote Cache or self-hosted) — CI speeds up significantly over time
- Task dependency graph: run build before test, codegen before build
Option B: Nx
Why not (for now):
- Higher configuration overhead
- Code generation (generators, executors) is Nx's strength — not needed here
- No evidence of Nx familiarity in the codebase (no nx.json found)
- Better suited to large teams with standardized generator workflows
Option C: Yarn or pnpm Workspaces
Not recommended. All repos use npm — switching the package manager adds a migration step for zero benefit at this team scale. npm workspaces achieve the same result without tooling churn.
Option D: Keep as separate repos
Not recommended. The repos are already functionally a single system. Keeping them separate means accepting all the costs of a monolith (coordination, coupling) with none of the benefits (atomic changes, shared tooling, unified CI).
Feasibility Assessment
Pre-conditions
| Condition | Status |
|---|---|
| GitHub PAT revoked | ⛔ Not done — blocks everything |
All repos have .nvmrc |
⚠️ Not present in any repo |
| soreto-melissa has CI | ⚠️ No CI exists |
| soreto-zoe Knex upgraded | ⚠️ Still on 0.16.3 |
seneca.js strategy decided |
⚠️ No decision documented |
Feasibility by Phase
| Phase | Feasibility | Notes |
|---|---|---|
| Monorepo scaffold creation | ✓ Immediately feasible | npm workspaces + Turborepo setup takes 1–2 days |
| soreto-melissa migration | ✓ Feasible after CI is added | Modern stack, clean structure |
| reverb-backend migration | ⚠️ Medium complexity | Seneca + multi-process Procfile complicates extraction |
| soreto-zoe migration | ⚠️ High complexity | AMD TypeScript must be refactored first |
| reverb-react migration | ✓ Low priority | Freeze in place as apps/legacy-portal/ |
Maturity Assessment
| Criterion | Score | Notes |
|---|---|---|
| Consistent package manager | ✅ 4/4 | All use npm — npm workspaces require no migration |
| TypeScript consistency | ⚠️ 2/4 | melissa, zoe yes; backend, react no |
| Test coverage | ⚠️ 2/4 | Some in backend/melissa; none in zoe |
| CI/CD discipline | ❌ 2/4 | Only backend and react (though react's CI is hollow) |
| Domain boundary clarity | ⚠️ MEDIUM | Some blurring — zoe calls backend directly |
| Shared code awareness | ⚠️ MEDIUM | Team appears aware of duplication but hasn't extracted yet |
Assessment: The organization is ready for a simple monorepo (npm workspaces). It is not yet ready for a fully orchestrated Nx/Turborepo setup with code generation. Start simple — add orchestration as the team gains confidence.