barsa d6f7c50e7b Refactor Salesforce request handling and improve logging
- Moved metrics tracking and logging from the queueing phase to the execution phase in SalesforceRequestQueueService for better accuracy.
- Updated CSRF token generation in CsrfController to accept parameters in a more flexible manner.
- Enhanced CacheService to handle immediate expiry requests without leaking stale values.
- Improved error handling and re-authentication logic in SalesforceConnection for better resilience during session expiration.
- Refactored logout functionality in AuthFacade to handle optional userId and improve logging during token revocation.
- Updated AuthController to apply rate limit headers and improved type handling in various request contexts.
- Streamlined imports and improved overall code organization across multiple modules for better maintainability.
2025-11-05 15:47:06 +09:00
2025-08-22 17:02:49 +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
  • jsforce for Salesforce integration
  • WHMCS API client
  • BullMQ for async jobs with ioredis
  • Zod-first validation shared via the domain package

Temporarily Disabled Modules

  • CasesModule and JobsModule are intentionally excluded from the running NestJS application until their APIs and job processors are fully implemented. See docs/TEMPORARY-DISABLED-MODULES.md for re-enablement details and placeholder behaviour.

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 8 for cache and queues
  • Docker for local development (Postgres/Redis)

Project Structure

new-portal-website/
├── apps/
│   ├── portal/            # Next.js 15 frontend (React 19, Tailwind, shadcn/ui)
│   └── bff/               # NestJS 11 backend (Prisma, BullMQ, Zod validation)
├── packages/
│   ├── shared/            # Shared types and utilities
│   └── api-client/        # Lightweight fetch helpers + shared Zod types
├── scripts/
│   ├── dev/               # Development management scripts
│   └── prod/              # Production deployment scripts
├── config/
│   ├── docker/
│   │   └── compose-plesk.yaml  # Plesk Docker stack (proxy / and /api)
│   ├── prettier.config.js      # Prettier configuration
│   └── .editorconfig           # Editor configuration
├── docs/                  # Comprehensive documentation
├── secrets/               # Private keys (git ignored)
├── .env.dev.example       # Development environment template
├── .env.production.example # Production environment template
├── 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 new-portal-website
    pnpm install
    
  2. Setup Environment

    # Copy development environment template
    cp .env.dev.example .env
    
    # Edit with your values (most defaults work for local development)
    nano .env
    
  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 portal-frontend:latest -f apps/portal/Dockerfile .
docker save -o portal-frontend.latest.tar portal-frontend:latest

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

Upload the tar files in Plesk → Docker → Images → Upload, then deploy using config/docker/compose-plesk.yaml as a stack.

API Client

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

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

const response = await apiClient.GET<DashboardSummary>("/api/me/summary");
const summary = getDataOrThrow(response);

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

Environment Configuration

  • Local development: use the root .env (see .env.example).
  • Plesk production: use split env files (no secrets under httpdocs).
    • Frontend: env/portal-frontend.env.sample → ensure NEXT_PUBLIC_API_BASE=/api
    • Backend: env/portal-backend.env.sample → ensure TRUST_PROXY=true, DB uses database:5432, Redis uses cache:6379
    • See PLESK_DEPLOYMENT.md for full instructions and proxy rule setup.

Key Environment Variables

# === 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=dev_secret_for_local_development_minimum_32_chars_long
BCRYPT_ROUNDS=10

# === External APIs (optional for basic development) ===
WHMCS_BASE_URL=https://demo.whmcs.com
WHMCS_API_IDENTIFIER=your_demo_identifier
WHMCS_API_SECRET=your_demo_secret
SF_LOGIN_URL=https://test.salesforce.com
SF_CLIENT_ID=your_dev_client_id
SF_PRIVATE_KEY_PATH=./secrets/sf-dev.key
SF_USERNAME=dev@yourcompany.com.sandbox

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=50     # flow control window
  • Verify subscriber status: GET /health/sf-events
    • enabled: whether Pub/Sub is enabled
    • channel: topic name
    • replay.lastReplayId: last committed cursor
    • subscriber.status: connected | disconnected | unknown

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/link-whmcs - OIDC callback or ValidateLogin
  • 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/catalog - WHMCS GetProducts (cached 5-15m)
  • 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
  • POST /api/cases - Create new case

Webhooks

  • POST /api/orders/:sfOrderId/fulfill - Secure Salesforce-initiated order fulfillment
  • POST /api/webhooks/whmcs - WHMCS action hooks → update mirrors + bust cache

Frontend Pages

Initial Pages

  • / - Dashboard (next invoice due, active subs, open cases)
  • /billing/invoices - Invoice list
  • /billing/invoices/[id] - Invoice details
  • /subscriptions - Active subscriptions
  • /support/cases - Support cases list
  • /support/cases/[id] - Case details
  • /support/new - Create new case
  • /account/profile - User profile management
  • /account/security - Security settings
  • /auth/login - Sign in
  • /auth/signup - Create account
  • /auth/set-password - Set password after WHMCS link

Development Milestones

Milestone 1: Identity & Linking

  • Portal login/signup
  • One-time WHMCS verification
  • Set new portal password
  • Store id_mappings

Milestone 2: Billing

  • Product catalog (GetProducts)
  • Checkout (AddOrder)
  • Invoice list/detail (GetInvoices)
  • WHMCS SSO deep links

Milestone 3: Cases & Webhooks

  • Salesforce case list/create
  • WHMCS webhooks → cache bust + mirrors
  • Nightly reconcile job (optional)

Security Features

  • HTTPS only with HttpOnly/SameSite cookies
  • Optional MFA for portal accounts
  • Idempotency keys on all mutating operations
  • Row-level security (user must own resources)
  • PII minimization with encryption at rest/in transit
  • No WHMCS/SF credentials exposed to browser

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

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 .env file exists in project root
  • Restart applications after changing .env
  • 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

Contributing

  1. Setup Development Environment

    cp .env.dev.example .env
    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

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%