- Consolidated and cleaned up type definitions in Freebit service interfaces for better readability. - Enhanced error handling and logging in Freebit service methods to provide clearer feedback. - Updated SIM management pages to streamline user interactions and improve UI components. - Removed deprecated subscription detail page and restructured routing for better navigation. - Added new notice and info row components in SIM cancellation page for improved user experience.
Refactor Freebit service and update SIM management components for improved clarity and functionality
Refactor Freebit service and update SIM management components for improved clarity and functionality
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
- OpenAPI/Swagger for documentation
Logging
- Centralized structured logging via Pino using
nestjs-pinoin the BFF - Sensitive fields are redacted; each request has a correlation ID
- Usage pattern in services:
- Inject
Loggerfromnestjs-pino:constructor(@Inject(Logger) private readonly logger: Logger) {} - Log with structured objects:
this.logger.error('Message', { error }) - See
docs/LOGGING.mdfor full guidelines
- Inject
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, OpenAPI)
├── packages/
│ └── shared/ # Shared types and utilities
├── scripts/
│ ├── dev/ # Development management scripts
│ └── prod/ # Production deployment scripts
├── compose-plesk.yaml # Plesk Docker stack (proxy / and /api)
├── 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.jsonengines - pnpm: Version 10.0.0+ (managed via
packageManagerfield) - Docker & Docker Compose: For local PostgreSQL and Redis services
- Git: For version control
Quick Start (2 minutes)
-
Clone and Install Dependencies
git clone <repository-url> cd new-portal-website pnpm install -
Setup Environment
# Copy development environment template cp .env.dev.example .env # Edit with your values (most defaults work for local development) nano .env -
Start Development Environment
# Start database and Redis services pnpm dev:start # In another terminal, start the applications with hot reload pnpm dev -
Access Your Applications
- Frontend: http://localhost:3000
- Backend API: http://localhost:4000/api
- API Documentation: http://localhost:4000/api/docs
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 compose-plesk.yaml as a stack.
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→ ensureNEXT_PUBLIC_API_BASE=/api - Backend:
env/portal-backend.env.sample→ ensureTRUST_PROXY=true, DB usesdatabase:5432, Redis usescache:6379 - See PLESK_DEPLOYMENT.md for full instructions and proxy rule setup.
- Frontend:
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-eventsenabled: whether Pub/Sub is enabledchannel: topic namereplay.lastReplayId: last committed cursorsubscriber.status: connected | disconnected | unknown
Development Tools Access
When running pnpm dev:tools, you get access to:
- Adminer (Database GUI): http://localhost:8080
- Server:
postgres, User:dev, Password:dev, Database:portal_dev
- Server:
- Redis Commander: http://localhost:8081
- User:
admin, Password:dev
- User:
Data Model
Core Tables (PostgreSQL)
users- Portal user accounts with auth credentialsid_mappings- Cross-system user ID mappingsinvoices_mirror- Optional WHMCS invoice cachesubscriptions_mirror- Optional WHMCS service cacheidempotency_keys- Prevent duplicate operations
API Surface (BFF)
Authentication
POST /api/auth/signup- Create portal user → WHMCS AddClient → SF upsertPOST /api/auth/login- Portal authenticationPOST /api/auth/link-whmcs- OIDC callback or ValidateLoginPOST /api/auth/set-password- Required after WHMCS link
User Management
GET /api/me- Current user profileGET /api/me/summary- Dashboard summaryPATCH /api/me- Update profilePATCH /api/me/billing- Sync to WHMCS 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 detailsPOST /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 detailsPOST /api/cases- Create new case
Webhooks
POST /api/orders/:sfOrderId/fulfill- Secure Salesforce-initiated order fulfillmentPOST /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
.envfile 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
- Check the logs:
pnpm dev:logs - Verify service status:
pnpm dev:status - Review environment configuration in
.env - Check the documentation in
docs/folder - 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
Contributing
-
Setup Development Environment
cp .env.dev.example .env pnpm install pnpm dev:start -
Follow Code Standards
- Run
pnpm lintbefore committing - Use
pnpm formatto format code - Ensure
pnpm type-checkpasses - Write tests for new features
- Run
-
Development Workflow
- Create feature branches from
main - Make small, focused commits
- Update documentation as needed
- Test thoroughly before submitting PRs
- Create feature branches from
-
Code Quality
- Follow TypeScript strict mode
- Use proper error handling memory:6689308
- Implement clean, minimal UI designs memory:6676820
- Avoid 'V2' suffixes in service names memory:6676816
Documentation
📚 Complete Documentation - Full documentation index
Quick Links
- Getting Started - Setup and configuration
- Development Commands - Daily workflow
- Address System - Address management
- Product Catalog - SKU-based catalog
- Deployment Guide - Production deployment
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
Languages
TypeScript
51%
JavaScript
47.2%
Shell
0.8%
HTML
0.5%
CSS
0.3%
Other
0.1%