barsa 928ad18d7e Refactor User Profile Management and Enhance Authentication Flow
- Improved `accountService` to streamline user profile management, including enhanced fetching and updating mechanisms for profile and address information.
- Updated `auth.store` to optimize client-side authentication state handling, ensuring a more robust login, signup, and session management process.
- Centralized exports for authentication services in `auth/api/index.ts` for better organization and accessibility.
- Enhanced overall service architecture by refining API services related to billing and checkout functionalities, promoting maintainability and clarity across the portal features.
2025-12-29 18:21:48 +09:00

Customer Portal Project

A modern customer portal where users can self-register, log in, browse & buy subscriptions, view/pay invoices, and manage support cases.

Architecture Overview

Systems of Record

  • WHMCS: Billing, subscriptions, invoices, and authoritative address storage
  • Salesforce: CRM (Accounts, Contacts, Cases) and order address snapshots
  • Portal: Modern UI with backend for frontend (BFF) architecture

Identity Management

  • Portal-native authentication (email + password, optional MFA)
  • One-time WHMCS user verification with forced password reset
  • User mapping: user_id ↔ whmcs_client_id ↔ sf_contact_id/sf_account_id

Tech Stack

Frontend (Portal UI)

  • Next.js 15 with App Router
  • Turbopack for ultra-fast development and builds
  • React 19 with TypeScript
  • Tailwind CSS with shadcn/ui components
  • TanStack Query for data fetching and caching
  • Zod for validation
  • React Hook Form for form management

Backend (BFF API)

  • NestJS 11 (Node 24 Current or 22 LTS)
  • Prisma 6 ORM with PostgreSQL 17
  • jsforce for Salesforce REST API integration
  • salesforce-pubsub-api-client for Salesforce Platform Events
  • p-queue for request throttling and queue management
  • WHMCS custom API client with comprehensive service layer
  • Freebit SIM management integration
  • Zod-first validation shared via the domain package
  • Bcrypt for password hashing

Queue Management

  • p-queue for intelligent request throttling to external APIs
  • Separate queues for Salesforce (standard + long-running) and WHMCS
  • Configurable concurrency, rate limiting, and timeout handling
  • Prevents API rate limit violations and resource exhaustion

Logging

  • Centralized structured logging via Pino using nestjs-pino in the BFF
  • Sensitive fields are redacted; each request has a correlation ID
  • Usage pattern in services:
    • Inject Logger from nestjs-pino: constructor(@Inject(Logger) private readonly logger: Logger) {}
    • Log with structured objects: this.logger.error('Message', { error })
    • See docs/LOGGING.md for full guidelines

Data & Infrastructure

  • PostgreSQL 17 for users, ID mappings, and optional mirrors
  • Redis 7 for cache, token blacklists, and rate limiting
  • Docker for local development (Postgres/Redis)

Project Structure

customer-portal/
├── apps/
│   ├── portal/            # Next.js 15 frontend (React 19, Tailwind, shadcn/ui)
│   └── bff/               # NestJS 11 backend (Prisma, p-queue, Zod validation)
├── packages/
│   ├── domain/            # Unified domain layer with contracts & schemas
│   ├── validation/        # Unified validation service (NestJS + React)
│   ├── logging/           # Centralized logging utilities (Pino)
│   └── integrations/      # External service integrations
│       ├── whmcs/         # WHMCS API client
│       └── freebit/       # Freebit SIM management
├── scripts/
│   ├── dev/               # Development management scripts
│   └── prod/              # Production deployment scripts
├── docker/
│   └── dev/               # Docker Compose for local development
│       └── docker-compose.yml  # PostgreSQL 17 + Redis 7
├── docs/                  # Comprehensive documentation
├── secrets/               # Private keys (git ignored)
├── env/                   # Environment file templates
├── package.json           # Root workspace configuration
├── pnpm-workspace.yaml    # pnpm workspace definition
└── README.md              # This file

Getting Started

Prerequisites

  • Node.js: Version 22 (LTS) or 24 (Current) - specified in package.json engines
  • pnpm: Version 10.0.0+ (managed via packageManager field)
  • Docker & Docker Compose: For local PostgreSQL and Redis services
  • Git: For version control

Quick Start (2 minutes)

  1. Clone and Install Dependencies

    git clone <repository-url>
    cd customer-portal
    pnpm install
    
  2. Setup Environment

    # Copy development environment template (if available)
    # Note: .env files may be filtered by .cursorignore
    # Contact your team for environment configuration
    
    # Edit with your values (most defaults work for local development)
    # Required: DATABASE_URL, REDIS_URL, JWT_SECRET
    # Optional for basic dev: WHMCS, Salesforce, Freebit credentials
    
  3. Start Development Environment

    # Start database and Redis services
    pnpm dev:start
    
    # In another terminal, start the applications with hot reload
    pnpm dev
    
  4. Access Your Applications

Development Commands

# === Daily Development ===
pnpm dev:start          # Start PostgreSQL + Redis services
pnpm dev                # Start both apps with hot reload
pnpm dev:stop           # Stop all services

# === Database Management ===
pnpm dev:migrate        # Run database migrations
pnpm db:studio          # Open Prisma Studio (database GUI)
pnpm dev:tools          # Start admin tools (Adminer + Redis Commander)

# === Utilities ===
pnpm dev:status         # Check service status
pnpm dev:logs           # View service logs
pnpm dev:reset          # Reset development environment
pnpm lint               # Run linting across all packages
pnpm type-check         # Run TypeScript checks

Build and Export Images (for Plesk upload)

# Frontend
docker build -t customer-portal-frontend:latest -f apps/portal/Dockerfile .
docker save -o customer-portal-frontend.latest.tar customer-portal-frontend:latest

# Backend
docker build -t customer-portal-backend:latest -f apps/bff/Dockerfile .
docker save -o customer-portal-backend.latest.tar customer-portal-backend:latest

Upload the tar files in Plesk → Docker → Images → Upload, then deploy using the appropriate compose stack configuration.

API Client

The portal uses TanStack Query with a lightweight fetch client that shares request/response contracts from @customer-portal/domain and validates them with Zod:

import { apiClient } from "@/lib/api-client";
import type { DashboardSummary } from "@customer-portal/domain/dashboard";

const { data: summary } = useQuery({
  queryKey: ["dashboard", "summary"],
  queryFn: () => apiClient.get<DashboardSummary>("/api/me/summary"),
});

Because the schemas and types live in the shared domain package there is no separate code generation step.

Environment Configuration

  • Local development: configure environment variables (contact team for template)
  • Docker services use defaults: PostgreSQL (dev/dev/portal_dev), Redis (no auth)
  • Plesk production: use split env files (no secrets under httpdocs)
    • Frontend: ensure NEXT_PUBLIC_API_BASE=/api
    • Backend: ensure TRUST_PROXY=true, DB uses database:5432, Redis uses cache:6379
    • See deployment documentation for full instructions

Key Environment Variables

Required environment variables (contact your team for specific values):

# === Application ===
NODE_ENV=development
BFF_PORT=4000
NEXT_PORT=3000

# === Database & Cache ===
DATABASE_URL=postgresql://dev:dev@localhost:5432/portal_dev?schema=public
REDIS_URL=redis://localhost:6379

# === Frontend (exposed to browser) ===
NEXT_PUBLIC_API_BASE=http://localhost:4000
NEXT_PUBLIC_APP_NAME=Customer Portal (Dev)
NEXT_PUBLIC_ENABLE_DEVTOOLS=true

# === Security ===
JWT_SECRET=<secure_secret_minimum_32_chars>
JWT_REFRESH_SECRET=<different_secure_secret_minimum_32_chars>
BCRYPT_ROUNDS=12

# === External APIs (required for full functionality) ===
WHMCS_BASE_URL=<your_whmcs_url>
WHMCS_API_IDENTIFIER=<your_identifier>
WHMCS_API_SECRET=<your_secret>

SF_LOGIN_URL=<salesforce_instance_url>
SF_CLIENT_ID=<oauth_client_id>
SF_PRIVATE_KEY_PATH=./secrets/sf-private.key
SF_USERNAME=<salesforce_username>

FREEBIT_API_BASE_URL=<freebit_api_url>
FREEBIT_CLIENT_ID=<freebit_client_id>
FREEBIT_CLIENT_SECRET=<freebit_secret>

Salesforce Pub/Sub (Events)

# Enable Pub/Sub subscription for order provisioning
SF_EVENTS_ENABLED=true
SF_PROVISION_EVENT_CHANNEL=/event/Order_Fulfilment_Requested__e
SF_EVENTS_REPLAY=LATEST        # or ALL for retention replay
SF_PUBSUB_ENDPOINT=api.pubsub.salesforce.com:7443
SF_PUBSUB_NUM_REQUESTED=25     # flow control window
  • Verify subscriber status: GET /api/health/sf-events
    • enabled: whether Pub/Sub is enabled
    • channel: topic name
    • replay.lastReplayId: last committed cursor
    • subscriber.status: connected | disconnected | unknown

Read more about the provisioning flow in docs/provisioning/RUNBOOK_PROVISIONING.md.

Development Tools Access

When running pnpm dev:tools, you get access to:

Data Model

Core Tables (PostgreSQL)

  • users - Portal user accounts with auth credentials
  • id_mappings - Cross-system user ID mappings
  • invoices_mirror - Optional WHMCS invoice cache
  • subscriptions_mirror - Optional WHMCS service cache
  • idempotency_keys - Prevent duplicate operations

API Surface (BFF)

Authentication

  • POST /api/auth/signup - Create portal user → WHMCS AddClient → SF upsert
  • POST /api/auth/login - Portal authentication
  • POST /api/auth/migrate - Account migration from legacy portal
  • POST /api/auth/set-password - Required after WHMCS link

User Management

  • GET /api/me - Current user profile
  • GET /api/me/summary - Dashboard summary
  • PATCH /api/me - Update profile
  • PATCH /api/me/address - Update address fields

Catalog & Orders

  • GET /api/services/* - Services catalog endpoints (internet/sim/vpn)
  • POST /api/orders - WHMCS AddOrder with idempotency

Invoices

  • GET /api/invoices - Paginated invoice list (cached 60-120s)
  • GET /api/invoices/:id - Invoice details
  • POST /api/invoices/:id/sso-link - WHMCS CreateSsoToken

Subscriptions

  • GET /api/subscriptions - WHMCS GetClientsProducts

Support Cases (Salesforce)

  • GET /api/cases - Cases list (cached 30-60s)
  • GET /api/cases/:id - Case details with comments
  • POST /api/cases - Create new case
  • POST /api/cases/:id/comments - Add comment to case

Webhooks & Events

  • POST /api/webhooks/whmcs - WHMCS action hooks → update mirrors + bust cache
  • Salesforce Platform Events - Real-time order provisioning via gRPC Pub/Sub

Frontend Pages

Public Pages

  • / - Landing page for non-authenticated users
  • /auth/login - Sign in
  • /auth/signup - Create account
  • /auth/set-password - Set password after WHMCS link

Authenticated Pages

  • /dashboard - Dashboard (invoices, active subs, orders)
  • /catalog - Product catalog home
  • /catalog/internet - Internet plans
  • /catalog/vpn - VPN products
  • /checkout - Checkout flow
  • /orders - Order list
  • /orders/[id] - Order details
  • /subscriptions - Active subscriptions
  • /subscriptions/[id] - Subscription details
  • /billing/invoices - Invoice list
  • /billing/invoices/[id] - Invoice details
  • /billing/payments - Payment methods
  • /support/cases - Support cases list
  • /support/cases/[id] - Case details
  • /support/new - Create new case
  • /account - User account management

Development Milestones

Milestone 1: Identity & Linking

  • Portal login/signup with JWT authentication
  • One-time WHMCS verification with SSO
  • Set new portal password (Bcrypt)
  • Store id_mappings (user ↔ WHMCS ↔ Salesforce)
  • Refresh token rotation
  • Account lockout after failed attempts
  • Rate limiting on auth endpoints

Milestone 2: Catalog & Orders

  • Product catalog (GetProducts from WHMCS)
  • Catalog caching with CDC invalidation
  • Internet plan catalog with address verification
  • VPN product catalog
  • Checkout flow with cart management
  • Order creation (WHMCS AddOrder)
  • Order list and details from Salesforce
  • Real-time order provisioning via Salesforce Platform Events

Milestone 3: Billing & Invoices

  • Invoice list/detail (GetInvoices from WHMCS)
  • Invoice caching with TTL
  • WHMCS SSO deep links for payment
  • Payment method management
  • Payment gateway listing
  • Subscription list and details
  • WHMCS webhooks → cache bust + mirror updates

Milestone 4: Support & Cases

  • Salesforce case list (cached)
  • Case details with comments
  • Create new support case
  • Add comments to existing cases
  • Case file attachments
  • Email notifications for case updates

Milestone 5: SIM Management & Provisioning

  • Freebit SIM management integration
  • Order provisioning workflow
  • Real-time event processing via Salesforce Platform Events
  • Comprehensive error handling and retry logic
  • Customer-facing SIM management UI

Security Features

  • HTTPS only with HttpOnly/SameSite cookies
  • JWT access + refresh tokens with Redis-backed blacklist
  • Bcrypt password hashing (configurable rounds)
  • Account lockout after failed login attempts
  • Rate limiting on auth endpoints and external API calls
  • Idempotency keys on all mutating operations
  • Row-level security (user must own resources)
  • PII minimization with encryption at rest/in transit
  • Audit logging for security-critical actions
  • No WHMCS/SF credentials exposed to browser

Caching Strategy

  • Invoices: TTL-based (90s); bust on WHMCS webhook
  • Catalog: CDC-driven (no TTL); manual bust on data changes
  • Orders: CDC-driven (no TTL); real-time invalidation via Salesforce Platform Events
  • WHMCS API responses: TTL-based caching (configurable per endpoint)
  • Redis-backed with request coalescing to prevent thundering herd
  • Keys include user_id to prevent cross-user leakage
  • Metrics tracking for cache hits, misses, and invalidations

Troubleshooting

Common Issues

Port Already in Use

# Check what's using the port
lsof -i :3000  # or :4000, :5432, :6379
# Kill the process or change ports in .env

Database Connection Issues

# Check if PostgreSQL is running
pnpm dev:status
# Restart services
pnpm dev:restart
# Reset everything
pnpm dev:reset

Environment Variables Not Loading

  • Ensure environment variables are configured (contact team for configuration)
  • Restart applications after changing environment variables
  • Check for typos in variable names
  • Frontend variables must start with NEXT_PUBLIC_

Docker Issues

# Clean up Docker resources
docker system prune -f
# Rebuild containers
pnpm dev:stop && pnpm dev:start

pnpm Issues

# Clear pnpm cache
pnpm store prune
# Reinstall dependencies
rm -rf node_modules && pnpm install

Getting Help

  1. Check the logs: pnpm dev:logs
  2. Verify service status: pnpm dev:status
  3. Review environment configuration in .env
  4. Check the documentation in docs/ folder
  5. Look for similar issues in the project's issue tracker

Documentation

  • Getting Started - Detailed setup guide
  • Development Guide - Quick reference for daily development
  • Deployment Guide - Production deployment instructions
  • Architecture - Code organization and conventions
  • Logging - Logging configuration and best practices
  • Portal Guides - High-level flow, data ownership, and error handling (docs/how-it-works/README.md)

Contributing

  1. Setup Development Environment

    # Configure environment variables (contact team)
    pnpm install
    pnpm dev:start
    
  2. Follow Code Standards

    • Run pnpm lint before committing
    • Use pnpm format to format code
    • Ensure pnpm type-check passes
    • Write tests for new features
  3. Development Workflow

    • Create feature branches from main
    • Make small, focused commits
    • Update documentation as needed
    • Test thoroughly before submitting PRs
  4. Code Quality

    • Follow TypeScript strict mode
    • Use proper error handling (no sensitive info exposed)
    • Implement clean, minimal UI designs
    • Avoid 'V2' suffixes in service names
    • Verify API integration against official documentation

Codebase Coding Standard

  1. Have types and validation in the shared domain layer.
  2. Keep business logic out of the frontend; use services and APIs instead.
  3. Reuse existing types and functions; extend them when additional behavior is needed.
  4. Follow the established folder structures documented in docs/STRUCTURE.md.

Documentation

📚 Complete Documentation - Full documentation index

Key Features

  • Required address at signup - No incomplete profiles
  • Order-type specific flows - Internet orders require verification
  • Real-time WHMCS sync - Address updates
  • Salesforce snapshots - Point-in-time order addresses
  • Clean architecture - Modular, maintainable code

License

[Your License Here] See docs/RUNBOOK_PROVISIONING.md for the provisioning runbook.

Description
Assist Design
Readme 16 MiB
Languages
TypeScript 51%
JavaScript 47.2%
Shell 0.8%
HTML 0.5%
CSS 0.3%
Other 0.1%