# System Architecture **Customer Portal - Comprehensive System Design** --- ## Table of Contents 1. [System Overview](#system-overview) 2. [Architecture Principles](#architecture-principles) 3. [Monorepo Structure](#monorepo-structure) 4. [Application Layers](#application-layers) 5. [Domain Layer](#domain-layer) 6. [Technology Stack](#technology-stack) 7. [Data Flow & Integration](#data-flow--integration) 8. [Deployment Architecture](#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: ```typescript // 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