Skip to content

← Back to README

G. Frontend Architecture Assessment


Two Frontends, One Being Modernized

The Soreto ecosystem has two separate frontend applications, both in active development:

App Status Tech (current) Tech (target) Purpose
reverb-react 🔄 Modernizing → Next.js 16 React 17/16, Babel 6, Webpack 4, Node 10 Next.js 16, React 19, TypeScript 6, Node 24 Admin + client portal (being modernized)
soreto-melissa ✅ Active development Next.js 13, React 18, TypeScript Next.js 16, React 19 Admin + client portal (new platform UI)

Both applications are live simultaneously and cross-reference each other. reverb-react is undergoing a controlled rewrite to Next.js 16 inside apps/legacy-portal/ — parallel to ongoing melissa development.


reverb-react Assessment

Cannot Be Upgraded In-Place — Rewrite Required

Attempting an in-place upgrade of reverb-react would require all of the following simultaneously, with compounding risk: 1. Babel 6 → Babel 7 (all presets and plugins must be updated) 2. Webpack 4 → Webpack 5 or Vite (config rewrite) 3. React 16/17 → React 19 (hooks audit, Concurrent Mode compatibility, React 19 new APIs) 4. react-router@3 + react-router-dom@4react-router@7 (two separate mismatches; complete API rewrite across 4 major versions) 5. Redux 3 → Redux Toolkit (Redux 5 requires a different pattern) 6. Remove Flux (Flux was abandoned by Meta in 2019) 7. @@PLACEHOLDER@@ config → proper env vars 8. Node 10 → 24

The correct approach is a controlled rewrite to Next.js 16 — starting on a clean scaffold inside apps/legacy-portal/, porting business logic while discarding the outdated tooling layer entirely. This avoids all compounding upgrade risks.

Recommendation: Modernize reverb-react to Next.js 16 + React 19 via a controlled rewrite inside apps/legacy-portal/. Do not attempt an in-place upgrade — the gaps are too large to bridge incrementally. See F — Version Standardization and K — Target Architecture for the full modernization target and effort estimate.

Next.js 16 Rewrite — Route & Feature Scope

The following areas need porting from the current reverb-react codebase into the Next.js 16 App Router scaffold. This is the input for the Phase 5 rewrite scope:

[ ] Admin dashboard (global)
[ ] Client dashboard and analytics
[ ] Campaign management
[ ] Campaign version management
[ ] A/B test management
[ ] Reward pool management
[ ] User management
[ ] Email template management
[ ] Affiliate configuration
[ ] Marketplace management
[ ] Report generation and export
[ ] User segmentation
[ ] By-channel analytics (BiAnalytics)
[ ] Zendesk lead management
[ ] Social sharing configuration
[ ] Asset management
[ ] Client user management

soreto-melissa Assessment

Architecture: Next.js 13 App Router

soreto-melissa correctly uses the Next.js 13 App Router with route groups:

app/
├── (client)/     ← role-guarded: CLIENT_USER, SAAS
├── (full-page)/  ← auth, subscribe, public
├── (landing)/    ← marketing
└── (main)/       ← admin routes

The role guard in (client)/layout.tsx is implemented as a client component that checks the StoreContext and redirects non-authorized users. This is appropriate for an admin portal.

SSR vs CSR Tradeoffs

Pattern Used in Melissa Assessment
Server Components Layouts, metadata ✓ Correct — static structure
Client Components ('use client') Interactive pages ✓ Correct — data-dependent pages
Server-side data fetching Not observed ⚠️ May be missing — some pages could fetch on server
API routes Not observed ⚠️ All calls go to reverb-backend directly

Opportunity: Admin dashboard pages that load large data tables could benefit from server-side data fetching (reducing client-side bundle size and first paint time). Currently all data fetching appears to be client-side via the service layer.

Next.js Version: 13.4.9 → Target 16

Version Status Notes
13.4.9 (current) Security patches limited Stable but 3 majors behind
14.x Stable App Router stable, Server Actions added
15.x Stable async/await request APIs, improved caching
16.2.6 (latest) Current stable ~87% faster startup, Turbopack default, AI-ready dev tools

Upgrade path: 13 → 14 is lower risk (image component change, minor breaking changes). 14 → 15 involves changes to how cookies(), headers(), and searchParams are accessed (now async). 15 → 16 requires reviewing Turbopack compatibility and updated error boundaries. Do not skip major versions. Start with 14 in the next 3 months.

State Management: React Context

The current Context approach is appropriate for this use case:

// store/Context.ts
type StoreContextType = {
  isAuthenticated: boolean;
  user: User | null;
  isAuthLoading: boolean;
  selectedCurrency: string;
  login: (email: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
  passwordlessLogin: (email: string, token: string) => Promise<void>;
  changeSelectedCurrency: (currency: string) => void;
};

Auth state, user profile, and currency selection are the right things to put in Context. This is not over-engineered.

Watch for: As melissa grows, if multiple separate domains (campaigns, rewards, etc.) start needing global state, Context will become insufficient. At that point, consider Zustand (lightweight) or TanStack Query (for server state). Do not introduce Redux — it would be a regression from the current clean approach.

UI Library: PrimeReact 10.2.1 (current) → shadcn/ui + Tailwind CSS v4 (target)

soreto-melissa currently uses PrimeReact 10.2.1 with primeflex@3.3.0. For the monorepo migration, both portals (apps/platform-ui/ and apps/legacy-portal/) are targeting shadcn/ui (CLI v4) + Tailwind CSS 4.2.0 as the unified UI stack. This eliminates the PrimeReact dependency and gives both portals identical tooling, making the @soreto/ui shared component package viable.

reverb-react legacy: primereact@1.5.1 — 9 major versions behind melissa, completely incompatible APIs. Not an upgrade path — both mismatches are eliminated when legacy-portal is rewritten from scratch on shadcn/ui.


Why shadcn/ui + Tailwind CSS v4

This is the recommended UI stack for both apps/platform-ui/ (melissa migration) and apps/legacy-portal/ (reverb-react rewrite). The decision is motivated by developer velocity, AI-assisted development gains, and long-term maintainability.

Tailwind CSS 4.2.0 — What Changed

Tailwind v4 is a ground-up rewrite with a CSS-first configuration model:

Capability Tailwind v3 Tailwind v4.2
Configuration tailwind.config.js (JavaScript) @theme directive in CSS — no config file
Full build speed baseline 5× faster
Incremental rebuild baseline 100× faster (critical for dev server)
Color system HSL OKLCH — perceptually uniform, better dark mode
Cascade control No layers CSS cascade layers — predictable specificity
Custom properties Manual @property — registered, animated
Webpack support Plugin required First-class webpack plugin (v4.2)
/* Tailwind v4: all design tokens in CSS — no tailwind.config.js */
@import "tailwindcss";

@theme {
  --color-brand: oklch(55% 0.2 260);
  --font-sans: "Inter", sans-serif;
  --radius: 0.5rem;
}

shadcn/ui CLI v4 — What It Provides

shadcn/ui is not a component library — it is a component registry and CLI. Components are copied directly into your codebase via the CLI. This means:

  • No package version to pin, upgrade, or conflict with — components are your code
  • No runtime overhead — pure Radix UI primitives + utility CSS
  • Full customization — modify any component file directly without fighting library internals
  • AI-agent nativeshadcn/skills (CLI v4, March 2026) gives coding agents (including Claude) direct context on component APIs, registry patterns, and Radix primitives
# Initialize project — creates components.json, adds Tailwind v4 config
npx shadcn@latest init

# Add a component — copies source into components/ui/
npx shadcn@latest add button
npx shadcn@latest add data-table
npx shadcn@latest add form

Components land in components/ui/ as plain TypeScript files you own completely.

Developer Velocity vs PrimeReact

Dimension PrimeReact 10 shadcn/ui + Tailwind v4
Version lock-in Package version pinned — 9 major versions behind reverb-react No version — components live in your repo
Customization Override via CSS specificity battles Edit the component file directly
Bundle size Full library imported even if unused Only the components you add
Accessibility Good (PrimeReact 10+) Built in — Radix UI primitives (WAI-ARIA, keyboard, focus)
Dark mode Theme via CSS variables Tailwind v4 OKLCH color system — automatic
AI-assisted work No agent context shadcn/skills gives agents component API context
Design system PrimeFlex utility layer (separate dep) Tailwind v4 — unified, no separate utility package
Shared across portals Requires both apps on same PrimeReact major @soreto/ui package: shared shadcn components, no version drift

Impact on @soreto/ui Package

With both portals on shadcn/ui + Tailwind v4, the @soreto/ui shared package becomes a component extension library — custom Soreto-specific wrappers built on top of shadcn primitives, shared across both apps with zero version compatibility concerns.


Frontend Modernization Roadmap

Phase 1: stabilize melissa (0–3 months)

  • [ ] Add CI/CD pipeline (GitHub Actions: lint + type-check + test + build)
  • [ ] Confirm deployment target and document it
  • [ ] Fix jest.setup.ts reference (ensure file exists)
  • [ ] Remove or justify babel.config.js (may conflict with SWC)
  • [ ] Replace @rjsf/core@6.0.0-beta.10 with stable version when available
  • [ ] Evaluate react-force-graph vs react-force-graph-2d — remove unused one

Phase 2: reverb-react modernization (3–9 months)

  • [ ] Stand up Next.js 16 scaffold in apps/legacy-portal/app/ at root, no src/, Node 24, React 19, TypeScript 6
  • [ ] Create app/(admin)/ and app/(client)/ route groups with guarded layouts
  • [ ] Build store/ with Zustand (replaces Redux 3 + Flux — business logic preserved)
  • [ ] Build service/ layer using @soreto/api-client (replaces reverb-react's hand-rolled service utilities)
  • [ ] Add Tailwind CSS v4.2 — CSS-first @theme directive in globals.css, no tailwind.config.js
  • [ ] Run npx shadcn@latest init — creates components.json, wires Tailwind v4
  • [ ] Build components/ with shadcn/ui (CLI v4) — components added via npx shadcn@latest add <component>
  • [ ] Replace @@PLACEHOLDER@@ tokens → process.env.NEXT_PUBLIC_* in .env.example
  • [ ] Deploy WAF in front of existing Heroku reverb-react app during transition

Phase 3: cut over and decommission (9–12 months)

  • [ ] Cut over traffic from old Heroku reverb-react to modernized apps/legacy-portal/
  • [ ] Decommission original Heroku reverb-react app
  • [ ] Remove NEXT_PUBLIC_LEGACY_PORTAL_URL links pointing to old app from melissa's constants.ts

Do Not: Next.js for reverb-backend

reverb-backend is a pure API server. There is no benefit to adding Next.js API routes as a proxy — this would add complexity and a new process without providing value. The reverb-backend Express server should remain a dedicated API server.