Assist_Design/docs/SYSTEM-ARCHITECTURE.md

20 KiB

System Architecture

Customer Portal - Comprehensive System Design


Table of Contents

  1. System Overview
  2. Architecture Principles
  3. Monorepo Structure
  4. Application Layers
  5. Domain Layer
  6. Technology Stack
  7. Data Flow & Integration
  8. Deployment Architecture

System Overview

The Customer Portal is a modern full-stack application built with clean architecture principles. It provides customers with a self-service portal to manage their telecommunications services, billing, and support cases.

High-Level Architecture

┌─────────────────────────────────────────────────────────────┐
│                     Customer Portal                          │
│                                                              │
│  ┌──────────────┐              ┌──────────────┐            │
│  │              │              │              │            │
│  │   Portal     │──────────────│     BFF      │            │
│  │  (Next.js)   │    REST/     │  (NestJS)    │            │
│  │              │    GraphQL   │              │            │
│  └──────────────┘              └──────┬───────┘            │
│                                       │                     │
│  ┌────────────────────────────────────┴─────────────────┐  │
│  │              Domain Package                           │  │
│  │  (Shared Types, Schemas, Validators)                 │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
                            │
        ┌───────────────────┼───────────────────┐
        │                   │                   │
┌───────▼──────┐    ┌──────▼──────┐    ┌──────▼──────┐
│              │    │             │    │             │
│  Salesforce  │    │    WHMCS    │    │   Freebit   │
│     CRM      │    │   Billing   │    │  SIM Mgmt   │
│              │    │             │    │             │
└──────────────┘    └─────────────┘    └─────────────┘

Key Components

  • Portal (Frontend): Next.js 14+ with App Router, React 18, TypeScript
  • BFF (Backend for Frontend): NestJS with clean architecture layers
  • Domain Package: Framework-agnostic shared types and business logic
  • External Systems: Salesforce (CRM), WHMCS (Billing), Freebit (SIM management)

Architecture Principles

1. Clean Architecture

The system follows clean architecture principles with clear separation of concerns:

  • Presentation Layer: UI components, pages, controllers
  • Application Layer: Use cases, orchestration, business workflows
  • Domain Layer: Business entities, rules, and logic
  • Infrastructure Layer: External integrations, databases, APIs

2. Domain-Driven Design

  • Business domains organized as independent modules
  • Ubiquitous language shared across technical and business teams
  • Bounded contexts with clear interfaces
  • Domain events for cross-domain communication

3. Single Responsibility

  • Each module, service, and component has one clear purpose
  • Clear boundaries between concerns
  • No circular dependencies
  • Minimal coupling between layers

4. Type Safety

  • Strong TypeScript typing throughout the stack
  • Runtime validation with Zod schemas
  • Single source of truth for types
  • Contract-first API design

5. Security First

  • No sensitive data exposure memory:6689308
  • Production-ready error handling
  • PII redaction in logs
  • Row-level security for data access

Monorepo Structure

customer-portal/
├── apps/
│   ├── portal/              # Next.js frontend application
│   └── bff/                 # NestJS backend-for-frontend
├── packages/
│   ├── domain/              # Shared domain types and business logic
│   ├── logging/             # Centralized logging utilities
│   └── validation/          # Shared validation schemas
├── docker/                  # Docker configurations
├── scripts/                 # Build and deployment scripts
└── docs/                    # Documentation

Workspace Organization

The monorepo uses pnpm workspaces for efficient package management:

  • Isolated dependencies: Each app manages its own dependencies
  • Shared packages: Common code reused across apps
  • Atomic changes: Related changes across multiple packages in single commits
  • Type safety: TypeScript project references for fast builds

Application Layers

Portal Architecture (Next.js)

apps/portal/src/
├── app/                     # Next.js App Router
│   ├── (public)/            # Public marketing and auth routes
│   ├── (authenticated)/     # Authenticated portal routes
│   └── api/                 # API routes (if needed)
├── components/              # Shared UI components
│   ├── ui/                  # Basic UI elements (atoms)
│   ├── molecules/           # Component combinations
│   ├── organisms/           # Complex UI sections
│   └── templates/           # Page layouts
├── features/                # Feature modules
│   ├── auth/                # Authentication
│   ├── billing/             # Invoices and payments
│   ├── catalog/             # Product catalog
│   ├── orders/              # Order management
│   ├── subscriptions/       # Service management
│   ├── support/             # Support cases
│   └── dashboard/           # Customer dashboard
├── lib/                     # Core utilities
│   ├── api/                 # API client with Zod validation
│   ├── hooks/               # Shared React hooks
│   └── utils/               # Utility functions
├── providers/               # React context providers
└── styles/                  # Global styles and design tokens

Key Principles:

  • Feature-First Organization: Related code grouped by business feature
  • Atomic Design: UI components organized hierarchically
  • Server-First: Leverage Next.js server components where possible
  • Type Safety: Full TypeScript coverage with strict mode
  • Performance: Code splitting, lazy loading, optimized bundles

BFF Architecture (NestJS)

apps/bff/src/
├── modules/                 # Feature modules
│   ├── auth/                # Authentication
│   ├── billing/             # Invoice and payment management
│   ├── catalog/             # Product catalog
│   ├── orders/              # Order processing
│   ├── subscriptions/       # Subscription management
│   └── support/             # Support cases
├── integrations/            # External service integrations
│   ├── salesforce/          # Salesforce CRM
│   │   ├── services/        # API services
│   │   ├── utils/           # Query builders (SOQL)
│   │   └── events/          # Platform events (Pub/Sub)
│   ├── whmcs/               # WHMCS billing
│   │   ├── services/        # API services
│   │   └── utils/           # Request builders
│   └── freebit/             # Freebit SIM management
│       └── services/        # API services
├── core/                    # Core services
│   ├── config/              # Configuration management
│   ├── logging/             # Logging setup
│   └── database/            # Database connections
├── common/                  # Shared resources
│   ├── guards/              # Auth guards
│   ├── interceptors/        # Request/response interceptors
│   ├── filters/             # Exception filters
│   └── pipes/               # Validation pipes
└── main.ts                  # Application entry point

Key Principles:

  • Modular Architecture: Features organized as NestJS modules
  • Integration Layer: External services abstracted behind clean interfaces
  • Single Transformation: Domain mappers transform data once
  • Infrastructure Concerns: Separated from business logic
  • Event-Driven: Platform Events for Salesforce integration

Domain Layer

The domain package provides framework-agnostic types and business logic shared across applications.

Domain Structure

packages/domain/
├── billing/
│   ├── contract.ts              # Normalized types (provider-agnostic)
│   ├── schema.ts                # Zod validation schemas
│   └── providers/               # Provider-specific adapters
│       └── whmcs/
│           ├── raw.types.ts     # WHMCS API response types
│           └── mapper.ts        # Transform WHMCS → Domain
├── subscriptions/
│   ├── contract.ts
│   ├── schema.ts
│   └── providers/
│       └── whmcs/
├── orders/
│   ├── contract.ts
│   ├── schema.ts
│   └── providers/
│       ├── salesforce/          # Read orders from Salesforce
│       └── whmcs/               # Create orders in WHMCS
├── catalog/
│   ├── contract.ts
│   ├── schema.ts
│   └── providers/
│       └── salesforce/          # Product catalog
├── customer/
│   ├── contract.ts
│   ├── schema.ts
│   └── providers/
│       ├── salesforce/
│       └── whmcs/
├── sim/
│   ├── contract.ts
│   ├── schema.ts
│   └── providers/
│       └── freebit/             # SIM management
└── common/
    ├── types.ts                 # Common types (Address, Money, etc.)
    ├── api.ts                   # API response wrappers
    └── schema.ts                # Common schemas

Provider Pattern

The domain layer uses a provider pattern to abstract external system details:

// Domain contract (provider-agnostic)
export interface Invoice {
  id: number;
  status: InvoiceStatus;
  amount: Money;
  dueDate: Date;
  // ... normalized fields
}

// Provider-specific raw type
export interface WhmcsInvoiceRaw {
  invoiceid: string;
  status: string;
  total: string;
  // ... WHMCS-specific fields
}

// Provider mapper
export function transformWhmcsInvoice(raw: unknown): Invoice {
  const validated = whmcsInvoiceRawSchema.parse(raw);
  
  const result: Invoice = {
    id: parseInt(validated.invoiceid),
    status: mapWhmcsStatus(validated.status),
    amount: {
      value: parseFloat(validated.total),
      currency: validated.currencycode
    },
    // ... map all fields
  };
  
  return invoiceSchema.parse(result); // Validate domain model
}

Benefits:

  • Provider Isolation: External API details don't leak into application code
  • Single Transformation: Map once using domain mappers
  • Type Safety: Runtime validation at boundaries
  • Testability: Easy to mock and test transformations
  • Scalability: Add new providers without changing application code

Technology Stack

Frontend

  • Framework: Next.js 14+ (App Router)
  • Language: TypeScript 5+
  • UI Library: React 18
  • Styling: Tailwind CSS
  • State Management: React Query (TanStack Query)
  • Form Handling: React Hook Form
  • Validation: Zod
  • HTTP Client: Fetch API with Zod validation

Backend

  • Framework: NestJS 10+
  • Language: TypeScript 5+
  • Runtime: Node.js 20+
  • Validation: Zod + class-validator
  • ORM: Prisma
  • Caching: Redis
  • Queue: BullMQ (Redis-backed)
  • Logging: Pino
  • Testing: Jest

Infrastructure

  • Database: PostgreSQL 15+
  • Cache: Redis 7+
  • Container: Docker
  • Orchestration: Docker Compose
  • Reverse Proxy: Nginx
  • CI/CD: GitHub Actions (assumed)

External Services

  • Salesforce: CRM and order management
    • REST API
    • Platform Events (Pub/Sub gRPC)
    • SOQL queries
  • WHMCS: Billing and provisioning
    • REST API
    • Webhooks for events
  • Freebit: SIM card management
    • REST API

Data Flow & Integration

Order Processing Flow

1. Customer creates order in Portal
   │
   ├─> Portal validates selections
   │
   └─> POST /api/orders → BFF

2. BFF creates Salesforce Order
   │
   ├─> Validates customer data
   ├─> Creates Order record
   ├─> Creates OrderItems
   └─> Status: Draft

3. Customer/Admin approves Order in Salesforce
   │
   └─> Record-Triggered Flow publishes OrderProvisionRequested__e

4. BFF receives Platform Event
   │
   ├─> PlatformEventsSubscriber enqueues job
   └─> BullMQ provisioning queue

5. Provisioning Worker processes job
   │
   ├─> OrderFulfillmentService orchestrates
   ├─> Creates WHMCS order (AddOrder)
   ├─> Accepts WHMCS order (AcceptOrder → creates services)
   └─> Updates Salesforce Order status

6. Customer sees updated status in Portal
   │
   └─> GET /api/orders/{id} → Shows provisioned services

Catalog Data Flow

┌──────────────┐
│  Salesforce  │
│  Product2    │
└──────┬───────┘
       │
       │ SOQL Query
       │
┌──────▼──────────────────────────┐
│  BFF Catalog Service            │
│  • Query products               │
│  • Filter by Portal_Catalog__c  │
│  • Transform with domain mapper │
└──────┬──────────────────────────┘
       │
       │ Domain Types
       │
┌──────▼───────────────┐
│  Cache (Redis)       │
│  TTL: 5-15 min       │
└──────┬───────────────┘
       │
       │ REST API
       │
┌──────▼───────┐
│   Portal     │
│   Catalog    │
└──────────────┘

Authentication Flow

1. User submits login credentials
   │
   ├─> Portal: POST /auth/login
   │
2. BFF validates credentials
   │
   ├─> Check against database
   ├─> Verify WHMCS account link (optional)
   │
3. Issue tokens
   │
   ├─> Access Token (JWT, 15 min)
   ├─> Refresh Token (stored in Redis, 7 days)
   │
4. Return tokens to client
   │
   ├─> Access Token in response body
   ├─> Refresh Token in httpOnly cookie
   │
5. Client makes authenticated requests
   │
   ├─> Include Access Token in Authorization header
   │
6. Token refresh
   │
   ├─> Portal: POST /auth/refresh
   ├─> BFF validates Refresh Token
   ├─> Issues new Access Token
   └─> Rotates Refresh Token (token family)

Deployment Architecture

Production Environment

┌─────────────────────────────────────────────────────────┐
│                     Load Balancer                        │
└────────────────────┬────────────────────────────────────┘
                     │
        ┌────────────┴────────────┐
        │                         │
┌───────▼────────┐      ┌─────────▼────────┐
│  Portal        │      │  BFF             │
│  (Next.js)     │      │  (NestJS)        │
│  • SSR/SSG     │      │  • REST API      │
│  • Static      │      │  • WebSockets    │
└───────┬────────┘      └─────────┬────────┘
        │                         │
        │              ┌──────────┴──────────┐
        │              │                     │
        │      ┌───────▼────────┐   ┌───────▼────────┐
        │      │  PostgreSQL    │   │  Redis         │
        │      │  (Primary DB)  │   │  (Cache+Queue) │
        │      └────────────────┘   └────────────────┘
        │
┌───────┴──────────────────────────────────────┐
│         External Services                    │
│  • Salesforce (CRM)                          │
│  • WHMCS (Billing)                           │
│  • Freebit (SIM Management)                  │
└──────────────────────────────────────────────┘

Scalability Considerations

  • Horizontal Scaling: Multiple BFF instances behind load balancer
  • Stateless Design: JWT tokens, no server-side sessions
  • Redis Clustering: Distributed cache and queue
  • Database Read Replicas: Separate read/write connections
  • CDN: Static assets served via CDN
  • Queue Workers: Separate processes for background jobs

Monitoring & Observability

  • Structured Logging: Pino with correlation IDs
  • Metrics: Response times, error rates, API latency
  • Health Checks: /health endpoints for both apps
  • Error Tracking: Centralized error logging
  • Performance Monitoring: Real-time performance metrics

Design Decisions

Why Monorepo?

  • Shared Code: Easy to share types, utilities, and business logic
  • Atomic Changes: Update frontend and backend in sync
  • Consistent Tooling: Single ESLint, TypeScript, and Prettier config
  • Developer Experience: Single repository, single checkout

Why BFF Pattern?

  • Frontend-Specific: API tailored to portal needs
  • Aggregation: Combine multiple backend services
  • Security: Backend handles sensitive operations
  • Performance: Caching and optimization close to frontend

Why Domain Package?

  • Single Source of Truth: Types defined once, used everywhere
  • Provider Abstraction: External systems isolated from application
  • Type Safety: Runtime validation with Zod
  • Testability: Business logic separate from infrastructure

Why Platform Events (Not Webhooks)?

  • Security: No inbound connections from Salesforce
  • Reliability: Durable replay with replayId tracking
  • Scalability: High-volume event processing
  • Real-time: Near-instant event delivery

Future Considerations

Planned Enhancements

  • GraphQL API: Consider GraphQL for complex data fetching
  • Event Sourcing: Event log for audit trail
  • CQRS: Separate read/write models for complex domains
  • Microservices: Split BFF into domain-specific services
  • Real-time Updates: WebSocket for live order status

Technical Debt

  • Legacy Migration: Some validation logic being migrated to domain
  • Test Coverage: Increase unit and integration test coverage
  • Performance: Optimize database queries and caching strategy
  • Documentation: Continue documenting API contracts and flows

Last Updated: October 2025
Status: Active - Production System