Skip to main content

Case Study: Scalable Frontend Architecture for a Multi-Team SaaS Platform

1. Context & Constraints

Product Context

  • B2B SaaS platform with:

    • SEO-critical marketing pages

    • Authenticated dashboard

    • Admin & reporting tools

  • Users expect:

    • fast initial load

    • responsive interactions

    • consistent UI across features

Team & Org Constraints

  • 5 frontend teams

  • Weekly production releases

  • Shared design system

  • Backend owned by a separate team

  • No dedicated frontend platform team initially

Technical Constraints

  • React + Next.js (App Router)

  • Existing codebase with:

    • mixed rendering strategies

    • ad-hoc state management

    • shared utilities growing uncontrollably


2. Problems Identified

Before proposing solutions, I analyzed systemic pain points:

Structural Problems

  • Feature code tightly coupled through shared utilities

  • No clear ownership boundaries

  • High refactor risk

Data & State Issues

  • Server data duplicated in global client state

  • Inconsistent caching rules

  • Frequent data synchronization bugs

Performance Issues

  • Hydration cost across entire app

  • Bundle size growing without budget

  • No objective performance metrics

Organizational Issues

  • Architectural decisions undocumented

  • Repeated debates about “best” patterns

  • Onboarding new engineers was slow and error-prone


3. Architectural Goals

I defined explicit goals before designing anything:

  1. Reduce future change cost

  2. Enable multiple teams to work safely in parallel

  3. Make architecture visible and enforceable

  4. Treat performance as a system constraint

  5. Encode decisions so they survive team changes


4. Key Architectural Decisions (ADRs)

ADR-001: Feature-Based Architecture over Layered Architecture

Decision

Adopt a feature-based architecture as the primary organizing principle.

Alternatives Considered

  • Layered (components, hooks, services)

  • Domain-only structure

Why Rejected

  • Layered structure optimized reuse, not change

  • Encouraged cross-feature coupling

Trade-offs

  • Some duplication accepted early

  • Requires discipline around boundaries


ADR-002: Modular Monolith over Micro-Frontends

Decision

Use a modular monolith with enforced boundaries instead of micro-frontends.

Why

  • Teams were small enough to coordinate releases

  • Micro-frontends would add runtime and performance complexity

  • Shared UX consistency was critical

Trade-offs

  • Shared release cadence

  • Requires strong governance


ADR-003: Server State Is Not Client State

Decision

All backend-owned data is treated as server state, not global client state.

Rules Introduced

  • Server data fetched & cached via a dedicated data layer

  • Client global state limited to:

    • auth session

    • feature flags

    • theme

Benefits

  • Eliminated duplicated sources of truth

  • Reduced state-related bugs


ADR-004: Route-Level Rendering Strategy

Decision

Rendering strategy chosen per route, not globally.

Route Type

Strategy

Marketing pages

SSG

Auth pages

SSR

Dashboard

CSR + streaming

Reports

SSR + caching

Trade-offs

  • Slightly higher architectural complexity

  • Significantly better performance predictability


5. System Design Overview

High-Level Structure

App Shell
├── Features
│ ├── Auth
│ ├── Billing
│ ├── Dashboard
│ └──Admin
├── Entities
│ ├──User
│ ├── Organization
│ └──Subscription
├── Shared
│ ├── UI Primitives
│ ├── Design Tokens
│ ├── Platform Utilities

Dependency Rules

  • Features may depend on Entities

  • Entities never depend on Features

  • Shared depends on nothing

  • No cross-feature imports allowed

These rules were enforced via linting and TypeScript path constraints.


6. Design System & UI Architecture

Design System Principles

  • Token-first (semantic tokens, not raw values)

  • Accessible by default

  • Composition over configuration

  • Versioned with deprecation policies

Component API Example

Instead of:

<Button color="blue" size="14px" />

We standardized:

<Button intent="primary" size="md" />

This:

  • prevented invalid combinations

  • simplified theming

  • enforced accessibility defaults


7. Performance Architecture

Performance Budgets Defined

- LCP ≤ 2.5s
- INP ≤ 200ms
- Initial JS ≤ 170KB (gzipped)
- CLS ≤ 0.1

Architectural Measures

  • Partial hydration for dashboard widgets

  • Server components for data orchestration

  • Third-party scripts isolated and deferred

  • Bundle size monitored in CI

Key Shift

Performance discussions moved from opinions to budget trade-offs.


8. Reliability & Error Architecture

Error Taxonomy Introduced

  • User errors (validation, permissions)

  • Network errors

  • Server errors

  • System errors

Error Boundary Strategy

  • Feature-level isolation

  • Local recovery where possible

  • Global fallback only for fatal errors

This reduced:

  • blank screens

  • global crashes

  • debugging ambiguity


9. Governance & Team Enablement

Architecture Artifacts Created

  • Architecture Decision Records (ADRs)

  • Frontend architecture standards

  • Design system governance docs

  • Migration playbooks

Enablement Tactics

  • Code generators for new features

  • Architecture office hours

  • RFC-based change proposals

Outcome

Teams followed architecture because it was easy and safe, not because it was mandated.


10. Outcomes & Impact

Quantitative

  • Reduced onboarding time for new engineers

  • Fewer regressions related to state and rendering

  • Stabilized bundle size growth

  • Improved Core Web Vitals consistency

Qualitative

  • Fewer architectural debates

  • Clear ownership boundaries

  • Higher confidence in refactoring

  • Improved collaboration with backend and design


11. What I Would Revisit Today

With hindsight:

  • Introduce streaming earlier for data-heavy dashboards

  • Formalize ownership maps sooner

  • Automate more architectural checks earlier

This reflects learning, not regret.


12. Key Takeaways

  • Frontend architecture is about durable decisions

  • Boundaries matter more than abstractions

  • Performance must be budgeted, not optimized later

  • Governance enables speed when done right

  • Architecture succeeds only if teams trust it


Why This Case Study Works in a Portfolio

It demonstrates:

  • System-level thinking

  • Trade-off awareness

  • Real-world constraints

  • Leadership without authority

  • Responsibility beyond code