Skip to content

← Back to README

Q. Epics, User Stories & Tasks


How to Read This Document

Work is organised into 6 Epics that map directly to the Migration Plan phases. Within each Epic, User Stories describe the outcome from the team's perspective. Each story breaks down into Tasks — atomic units of work that can be picked up individually.

Priority Levels

Priority Label Meaning
P0 🚨 CRITICAL Blocks all other work or is an active security incident — do today
P1 🔴 HIGH Required before the next phase can begin — this sprint or this week
P2 🟡 MEDIUM Parallel stream that can run concurrently with P1 after foundation is set
P3 🟢 LOW Improvement that adds long-term value; schedule after P2 streams are stable

Effort Estimates (AI-assisted)

Size Label Duration
XS Extra Small < 1 day
S Small 1–2 days
M Medium 3–5 days
L Large 1–2 weeks
XL Extra Large 2–4 weeks

Owners

Code Role
Any Any engineer — no specialist needed
Arch Principal Architect
Eng1 Full-Stack Engineer 1 (backend focus)
Eng2 Full-Stack Engineer 2 (frontend/platform focus)
Eng3 Full-Stack Engineer 3 (legacy portal / zoe focus)
DevOps DevOps / deployment owner
Sec Security lead (or engineer performing security tasks)

Epic Index

Epic Title Priority Phase Owner
EPIC-0 Security Hardening 🚨 P0 Phase 0 Any/Sec/DevOps
EPIC-1 CI/CD Foundation & Dependency Triage 🔴 P1 Phase 1 All 3 Eng
EPIC-2 Monorepo Bootstrap & Shared Packages 🔴 P1 Phase 2 Eng1 + Eng2
EPIC-3 Backend Modernization (reverb-backend) 🟡 P2 Phase 3 Eng1
EPIC-4 Zoe Modernization (soreto-zoe) 🟡 P2 Phase 4 Eng3
EPIC-5 Legacy Portal Rewrite (reverb-react → Next.js 16) 🟡 P2 Phase 5 Eng2 + Eng3

EPIC-0 — Security Hardening

Priority: 🚨 P0
Phase: 0 — Week 1
Blocks: All other epics
Goal: Eliminate the active security exposure and verify production secrets before any structural work begins.


STORY-0.1 — Revoke the leaked GitHub PAT

As the security lead,
I want the GitHub Personal Access Token embedded in soreto-zoe/package.json to be revoked immediately,
so that unauthorised access to Soreto's private repositories is closed.

Acceptance Criteria: - PAT is revoked in GitHub → Settings → Developer Settings → Personal Access Tokens - Audit log reviewed: all repos the PAT had access to are identified - Replacement strategy for soreto-arena dependency is in place (see STORY-0.2) - soreto-zoe/package.json no longer contains any GitHub token

# Task Priority Effort Owner
T-0.1.1 Revoke PAT: GitHub → Settings → Developer Settings → Personal Access Tokens → Revoke 🚨 P0 XS Sec
T-0.1.2 Review GitHub PAT audit log — identify every repo the token accessed 🚨 P0 XS Sec
T-0.1.3 Search all four repos for other embedded tokens: git log -S "ghp_" --all 🚨 P0 XS Any
T-0.1.4 Remove PAT from soreto-zoe/package.json (replace soreto-arena dep — see STORY-0.2) 🚨 P0 XS Any

STORY-0.2 — Replace soreto-arena with a public npm alternative

As an engineer maintaining the job scheduler,
I want the soreto-arena GitHub-hosted dependency replaced with a public npm package,
so that the build no longer requires a GitHub PAT and the dependency is auditable.

Acceptance Criteria: - soreto-zoe/package.json no longer references a GitHub URL with embedded token - Job queue UI is accessible in development and staging - CI build succeeds without any GitHub authentication

# Task Priority Effort Owner
T-0.2.1 Evaluate bull-board (npm: @bull-board/express) as drop-in replacement for soreto-arena 🚨 P0 XS Eng3
T-0.2.2 Install @bull-board/express and wire up the existing Bull queues 🚨 P0 S Eng3
T-0.2.3 Verify queue UI works in development 🚨 P0 XS Eng3
T-0.2.4 Remove soreto-arena entry from package.json and package-lock.json 🚨 P0 XS Eng3

STORY-0.3 — Verify and harden production secrets

As a DevOps engineer,
I want to confirm that SESSION_SECRET, TOKEN_SECRET, and COOKIE_SECRET are explicitly set in every Heroku environment,
so that the application does not silently use the hardcoded defaults in reverb-backend/config/config.js.

Acceptance Criteria: - All three secrets are confirmed set in Heroku staging and production environments - A runbook documents which secrets are required per application - config/config.js defaults are replaced with an explicit process.env.X || (() => { throw new Error('X must be set') })() pattern

# Task Priority Effort Owner
T-0.3.1 Run heroku config -a <reverb-backend-app> \| grep -E "SECRET\|TOKEN" on staging + production 🚨 P0 XS DevOps
T-0.3.2 If any secret is missing: generate cryptographically strong value (node -e "console.log(require('crypto').randomBytes(64).toString('hex'))") and set in Heroku 🚨 P0 XS DevOps
T-0.3.3 Update reverb-backend/config/config.js to throw on missing secrets in production (NODE_ENV === 'production') 🔴 P1 S Eng1
T-0.3.4 Create docs/ops/SECRETS_RUNBOOK.md listing all required env vars per app 🔴 P1 S DevOps

STORY-0.4 — Audit git history for other embedded secrets

As a security lead,
I want to scan the full git history of all four repos for any other embedded credentials,
so that there are no other live secrets in the codebase history.

Acceptance Criteria: - All four repos scanned with git log -S patterns for common secret patterns - Any findings documented and rotated - Git history remediation plan in place for any found secrets (BFG Repo Cleaner or git filter-repo)

# Task Priority Effort Owner
T-0.4.1 Scan each repo: git log -S "password\|secret\|token\|key\|api_key" --all --oneline 🚨 P0 XS Sec
T-0.4.2 Run trufflehog or gitleaks against all four repos 🔴 P1 S Sec
T-0.4.3 For any found secrets: rotate them immediately, document in security incident log 🔴 P1 S Sec
T-0.4.4 If secrets are in history (not just working tree): use git filter-repo to rewrite history and force-push 🟡 P2 M Sec + Arch

EPIC-1 — CI/CD Foundation & Dependency Triage

Priority: 🔴 P1
Phase: 1 — Weeks 2–6
Blocks: Epic 2 (CI required before monorepo migration)
Goal: Give every repo a quality gate. Stop broken code from being merged undetected. Remove dead integrations that add noise.


STORY-1.1 — Add GitHub Actions CI to soreto-melissa

As a developer on soreto-melissa,
I want every pull request to run typechecking, linting, tests, and a build,
so that regressions are caught before code reaches main.

Acceptance Criteria: - GitHub Actions workflow runs on every push and pull request - Steps: npm citsc --noEmitnext lintjestnext build - Build badge visible in the repository README - Workflow fails fast: any step failure blocks the PR

# Task Priority Effort Owner
T-1.1.1 Create .github/workflows/ci.yml in soreto-melissa 🔴 P1 S Eng2
T-1.1.2 Add typecheck npm script: "typecheck": "tsc --noEmit" 🔴 P1 XS Eng2
T-1.1.3 Verify jest.setup.ts exists (referenced in jest.config.js but unverified) — create if absent 🔴 P1 XS Eng2
T-1.1.4 Run test suite locally — fix any immediate failures before enabling CI 🔴 P1 S Eng2
T-1.1.5 Add status badge to README.md 🟡 P2 XS Eng2

STORY-1.2 — Add GitHub Actions CI to soreto-zoe

As a developer on soreto-zoe,
I want every pull request to run typechecking and a build,
so that TypeScript errors are caught in CI rather than at runtime.

Acceptance Criteria: - GitHub Actions workflow runs on every push and pull request - Steps: npm citsc (build) - Workflow fails if tsc exits non-zero

# Task Priority Effort Owner
T-1.2.1 Create .github/workflows/ci.yml in soreto-zoe 🔴 P1 S Eng3
T-1.2.2 Confirm tsc succeeds with the two-tsconfig setup — fix any pre-existing errors 🔴 P1 S Eng3
T-1.2.3 Fix malformed package-lock.json (re-generate with npm install) 🔴 P1 XS Eng3

STORY-1.3 — Migrate reverb-backend from Travis CI to GitHub Actions

As a developer on reverb-backend,
I want CI to run on GitHub Actions with the same steps as Travis CI,
so that CI continues to work when Travis CI access lapses and the team has one CI provider.

Acceptance Criteria: - GitHub Actions runs npm cinpm test (Mocha) on every push and PR - Travis CI .travis.yml is removed or disabled - Existing test suite passes in the new runner

# Task Priority Effort Owner
T-1.3.1 Create .github/workflows/ci.yml for reverb-backend 🔴 P1 S Eng1
T-1.3.2 Run full Mocha test suite — document coverage percentage (resolves Assumption A7) 🔴 P1 S Eng1
T-1.3.3 Archive (disable, don't delete) .travis.yml 🔴 P1 XS Eng1

STORY-1.4 — Migrate reverb-react from Travis CI to GitHub Actions

As a developer on reverb-react,
I want CI to run a basic build check on GitHub Actions,
so that the repo has a functioning quality gate during the transition to the Next.js 16 rewrite.

Acceptance Criteria: - GitHub Actions runs npm cinpm run build (webpack) on push and PR - Travis CI disabled - Note: tests are not added (Next.js 16 rewrite supersedes this; keep minimal)

# Task Priority Effort Owner
T-1.4.1 Create .github/workflows/ci.yml for reverb-react (build only) 🔴 P1 S Eng3
T-1.4.2 Archive .travis.yml 🔴 P1 XS Eng3

STORY-1.5 — Add .nvmrc files to all repositories

As a developer cloning any Soreto repository,
I want a .nvmrc file at the root,
so that nvm use (or fnm use) sets the correct Node version automatically.

Acceptance Criteria: - Each repo has a .nvmrc declaring the current (audited) Node version - CI workflows reference node-version-file: .nvmrc

# Task Priority Effort Owner
T-1.5.1 Add .nvmrc to reverb-backend: 14.17.3 🔴 P1 XS Eng1
T-1.5.2 Add .nvmrc to reverb-react: 10.15.3 (documents current — upgrade comes in Phase 5) 🔴 P1 XS Eng3
T-1.5.3 Add .nvmrc to soreto-melissa: 22.0.0 🔴 P1 XS Eng2
T-1.5.4 Add .nvmrc to soreto-zoe: 16.13.0 (documents current — upgrade comes in Phase 4) 🔴 P1 XS Eng3

STORY-1.6 — Remove dead integrations and deprecated dependencies

As an engineer,
I want dead third-party integrations removed from the codebase,
so that the app no longer makes requests to defunct APIs and the dependency surface is reduced.

Acceptance Criteria: - universal-analytics removed from reverb-backend (Google UA shut down July 2024) - Google+ sharing code removed from reverb-react (shut down April 2019) - node-sass replaced with sass in reverb-backend (prerequisite for Node upgrade) - Removed code is tested to confirm no runtime regressions

# Task Priority Effort Owner
T-1.6.1 Remove universal-analytics from reverb-backend — find all call sites and delete 🔴 P1 S Eng1
T-1.6.2 If analytics needed: integrate GA4 via google-analytics-data (GA4 API) 🟢 P3 M Eng1
T-1.6.3 Remove Google+ sharing code from reverb-react (GOOGLE.URL_SUPPORT) 🔴 P1 XS Eng3
T-1.6.4 Replace node-sass with sass in reverb-backend (npm uninstall node-sass && npm install sass) 🔴 P1 S Eng1
T-1.6.5 Verify all SCSS still compiles after sass swap 🔴 P1 XS Eng1

STORY-1.7 — Begin Knex upgrade in soreto-zoe

As an engineer on soreto-zoe,
I want to start the incremental Knex upgrade from 0.16.3,
so that the scheduler's database layer moves onto a supported version without a big-bang upgrade.

Acceptance Criteria: - Knex upgraded from 0.16.30.21.x in soreto-zoe - All existing migrations run successfully against the staging database - No query regressions in the integration test (manual or automated)

# Task Priority Effort Owner
T-1.7.1 Read the Knex changelog from 0.16.x → 0.21.x — list breaking changes 🔴 P1 S Eng3
T-1.7.2 Upgrade knex@0.16.3knex@0.21.x and update knexfile.js if needed 🔴 P1 M Eng3
T-1.7.3 Run all Knex migrations against a local/staging PostgreSQL — confirm clean execution 🔴 P1 S Eng3
T-1.7.4 Document further Knex upgrade steps (0.21 → 0.95 → 2.x → 3.x) in UPGRADE_BLOCKERS.md 🔴 P1 XS Eng3

STORY-1.8 — Create baseline documentation

As a developer joining the project,
I want a domain model, a list of upgrade blockers, and a reverb-react parity checklist to exist,
so that the migration work has a shared reference and progress can be tracked.

Acceptance Criteria: - docs/spec/DOMAIN_MODEL.md exists with entity definitions (User, Campaign, Reward, SharedUrl, Order) - docs/dependencies/UPGRADE_BLOCKERS.md exists with the full blocker list from the audit - docs/migration/REVERB_REACT_PARITY.md exists with a checkbox for every distinct page/feature in reverb-react

# Task Priority Effort Owner
T-1.8.1 Create docs/spec/DOMAIN_MODEL.md — extract entity shapes from reverb-backend service files 🔴 P1 M Arch
T-1.8.2 Create docs/dependencies/UPGRADE_BLOCKERS.md from audit findings 🔴 P1 S Arch
T-1.8.3 Count and list all distinct page components in reverb-react/src/components/admin/ and client/ 🔴 P1 S Eng3
T-1.8.4 Create docs/migration/REVERB_REACT_PARITY.md as a feature checklist based on T-1.8.3 🔴 P1 S Eng3

EPIC-2 — Monorepo Bootstrap & Shared Packages

Priority: 🔴 P1 (starts Week 5, runs to Week 12)
Phase: 2
Depends on: Epic 1 complete (CI established on all repos)
Goal: Create the soreto-platform monorepo and migrate soreto-melissa as the first app. Establish the shared packages that all future apps will consume.


STORY-2.1 — Scaffold the soreto-platform monorepo

As the principal architect,
I want a soreto-platform repository with npm workspaces and Turborepo configured,
so that the team has a stable target structure to migrate apps into.

Acceptance Criteria: - soreto-platform/ repository exists with npm workspaces configured - Turborepo 2.x installed with build, test, lint, typecheck pipeline tasks - Empty apps/, packages/, tooling/, docs/ directories present - Root .nvmrc set to Node 24 - Root CLAUDE.md documents the monorepo overview, workspace layout, and per-app responsibilities

# Task Priority Effort Owner
T-2.1.1 Create soreto-platform/ directory and git init 🔴 P1 XS Arch
T-2.1.2 Create root package.json with workspaces: ["apps/*", "packages/*", "tooling/*"] 🔴 P1 XS Arch
T-2.1.3 Install Turborepo: npm install turbo --save-dev -w 🔴 P1 XS Arch
T-2.1.4 Create turbo.json with pipeline: build, test, lint, typecheck 🔴 P1 S Arch
T-2.1.5 Create directory structure: apps/, packages/, tooling/, docs/ 🔴 P1 XS Arch
T-2.1.6 Create root .nvmrc: 24 🔴 P1 XS Arch
T-2.1.7 Create root .gitignore covering all workspaces 🔴 P1 XS Arch
T-2.1.8 Create root CLAUDE.md — monorepo overview, workspace conventions, app responsibilities 🔴 P1 M Arch
T-2.1.9 Configure GitHub Actions root CI: turbo run lint typecheck test build --filter=[HEAD^1] 🔴 P1 S Arch

STORY-2.2 — Create @soreto/tsconfig shared TypeScript configurations

As a developer in any Soreto app,
I want a shared TypeScript config that enforces consistent strict settings,
so that every app inherits the same compiler options without duplicating them.

Acceptance Criteria: - packages/tsconfig/ exists with base.json, nextjs.json, node.json - All apps extend one of these via extends: "@soreto/tsconfig/nextjs.json" - strict: true in base config

# Task Priority Effort Owner
T-2.2.1 Create packages/tsconfig/package.json (name: @soreto/tsconfig) 🔴 P1 XS Eng2
T-2.2.2 Create base.json: strict: true, ES2022, moduleResolution: bundler 🔴 P1 XS Eng2
T-2.2.3 Create nextjs.json: extends base, adds Next.js-specific paths 🔴 P1 XS Eng2
T-2.2.4 Create node.json: extends base, sets module: NodeNext 🔴 P1 XS Eng2

STORY-2.3 — Create @soreto/eslint-config shared linting rules

As a developer,
I want a single shared ESLint config all apps extend,
so that linting rules are consistent and not duplicated across four different ESLint versions.

Acceptance Criteria: - packages/eslint-config/ exists with a flat config extending recommended + TypeScript rules - Apps replace their individual ESLint configs with extends: ["@soreto/eslint-config"]

# Task Priority Effort Owner
T-2.3.1 Create packages/eslint-config/package.json 🔴 P1 XS Eng2
T-2.3.2 Create index.js extending @eslint/js recommended + typescript-eslint recommended 🔴 P1 S Eng2
T-2.3.3 Add Next.js-specific rule extension (@soreto/eslint-config/nextjs) 🔴 P1 XS Eng2

STORY-2.4 — Create @soreto/types shared type package

As a developer on any Soreto app,
I want a shared types package that defines the canonical API entity shapes,
so that soreto-melissa, reverb-backend, and soreto-zoe all share the same type definitions and API contract.

Acceptance Criteria: - packages/types/ published as @soreto/types@1.0.0 - Contains: User, Campaign, CampaignVersion, Order, Reward, SharedUrl, ROLES enum, COUNTRIES - Contains: ApiResponse<T>, PaginatedResponse<T> envelope types - Validated against actual reverb-backend API response shapes - soreto-melissa imports from @soreto/types instead of local types/ folder

# Task Priority Effort Owner
T-2.4.1 Create packages/types/ workspace with tsconfig.json 🔴 P1 XS Eng2
T-2.4.2 Extract ROLES enum and COUNTRIES from soreto-melissa/shared/constants.ts 🔴 P1 XS Eng2
T-2.4.3 Define User, Campaign, CampaignVersion, Order, Reward, SharedUrl interfaces from reverb-backend service files 🔴 P1 M Eng1 + Eng2
T-2.4.4 Define ApiResponse<T> and PaginatedResponse<T> wrapper types 🔴 P1 XS Eng2
T-2.4.5 Validate all types against actual API responses from reverb-backend staging 🔴 P1 M Eng1 + Eng2
T-2.4.6 Replace soreto-melissa/shared/constants.ts role/country imports with @soreto/types 🔴 P1 S Eng2
T-2.4.7 Replace local types/ usage in soreto-melissa with @soreto/types imports 🔴 P1 M Eng2

STORY-2.5 — Migrate soreto-melissa into apps/platform-ui/

As an engineer,
I want soreto-melissa moved into the monorepo as apps/platform-ui/,
so that it benefits from shared tooling and Turborepo CI caching.

Acceptance Criteria: - Git history preserved via git subtree or git mv - apps/platform-ui/ builds and deploys successfully from the monorepo - All imports updated to @soreto/types, @soreto/tsconfig, @soreto/eslint-config - Heroku deploys from APP_BASE=apps/platform-ui with heroku-buildpack-monorepo - CI passes end-to-end in Turborepo

# Task Priority Effort Owner
T-2.5.1 Use git subtree add to bring soreto-melissa history into soreto-platform 🔴 P1 S Eng2
T-2.5.2 Move into apps/platform-ui/ and update package.json name to @soreto/platform-ui 🔴 P1 S Eng2
T-2.5.3 Update tsconfig.json to extend @soreto/tsconfig/nextjs.json 🔴 P1 XS Eng2
T-2.5.4 Update ESLint config to extend @soreto/eslint-config/nextjs 🔴 P1 XS Eng2
T-2.5.5 Update @soreto/* deps to use npm workspace protocol ("@soreto/types": "*") 🔴 P1 XS Eng2
T-2.5.6 Move @soreto/* packages from devDependenciesdependencies (Heroku prunes devDeps) 🔴 P1 XS Eng2
T-2.5.7 Add Procfile: web: npm start 🔴 P1 XS Eng2
T-2.5.8 Configure Heroku: add heroku-buildpack-monorepo (first) + heroku/nodejs (second) 🔴 P1 S DevOps
T-2.5.9 Set APP_BASE=apps/platform-ui Heroku config var 🔴 P1 XS DevOps
T-2.5.10 Verify Heroku deploy succeeds and app loads correctly 🔴 P1 S Eng2 + DevOps
T-2.5.11 Add per-app CLAUDE.md: "App Router only. All code in app/, components/, service/, store/. No src/ directory." 🔴 P1 XS Eng2

STORY-2.6 — Stand up the Next.js 16 scaffold for apps/legacy-portal/

As an engineer on the legacy portal rewrite,
I want a clean Next.js 16 scaffold ready in the monorepo,
so that the reverb-react porting work can begin immediately without spending time on tooling setup.

Acceptance Criteria: - apps/legacy-portal/ exists in the monorepo with Next.js 16, React 19, TypeScript 6, Node 24 - App Router at root (app/ — no src/ directory) - app/(admin)/ and app/(client)/ route groups with placeholder guarded layouts - Tailwind CSS 4.2.0 configured with @theme directive in globals.css - shadcn/ui CLI v4 initialised (components.json present, components/ui/ directory ready) - Zustand installed as state management - CI workflow runs typecheck + lint + build - Deploys to Heroku with APP_BASE=apps/legacy-portal

# Task Priority Effort Owner
T-2.6.1 Scaffold: npx create-next-app@latest legacy-portal --typescript --app --no-src-dir in apps/ 🔴 P1 XS Eng3
T-2.6.2 Set Node version: update engines in package.json to >=24, update .nvmrc 🔴 P1 XS Eng3
T-2.6.3 Add Tailwind CSS 4.2.0: install tailwindcss@^4, configure @import "tailwindcss" in globals.css, define @theme block 🔴 P1 S Eng3
T-2.6.4 Initialise shadcn/ui: npx shadcn@latest init — select style, base colour, confirm globals.css path 🔴 P1 XS Eng3
T-2.6.5 Create app/(admin)/layout.tsx with role guard (redirect non-admin to login) 🔴 P1 S Eng3
T-2.6.6 Create app/(client)/layout.tsx with role guard (redirect non-client to admin or login) 🔴 P1 S Eng3
T-2.6.7 Install Zustand: npm install zustand 🔴 P1 XS Eng3
T-2.6.8 Create store/useAuthStore.ts with isAuthenticated, user, login(), logout() 🔴 P1 S Eng3
T-2.6.9 Create service/ directory and stub BaseService.ts using @soreto/api-client 🟡 P2 S Eng3
T-2.6.10 Add Procfile: web: npm start 🔴 P1 XS Eng3
T-2.6.11 Set APP_BASE=apps/legacy-portal Heroku config var 🔴 P1 XS DevOps
T-2.6.12 Add per-app CLAUDE.md: route groups, shadcn/skills context, Zustand store conventions 🔴 P1 S Eng3
T-2.6.13 Deploy WAF (Cloudflare or equivalent) in front of current reverb-react Heroku app — compensating control during transition 🔴 P1 M DevOps

EPIC-3 — Backend Modernization

Priority: 🟡 P2 (starts Week 12, runs Weeks 12–20)
Phase: 3 — parallel with Epics 4 and 5
Depends on: Epic 2 scaffold complete
Owner: Eng1
Goal: Move reverb-backend to Node 24, introduce TypeScript for new code, and publish a typed API client.


STORY-3.1 — Upgrade reverb-backend Node 14 → 24 incrementally

As a backend engineer,
I want reverb-backend running on Node 24 LTS,
so that the API server receives security patches and can run modern JavaScript.

Acceptance Criteria: - reverb-backend runs on Node 24 LTS in CI and production - All Mocha tests pass at each Node increment (14→18→20→22→24) - seneca compatibility verified on Node 18+ (blockers documented) - passport upgraded to 0.7.x - connect-redis upgraded to v6

# Task Priority Effort Owner
T-3.1.1 Upgrade connect-redis@3connect-redis@6 (breaking API change — update session store initialisation) 🟡 P2 M Eng1
T-3.1.2 Upgrade passport@0.3.2passport@0.7.x 🟡 P2 M Eng1
T-3.1.3 Upgrade Express 4.x5.x — run CI, fix breaking changes (path parameter handling, router API) 🟡 P2 M Eng1
T-3.1.4 Upgrade Node: 14 → 18 — run full test suite, fix failures 🟡 P2 M Eng1
T-3.1.5 Test seneca on Node 18: run test suite — if fails, document replacement candidates (moleculer, direct AMQP) 🟡 P2 M Eng1
T-3.1.6 Upgrade Node: 18 → 20 → 22 → 24 — run CI at each step 🟡 P2 M Eng1
T-3.1.7 Update .nvmrc to 24 🟡 P2 XS Eng1

STORY-3.2 — Migrate reverb-backend into apps/platform-api/

As an engineer,
I want reverb-backend in the monorepo as apps/platform-api/,
so that it shares tooling with the other apps and benefits from Turborepo CI caching.

Acceptance Criteria: - Git history preserved - apps/platform-api/ builds, tests pass, and deploys from monorepo - Heroku deploys via APP_BASE=apps/platform-api - local_modules/soreto-cookie-jam replaced by @soreto/auth-utils

# Task Priority Effort Owner
T-3.2.1 git subtree add to bring reverb-backend history into soreto-platform 🟡 P2 S Eng1
T-3.2.2 Move into apps/platform-api/ and rename workspace to @soreto/platform-api 🟡 P2 S Eng1
T-3.2.3 Extract local_modules/soreto-cookie-jampackages/auth-utils/ as @soreto/auth-utils 🟡 P2 M Eng1
T-3.2.4 Update all require('../local_modules/soreto-cookie-jam')require('@soreto/auth-utils') 🟡 P2 S Eng1
T-3.2.5 Add Procfile: web: node server.js (or current start command) 🟡 P2 XS Eng1
T-3.2.6 Set APP_BASE=apps/platform-api Heroku config var 🟡 P2 XS DevOps
T-3.2.7 Verify Heroku deploy and smoke test all major API endpoints 🟡 P2 M Eng1

STORY-3.3 — Introduce TypeScript to reverb-backend (phased)

As a backend engineer,
I want to write new reverb-backend files in TypeScript,
so that the codebase gradually gains type safety without requiring a full rewrite.

Acceptance Criteria: - tsconfig.json added with allowJs: true — existing JS code untouched - New service files written in TypeScript - AbstractService.js converted to AbstractService.ts as the first migration - TypeScript extends @soreto/tsconfig/node.json

# Task Priority Effort Owner
T-3.3.1 Add tsconfig.json to apps/platform-api/ extending @soreto/tsconfig/node.json 🟡 P2 XS Eng1
T-3.3.2 Enable "allowJs": true — confirm build still passes 🟡 P2 XS Eng1
T-3.3.3 Convert services/AbstractService.jsAbstractService.ts 🟡 P2 M Eng1
T-3.3.4 Add JSDoc type annotations to config/config.js 🟡 P2 S Eng1
T-3.3.5 Write next 3 new service files in TypeScript — confirm pattern is established 🟡 P2 M Eng1

STORY-3.4 — Publish @soreto/api-client from OpenAPI spec

As a developer on soreto-zoe or soreto-melissa,
I want a typed API client generated from the reverb-backend OpenAPI spec,
so that all consumers share the same typed method signatures and request/response shapes.

Acceptance Criteria: - OpenAPI spec covers all public reverb-backend routes - packages/api-client/ generated from the spec via openapi-typescript or orval - @soreto/api-client published and consumable by soreto-zoe and soreto-melissa - soreto-melissa's service/BaseService.tsx updated to use @soreto/api-client

# Task Priority Effort Owner
T-3.4.1 Install swagger-ui-express + swagger-jsdoc in apps/platform-api/ 🟡 P2 S Eng1
T-3.4.2 Document 10 highest-traffic API routes with OpenAPI JSDoc annotations 🟡 P2 M Eng1
T-3.4.3 Create packages/api-client/ workspace — generate client using openapi-typescript 🟡 P2 M Eng2
T-3.4.4 Replace soreto-melissa/service/BaseService.tsx with @soreto/api-client 🟡 P2 L Eng2
T-3.4.5 Update service files in soreto-melissa one-by-one to use typed methods from @soreto/api-client 🟢 P3 XL Eng2

EPIC-4 — Zoe Modernization

Priority: 🟡 P2 (starts Week 16, runs Weeks 16–24)
Phase: 4 — parallel with Epic 3
Depends on: Epic 2 scaffold complete; Epic 3 @soreto/api-client published
Owner: Eng3
Goal: Eliminate the CRITICAL/HIGH risks in soreto-zoe: complete the Knex upgrade, upgrade Node to 24, convert AMD TypeScript to ES modules, and migrate into the monorepo.


STORY-4.1 — Complete the full Knex upgrade path (0.16 → 3.x)

As a backend engineer on soreto-zoe,
I want Knex upgraded to the latest stable version,
so that the database client receives security patches and supports modern PostgreSQL features.

Acceptance Criteria: - Knex upgraded through all intermediate versions: 0.16.30.21.x0.95.72.x3.x - All existing migrations execute cleanly against staging at each step - No query regressions — integration smoke test passes at each step

# Task Priority Effort Owner
T-4.1.1 Upgrade knex@0.21.x (from Epic 1) → 0.95.7 — review changelog, update breaking changes 🟡 P2 M Eng3
T-4.1.2 Run migrations + smoke test on staging at 0.95.7 🟡 P2 S Eng3
T-4.1.3 Upgrade 0.95.72.x — update knexfile.js, run migrations + smoke test 🟡 P2 M Eng3
T-4.1.4 Upgrade 2.x3.x (current) — run migrations + smoke test 🟡 P2 M Eng3
T-4.1.5 Verify cross-schema behaviour: does zoe schema reference reverb schema directly? (resolves Assumption A6) 🟡 P2 S Eng3

STORY-4.2 — Upgrade soreto-zoe Node 16 → 24

As an engineer on soreto-zoe,
I want soreto-zoe running on Node 24 LTS,
so that the job scheduler receives security patches and is on a supported runtime.

Acceptance Criteria: - soreto-zoe runs on Node 24 in CI and production - puppeteer@9 upgraded to puppeteer@25.x (each processor individually tested) - bull@3 remains or is upgraded to bullmq@5 (decision based on breaking changes) - All affiliate processors execute without errors on Node 24

# Task Priority Effort Owner
T-4.2.1 Test current processors with puppeteer@25.x — identify breaking changes per processor 🟡 P2 M Eng3
T-4.2.2 Fix each broken processor — Puppeteer 25 API changes (e.g. page.goto, page.waitForSelector updated) 🟡 P2 L Eng3
T-4.2.3 Evaluate bull@3bullmq@5: check queue definition API compatibility — upgrade if non-breaking 🟡 P2 M Eng3
T-4.2.4 Upgrade Node: 16 → 18 — run CI, fix failures 🟡 P2 S Eng3
T-4.2.5 Upgrade Node: 18 → 20 → 22 → 24 — run CI at each step 🟡 P2 M Eng3

STORY-4.3 — Convert AMD TypeScript to ES modules

As an engineer on soreto-zoe,
I want the TypeScript build to use standard ES module (or CommonJS) output,
so that the codebase uses idiomatic TypeScript that is understandable and AI-tool-compatible.

Acceptance Criteria: - tsconfig.json updated: module: "NodeNext" (or "CommonJS"), outFile removed - namespace Zoe.* patterns replaced with import/export ES module syntax - Two-tsconfig setup (tsconfig.json + tsconfig.service.json) collapsed to one - Build script produces a single output directory

# Task Priority Effort Owner
T-4.3.1 Audit all namespace Zoe. usages: list every file and interface that needs conversion 🟡 P2 S Eng3
T-4.3.2 Remove "module": "amd" and "outFile" from tsconfig.json 🟡 P2 XS Eng3
T-4.3.3 Convert each namespace Zoe.* file to export interface / export class 🟡 P2 L Eng3
T-4.3.4 Update all import paths to use import { X } from './...' syntax 🟡 P2 M Eng3
T-4.3.5 Collapse tsconfig.service.json into main tsconfig.json 🟡 P2 XS Eng3
T-4.3.6 Confirm single tsc build produces runnable output 🟡 P2 S Eng3

STORY-4.4 — Migrate soreto-zoe into apps/zoe/

As an engineer,
I want soreto-zoe in the monorepo as apps/zoe/,
so that the job scheduler shares tooling with the rest of the platform.

Acceptance Criteria: - Git history preserved - apps/zoe/ builds and deploys from monorepo - local_modules/reverb replaced by @soreto/api-client - Heroku deploys via APP_BASE=apps/zoe

# Task Priority Effort Owner
T-4.4.1 git subtree add to bring soreto-zoe history into soreto-platform 🟡 P2 S Eng3
T-4.4.2 Move into apps/zoe/ and rename workspace to @soreto/zoe 🟡 P2 S Eng3
T-4.4.3 Replace all require('reverb') / require('../local_modules/reverb') with @soreto/api-client 🟡 P2 M Eng3
T-4.4.4 Add Procfile: worker: node dist/worker.js 🟡 P2 XS Eng3
T-4.4.5 Move @soreto/* packages to dependencies (not devDependencies) for Heroku 🟡 P2 XS Eng3
T-4.4.6 Set APP_BASE=apps/zoe Heroku config var 🟡 P2 XS DevOps
T-4.4.7 Verify Heroku deploy — confirm worker processes start and queues drain 🟡 P2 S Eng3 + DevOps

EPIC-5 — Legacy Portal Rewrite

Priority: 🟡 P2 (starts Week 20, runs Weeks 20–36)
Phase: 5 — parallel with Epics 3 and 4
Depends on: Epic 2 scaffold (apps/legacy-portal/) complete; soreto-melissa stable
Owner: Eng2 + Eng3
Goal: Port all reverb-react routes into the Next.js 16 scaffold (apps/legacy-portal/), complete QA, and decommission the Node 10 Heroku app.


STORY-5.1 — Port all admin routes to app/(admin)/

As an admin user of the Soreto platform,
I want all admin dashboard pages to work in the new Next.js 16 portal,
so that I can manage campaigns, clients, fraud, and users without using the legacy portal.

Acceptance Criteria: - All routes listed in docs/migration/REVERB_REACT_PARITY.md under (admin) are ✅ checked off - Each page is a Server Component or Client Component as appropriate (no arbitrary CSR) - State managed via Zustand store — no Redux or Flux references - API calls use @soreto/api-client typed methods - UI components added via npx shadcn@latest add <component> — no PrimeReact imports

# Task Priority Effort Owner
T-5.1.1 Port campaign management pages: campaign list, campaign wizard, campaign version detail 🟡 P2 L Eng2
T-5.1.2 Port client management pages: client list, client overview, client explorer, client dashboard 🟡 P2 L Eng2
T-5.1.3 Port user management pages: user list, user detail, roles 🟡 P2 M Eng2
T-5.1.4 Port fraud management pages 🟡 P2 M Eng3
T-5.1.5 Port segmentation pages 🟡 P2 M Eng3
T-5.1.6 Port reporting pages (using @soreto/api-client for report data) 🟡 P2 L Eng2
T-5.1.7 Port settings pages 🟡 P2 S Eng3
T-5.1.8 Port Zendesk integration page 🟡 P2 S Eng3
T-5.1.9 Port top-user-networks page 🟡 P2 S Eng3
T-5.1.10 Replace moment date formatting with date-fns across all ported pages 🟡 P2 M Eng2

STORY-5.2 — Port all client routes to app/(client)/

As a client user of the Soreto platform,
I want the client dashboard and related pages to work in the new Next.js 16 portal,
so that I can view campaign performance without using the legacy portal.

Acceptance Criteria: - All routes listed in docs/migration/REVERB_REACT_PARITY.md under (client) are ✅ checked off - Role guard in app/(client)/layout.tsx redirects non-client users correctly - Client data loads via @soreto/api-client

# Task Priority Effort Owner
T-5.2.1 Port client dashboard page 🟡 P2 M Eng3
T-5.2.2 Port client reports and stats pages 🟡 P2 M Eng3
T-5.2.3 Port client account/settings pages 🟡 P2 S Eng3
T-5.2.4 Port SaaS onboarding and subscription pages 🟡 P2 M Eng2

STORY-5.3 — Replace @@PLACEHOLDER@@ config with process.env.NEXT_PUBLIC_*

As a DevOps engineer,
I want the legacy portal to use standard Next.js environment variables,
so that a single build artifact can be deployed to any environment without rebuilding.

Acceptance Criteria: - All @@PLACEHOLDER@@ tokens replaced with process.env.NEXT_PUBLIC_* equivalents - .env.example documents all required variables - Heroku config vars set for staging and production - No string-replace-loader or webpack token replacement in the new scaffold

# Task Priority Effort Owner
T-5.3.1 List all @@PLACEHOLDER@@ tokens from reverb-react/src/config/config.js 🟡 P2 XS Eng3
T-5.3.2 Create .env.example in apps/legacy-portal/ with all NEXT_PUBLIC_* equivalents 🟡 P2 S Eng3
T-5.3.3 Set Heroku config vars for each placeholder on staging and production 🟡 P2 S DevOps
T-5.3.4 Update all page/service references from config import → process.env.NEXT_PUBLIC_* 🟡 P2 S Eng3

STORY-5.4 — Full QA pass and gradual traffic cut-over

As a product owner,
I want a complete quality assurance pass before cutting over production traffic,
so that users are not exposed to regressions when the legacy portal is replaced.

Acceptance Criteria: - All items in docs/migration/REVERB_REACT_PARITY.md are ticked ✅ - Admin and client flows tested end-to-end on staging (same reverb-backend as production) - Error monitoring in place (Sentry or equivalent) before cut-over - Traffic cut-over is gradual: 10% → 50% → 100% over 2 weeks - Error rates monitored and cut-over can be reverted instantly (DNS/load balancer toggle)

# Task Priority Effort Owner
T-5.4.1 Full manual QA pass against docs/migration/REVERB_REACT_PARITY.md checklist 🟡 P2 L Eng2 + Eng3
T-5.4.2 Install error monitoring (Sentry @sentry/nextjs) in apps/legacy-portal/ 🟡 P2 S Eng2
T-5.4.3 Cut 10% of production traffic to new portal — monitor for 48 hours 🟡 P2 XS DevOps
T-5.4.4 Cut 50% of production traffic — monitor for 5 days 🟡 P2 XS DevOps
T-5.4.5 Cut 100% of production traffic to apps/legacy-portal/ 🟡 P2 XS DevOps
T-5.4.6 Monitor error rates for 2 weeks post-cut-over 🟡 P2 XS All

STORY-5.5 — Decommission the legacy Heroku reverb-react app

As a DevOps engineer,
I want the original reverb-react Heroku app (Node 10, EOL) taken offline,
so that the platform is no longer running an unsupported runtime in production.

Acceptance Criteria: - All production traffic confirmed on the new legacy-portal app for 2+ weeks - Old reverb-react Heroku app spun down - NEXT_PUBLIC_LEGACY_PORTAL_URL in soreto-melissa updated if URL changed - Old reverb-react source files removed from apps/legacy-portal/ (kept in git history)

# Task Priority Effort Owner
T-5.5.1 Confirm 2-week stability on new portal (zero rollback events) 🟡 P2 XS Eng2
T-5.5.2 Scale old Heroku reverb-react dynos to 0 (keep app for 30-day rollback window) 🟡 P2 XS DevOps
T-5.5.3 Update NEXT_PUBLIC_LEGACY_PORTAL_URL in soreto-melissa .env / Heroku config if URL changed 🟡 P2 XS DevOps
T-5.5.4 Remove old reverb-react source reference files from apps/legacy-portal/ working tree (history kept) 🟢 P3 XS Eng3
T-5.5.5 Delete old Heroku reverb-react app (after 30-day window) 🟢 P3 XS DevOps

Summary: Task Count & Effort by Epic

Epic Stories Tasks Total Effort (AI-assisted) Priority
EPIC-0 Security 4 16 ~1–2 days 🚨 P0
EPIC-1 CI/CD Foundation 8 32 ~2–3 weeks 🔴 P1
EPIC-2 Monorepo Bootstrap 6 48 ~3–4 weeks 🔴 P1
EPIC-3 Backend Modernization 4 24 ~4–6 weeks 🟡 P2
EPIC-4 Zoe Modernization 4 28 ~4–5 weeks 🟡 P2
EPIC-5 Legacy Portal Rewrite 5 35 ~5–8 weeks 🟡 P2
Total 31 183 3–6 months

Epics 3, 4, and 5 run in parallel after Epic 2 is complete, which is what compresses the tail to 3–6 months for a 3-engineer team.