K. Recommended Target Architecture
Target: Monorepo with npm Workspaces + Turborepo
Tooling: npm workspaces + Turborepo Node version: 24 LTS (unified; Active LTS as of May 2026) Language: TypeScript everywhere (reverb-backend migration phased) Package manager: npm (already used across all repos — no migration required)
Proposed Repository Structure
soreto-platform/
│
├── apps/
│ ├── platform-api/ ← reverb-backend (migrated, renamed)
│ │ ├── src/
│ │ │ ├── routes/api/
│ │ │ ├── services/
│ │ │ ├── middleware/
│ │ │ ├── config/
│ │ │ └── common/
│ │ ├── migrations/ ← stays here (reverb schema)
│ │ ├── test/
│ │ ├── package.json
│ │ ├── tsconfig.json ← extends ../../tooling/tsconfig/base.json
│ │ ├── .env.example
│ │ └── CLAUDE.md
│ │
│ ├── platform-ui/ ← soreto-melissa (migrated)
│ │ ├── app/ ← Next.js App Router
│ │ ├── components/
│ │ ├── service/
│ │ ├── shared/
│ │ ├── store/
│ │ ├── types/
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ ├── .env.example
│ │ └── CLAUDE.md
│ │
│ ├── zoe/ ← soreto-zoe (migrated, refactored)
│ │ ├── src/
│ │ │ ├── modules/
│ │ │ ├── services/
│ │ │ └── database/
│ │ ├── processors/ ← eventually typed
│ │ ├── migrations/ ← stays here (zoe schema)
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ ├── config.js ← replace with @soreto/config
│ │ └── CLAUDE.md
│ │
│ └── legacy-portal/ ← reverb-react (modernized → Next.js 16 + React 19 + Node 24)
│ ├── src/
│ │ ├── actions/ ← Redux action creators (admin, client, shared, user)
│ │ ├── components/ ← React components (admin, client, sharePopup, shared, user)
│ │ ├── config/ ← config.js with @@PLACEHOLDER@@ tokens
│ │ ├── constants/
│ │ ├── decorators/
│ │ ├── dispatchers/ ← Flux app-dispatcher
│ │ ├── middleware/
│ │ ├── mixins/ ← Flux storeWatchMixin
│ │ ├── reducers/ ← Redux reducers (admin, client, shared, user)
│ │ ├── stores/ ← Flux stores
│ │ ├── utils/ ← helpers, services, wrappers
│ │ └── main.js ← entry point
│ ├── public/ ← static assets (images)
│ ├── dist/ ← compiled output (webpack — do not touch)
│ ├── index.js ← Express static file server (Procfile: web: node index.js)
│ ├── webpack.config.js ← pinned, do not update
│ ├── .babelrc ← Babel 6 config — pinned
│ ├── .travis.yml ← migrate to GitHub Actions (build only)
│ ├── package.json ← pinned, do not update dependencies
│ ├── package-lock.json
│ ├── README.md ← "MODERNIZING: Next.js 16 rewrite in progress — add to app/, not src/"
│ └── CLAUDE.md ← "Rewriting to Next.js 16 + React 19. New features go in app/ router."
│
├── packages/
│ ├── types/ ← @soreto/types
│ │ ├── src/
│ │ │ ├── entities/ ← Campaign, Order, Reward, SharedUrl, User
│ │ │ ├── enums/ ← RoleName, OrderStatus, RewardStatus
│ │ │ ├── api/ ← ApiResponse, PaginatedResponse
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ ├── api-client/ ← @soreto/api-client
│ │ ├── src/
│ │ │ ├── client.ts ← ReverbClient class
│ │ │ ├── postReward.ts
│ │ │ ├── notification.ts
│ │ │ ├── zendesk.ts
│ │ │ └── index.ts
│ │ ├── test/
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ ├── constants/ ← @soreto/constants
│ │ ├── src/
│ │ │ ├── roles.ts
│ │ │ ├── countries.ts
│ │ │ ├── campaignTypes.ts
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ ├── config/ ← @soreto/config
│ │ ├── src/
│ │ │ ├── loader.ts ← validated env loading
│ │ │ └── schemas/ ← per-app schemas
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ └── auth-utils/ ← @soreto/auth-utils
│ ├── src/
│ │ ├── cookieHandler.ts ← from soreto-cookie-jam
│ │ └── jwtDecode.ts
│ ├── package.json
│ └── tsconfig.json
│
├── tooling/
│ ├── eslint-config/ ← @soreto/eslint-config
│ │ ├── index.js
│ │ ├── next.js
│ │ ├── node.js
│ │ └── package.json
│ │
│ ├── tsconfig/ ← @soreto/tsconfig
│ │ ├── base.json
│ │ ├── nextjs.json
│ │ ├── node.json
│ │ └── package.json
│ │
│ └── jest-config/ ← @soreto/jest-config
│ ├── jest.base.js
│ ├── jest.node.js
│ ├── jest.react.js
│ └── package.json
│
├── docs/
│ ├── architecture/
│ │ ├── SYSTEM_OVERVIEW.md
│ │ ├── DATABASE_SCHEMA.md
│ │ ├── API_CONTRACT.md
│ │ └── AUTH_FLOW.md
│ ├── adr/
│ │ ├── 001-monorepo-migration.md
│ │ ├── 002-node-standardization.md
│ │ ├── 003-typescript-adoption.md
│ │ ├── 004-modernize-reverb-react.md
│ │ └── 005-seneca-decision.md
│ ├── spec/
│ │ ├── DOMAIN_MODEL.md
│ │ ├── API_ENDPOINTS.md
│ │ └── JOB_PROCESSORS.md
│ ├── migration/
│ │ ├── REVERB_REACT_PARITY.md
│ │ └── NODE_UPGRADE_TRACKER.md
│ └── dependencies/
│ ├── INTER_REPO_COUPLING.md
│ └── UPGRADE_BLOCKERS.md
│
├── turbo.json ← Turborepo task pipeline
├── package.json ← Root workspace (engines, scripts, workspaces field)
├── .nvmrc ← 24 (Active LTS)
├── .env.example ← Shared env var documentation
└── CLAUDE.md ← Root AI context document
System Architecture Diagram
╔═══════════════════════════════════════════════════════════════════╗
║ SORETO PLATFORM ║
║ ║
║ ┌─────────────────┐ ┌───────────────────────────────────┐ ║
║ │ platform-ui │────►│ platform-api │ ║
║ │ (Next.js 16) │ │ (Express 5, Node 24, TypeScript) │ ║
║ │ React 19 │ │ │ ║
║ │ PrimeReact │ │ Routes: /api/v1/* │ ║
║ │ TypeScript │ │ Auth: Passport (cookie/bearer) │ ║
║ └─────────────────┘ └────────────┬──────────────────────┘ ║
║ │ ║
║ ┌─────────────────┐ │ ║
║ │ legacy-portal │ ┌─────────────▼─────────┐ ║
║ │ (→ Next.js 16) │ │ PostgreSQL │ ║
║ │ reverb-react │ │ schema: reverb │ ║
║ └─────────────────┘ │ schema: zoe │ ║
║ └─────────────▲─────────┘ ║
║ ┌─────────────────┐ │ ║
║ │ zoe │────────────────────┘ ║
║ │ (Bull queues) │ ┌──────────────────────┐ ║
║ │ TypeScript │────►│ Redis │ ║
║ │ 12+ affiliate │ │ Sessions + Bull Q │ ║
║ │ processors │ └──────────────────────┘ ║
║ └─────────────────┘ ║
║ ║
║ ─ ─ ─ ─ ─ ─ ─ ─ shared packages ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ║
║ ║
║ @soreto/types @soreto/api-client @soreto/constants ║
║ @soreto/config @soreto/auth-utils @soreto/eslint-config ║
╚═══════════════════════════════════════════════════════════════════╝
Key Configuration Files
npm-workspaces (in package.json)
{
"workspaces": [
"apps/*",
"packages/*",
"tooling/*"
]
}
turbo.json
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
},
"lint": {
"outputs": []
},
"typecheck": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
}
}
}
Root package.json
{
"name": "soreto-platform",
"private": true,
"engines": {
"node": ">=24.0.0",
"npm": ">=10.0.0"
},
"workspaces": [
"apps/*",
"packages/*",
"tooling/*"
],
"scripts": {
"build": "turbo build",
"test": "turbo test",
"lint": "turbo lint",
"typecheck": "turbo typecheck",
"dev": "turbo dev --parallel"
}
}
Migration Sequence
Apps migrate into this structure one at a time, not simultaneously. See L — Migration Plan for the full phased sequence.
Order:
1. Create the monorepo scaffold (empty structure)
2. Migrate soreto-melissa → apps/platform-ui/ (first — cleanest codebase)
3. Extract @soreto/types and @soreto/constants
4. Move reverb-react → apps/legacy-portal/ (stand up Next.js 16 scaffold; rewrite begins)
5. Migrate reverb-backend → apps/platform-api/
6. Migrate soreto-zoe → apps/zoe/ (after AMD TypeScript refactor)
7. Extract @soreto/api-client (replace local_modules/reverb)
Legacy Portal: Modernization Target
apps/legacy-portal/ (reverb-react) is modernized, not frozen. The existing stack (Babel 6, Webpack 4, Node 10, React 17/dom 16.5 mismatch, react-router@3 + react-router-dom@4 mismatch) cannot be incrementally upgraded — the gaps are too large and compound. The correct path is a controlled rewrite to Next.js 16 + React 19 inside the monorepo.
Modernize to Next.js 16
Target stack:
| Layer | Current | Target |
|---|---|---|
| Framework | CRA-style Webpack 4 bundle | Next.js 16.2.6 (App Router) |
| React | 17.0.1 + react-dom 16.5.0 ⛔ | React 19.2.6 |
| Routing | react-router@3 + react-router-dom@4 ⛔ | react-router@7.15.1 (or Next.js file routing) |
| Language | JavaScript/JSX | TypeScript 6.0.3 |
| State | Redux 3.7.2 + Flux (mixed) | React Context + Zustand or Redux Toolkit 2.x |
| Bundler | Webpack 4.7.0 | Turbopack (Next.js 16 default) |
| Node | ~10.15.3 ⛔ | 24 LTS |
| Styling | PrimReact 1.5.1 | PrimeReact 10.9.8 (matches platform-ui) |
| Build config | .babelrc (Babel 6) |
tsconfig.json + SWC |
Target structure after modernization:
apps/legacy-portal/ ← modernized as Next.js 16 App Router app
├── app/
│ ├── (admin)/ ← admin routes (migrated from src/components/admin/)
│ ├── (client)/ ← client routes (migrated from src/components/client/)
│ └── layout.tsx
├── components/ ← migrated from src/components/shared/
├── store/ ← Zustand or Redux Toolkit (replaces Redux 3 + Flux)
├── service/ ← API calls (replaces src/utils/services/)
├── types/ ← TypeScript definitions
├── package.json ← Next.js 16, React 19, TypeScript 6
├── tsconfig.json ← extends ../../tooling/tsconfig/nextjs.json
├── next.config.ts
└── CLAUDE.md
Effort estimate: 6–10 weeks for one frontend engineer. This is a controlled rewrite — Babel 6, Flux, and the react-router v3/v4 dual installation cannot be incrementally migrated. The business logic (Redux action creators, API calls, reducers) can be preserved; the rendering and tooling layers are rewritten.
While the rewrite is in progress: Deploy a WAF (Cloudflare or AWS WAF) in front of the existing reverb-react Heroku app to compensate for Node 10 EOL exposure during the transition window.
What Does Not Change
| Item | Reason |
|---|---|
Database schemas (reverb, zoe) |
Schema changes are separate from repo structure |
| PostgreSQL / Redis / RabbitMQ | Infrastructure stays the same |
| Heroku deployment | App-level, not repo-level |
| Existing git history | Each app preserves its history via git subtree or history import |
| Business logic | No business logic changes during the structural migration |