Assist_Design/docs/architecture/system-overview.md
barsa a3dbd07183 Enhance ESLint Rules and Refactor Domain Imports
- Updated ESLint configuration to enforce stricter import rules for the @customer-portal/domain package, promoting better import hygiene and preventing deep imports.
- Refactored various files across the BFF and portal applications to comply with the new import rules, ensuring that only the appropriate modules are imported from the domain.
- Cleaned up unused imports and optimized code structure for improved maintainability and clarity.
- Updated documentation to reflect changes in import practices and domain structure.
2025-12-26 14:53:03 +09:00

8.3 KiB

Customer Portal Architecture

🏗️ System Overview

The Customer Portal is a modern monorepo with clean separation between frontend (Next.js) and backend (NestJS), designed for maintainability and scalability.

High-Level Structure

apps/
  portal/              # Next.js frontend
  bff/                 # NestJS Backend-for-Frontend
packages/
  domain/              # Pure domain types, validation schemas, and utilities (isomorphic)

🎯 Architecture Principles

1. Separation of Concerns

  • Dev vs Prod: Clear separation with appropriate tooling
  • Services vs Apps: Development runs apps locally, production containerizes everything
  • Configuration vs Code: Environment variables for configuration, code for logic

2. Single Source of Truth

  • One environment template: .env.example
  • One Docker Compose per environment
  • One script per operation type

3. Clean Dependencies

  • Portal: Uses @/lib/* for shared utilities and services
  • BFF: Feature-aligned modules with shared concerns in src/common/
  • Domain: Framework-agnostic types and utilities

🚀 Portal (Next.js) Architecture

src/
  app/                 # App Router routes
  components/          # Design system (atomic design)
    atoms/             # Basic UI elements
    molecules/         # Component combinations
    organisms/         # Complex UI sections
    templates/         # Page layouts
  features/            # Feature modules (auth, billing, etc.)
  lib/                 # Core utilities and services
    api/               # Zod-aware fetch client + helpers
    hooks/             # Shared React hooks
    utils/             # Utility functions
  providers/           # Context providers
  styles/              # Global styles

Conventions

  • Use @/lib/* for shared frontend utilities and services
  • Feature modules own their components/, hooks/, services/, and types/
  • Cross-feature UI belongs in components/ (atomic design)
  • Avoid duplicate layers - no core/ or shared/ inside apps

🔧 BFF (NestJS) Architecture

src/
  modules/             # Feature-aligned modules
    auth/              # Authentication and authorization
    users/             # User management
    me-status/         # Aggregated customer status (dashboard + gating signals)
    id-mappings/       # Portal-WHMCS-Salesforce ID mappings
    services/          # Services catalog (browsing/purchasing)
    orders/            # Order creation and fulfillment
    invoices/          # Invoice management
    subscriptions/     # Service and subscription management
    currency/          # Currency handling
    support/           # Support case management
    realtime/          # Server-Sent Events API
    verification/      # ID verification
    notifications/     # User notifications
    health/            # Health check endpoints
  core/                # Core services and utilities
  infra/               # Infrastructure (database, cache, queue, email)
  integrations/        # External service integrations
    salesforce/        # Salesforce CRM integration
    whmcs/             # WHMCS billing integration
    freebit/           # Freebit SIM provider integration
    sftp/              # SFTP file transfer
  main.ts              # Application entry point

Conventions

  • Prefer modules/* over flat directories per domain
  • Keep DTOs and validators in-module
  • Reuse packages/domain for domain types
  • External integrations in dedicated modules

API Boundary: Public vs Account

  • Public APIs (/api/public/*): strictly non-personalized endpoints intended for marketing pages and unauthenticated browsing.
  • Account APIs (/api/account/*): authenticated endpoints that may return personalized responses (e.g. eligibility-gated catalogs, SIM family discount availability).

📦 Shared Packages

Domain Package (packages/domain/)

The domain package is the single source of truth for shared types, validation schemas, and utilities across both the BFF and Portal applications.

packages/domain/
├── auth/           # Authentication types and validation
├── billing/        # Invoice and payment types
├── services/       # Services catalog types
├── checkout/       # Checkout flow types
├── common/         # Shared utilities and base types
├── customer/       # Customer profile types
├── dashboard/      # Dashboard data types
├── mappings/       # ID mapping types (Portal-WHMCS-SF)
├── notifications/  # Notification types
├── opportunity/    # Salesforce opportunity types
├── orders/         # Order types and Salesforce mappings
├── payments/       # Payment method types
├── providers/      # Provider-specific type definitions
├── realtime/       # SSE event types
├── salesforce/     # Salesforce API types
├── sim/            # SIM lifecycle and Freebit types
├── subscriptions/  # Subscription types
├── support/        # Support case types
├── toolkit/        # Utility functions
└── index.ts        # Public exports

Key Principles

  • Framework-agnostic: No NestJS or React dependencies
  • Isomorphic: Works in both Node.js and browser environments
  • Zod-first validation: Schemas defined with Zod for runtime validation
  • Provider mappers: Transform external API responses to domain types

Usage

Import via module entrypoints:

import { invoiceSchema, type Invoice } from "@customer-portal/domain/billing";
import { orderSummarySchema, type OrderSummary } from "@customer-portal/domain/orders";
import { SIM_STATUS } from "@customer-portal/domain/sim";

Integration with BFF

The BFF integration layer (apps/bff/src/integrations/) uses domain mappers to transform raw provider data:

External API → Raw Response → Domain Mapper → Domain Type → Use Everywhere

This ensures a single transformation point and consistent types across the application.

Logging

Centralized logging is implemented in the BFF using nestjs-pino:

  • Structured JSON logging for production
  • Correlation IDs for request tracing
  • Automatic PII redaction for security

🔗 Integration Architecture

API Client

  • Implementation: Fetch wrapper using shared Zod schemas from @customer-portal/domain
  • Features: CSRF protection, auth handling, consistent ApiResponse helpers
  • Location: apps/portal/src/lib/api/

External Services

  • WHMCS: Billing system integration
  • Salesforce: CRM and order management
  • Redis: Caching and session storage
  • PostgreSQL: Primary data store

🔒 Security Architecture

Authentication Flow

  • Portal-native authentication with JWT tokens
  • Optional MFA support
  • Secure token rotation with Redis backing

Error Handling

  • Never leak sensitive details to end users memory:6689308
  • Centralized error mapping to user-friendly messages
  • Comprehensive audit trails

Data Protection

  • PII minimization with encryption at rest/in transit
  • Row-level security (users can only access their data)
  • Idempotency keys on all mutating operations

🚀 Development Workflow

Path Aliases

  • Portal: @/*, @/lib/*, @/features/*, @/components/*
  • BFF: @/* mapped to apps/bff/src
  • Domain: Import via @customer-portal/domain

Code Quality

  • Strict TypeScript rules enforced repository-wide
  • ESLint and Prettier for consistent formatting
  • Pre-commit hooks for quality gates

Domain Build Hygiene

The domain package (packages/domain) is consumed via committed dist/ outputs.

  • Build: pnpm domain:build
  • Verify dist drift (CI-friendly): pnpm domain:check-dist

📈 Performance & Scalability

Caching Strategy

  • Invoices: 60-120s per page; bust on WHMCS webhook
  • Cases: 30-60s; bust after create/update
  • Catalog: 5-15m; manual bust on changes
  • Keys include user_id to prevent cross-user leakage

Database Optimization

  • Connection pooling with Prisma
  • Proper indexing on frequently queried fields
  • Optional mirrors for external system data

This architecture supports clean, maintainable code with clear separation of concerns and production-ready security.