2025-08-20 18:02:50 +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, and invoices
|
|
|
|
|
- **Salesforce**: CRM (Accounts, Contacts, Cases)
|
|
|
|
|
- **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
|
|
|
|
|
|
|
|
|
|
### 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
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
projects/new-portal-website/
|
2025-08-21 15:24:40 +09:00
|
|
|
├── apps/
|
|
|
|
|
│ ├── portal/ # Next.js frontend (UI)
|
|
|
|
|
│ └── bff/ # NestJS backend (API)
|
|
|
|
|
├── tools/
|
|
|
|
|
│ ├── dev/ # Development scripts
|
|
|
|
|
│ └── deployment/ # Docker Compose for development
|
|
|
|
|
├── docs/ # Documentation
|
|
|
|
|
├── packages/ # Shared packages
|
|
|
|
|
└── secrets/ # Private keys (git ignored)
|
2025-08-20 18:02:50 +09:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Getting Started
|
|
|
|
|
|
|
|
|
|
### Prerequisites
|
|
|
|
|
- Node.js 24 (Current) or 22 (LTS)
|
|
|
|
|
- Docker and Docker Compose
|
|
|
|
|
- pnpm (recommended) via Corepack
|
|
|
|
|
|
|
|
|
|
### Local Development Setup
|
|
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
1. **Start Development Environment**
|
2025-08-20 18:02:50 +09:00
|
|
|
```bash
|
2025-08-21 15:24:40 +09:00
|
|
|
# Option 1: Start everything at once (recommended)
|
|
|
|
|
pnpm start:all
|
|
|
|
|
|
|
|
|
|
# Option 2: Start services only, then apps manually
|
|
|
|
|
pnpm start:services
|
2025-08-20 18:02:50 +09:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. **Setup Portal (Frontend)**
|
|
|
|
|
```bash
|
2025-08-21 15:24:40 +09:00
|
|
|
cd apps/portal
|
2025-08-20 18:02:50 +09:00
|
|
|
cp .env.example .env.local
|
2025-08-21 15:24:40 +09:00
|
|
|
pnpm install
|
|
|
|
|
pnpm run dev
|
2025-08-20 18:02:50 +09:00
|
|
|
```
|
|
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
3. **Setup BFF (Backend)**
|
2025-08-20 18:02:50 +09:00
|
|
|
```bash
|
2025-08-21 15:24:40 +09:00
|
|
|
cd apps/bff
|
2025-08-20 18:02:50 +09:00
|
|
|
cp .env.example .env
|
2025-08-21 15:24:40 +09:00
|
|
|
pnpm install
|
|
|
|
|
pnpm run dev
|
2025-08-20 18:02:50 +09:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Environment Variables
|
|
|
|
|
|
|
|
|
|
#### Portal (.env.local)
|
|
|
|
|
```env
|
|
|
|
|
NEXT_PUBLIC_API_BASE="http://localhost:4000"
|
|
|
|
|
NEXT_PUBLIC_APP_NAME="Customer Portal"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### BFF (.env)
|
|
|
|
|
```env
|
|
|
|
|
DATABASE_URL="postgresql://app:app@localhost:5432/portal?schema=public"
|
|
|
|
|
REDIS_URL="redis://localhost:6379"
|
|
|
|
|
WHMCS_BASE_URL="https://<your-whmcs>"
|
|
|
|
|
WHMCS_API_IDENTIFIER="<identifier>"
|
|
|
|
|
WHMCS_API_SECRET="<secret>"
|
|
|
|
|
SF_LOGIN_URL="https://login.salesforce.com"
|
|
|
|
|
SF_CLIENT_ID="<consumer_key>"
|
|
|
|
|
SF_USERNAME="<integration@yourco.com>"
|
|
|
|
|
SF_PRIVATE_KEY_PATH="./secrets/sf.key"
|
|
|
|
|
PORT=4000
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 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/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 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/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
|
|
|
|
|
|
|
|
|
|
## Current Status
|
|
|
|
|
|
|
|
|
|
✅ **Completed:**
|
|
|
|
|
- Project structure setup
|
|
|
|
|
- Next.js 15 app with TypeScript
|
|
|
|
|
- Tailwind CSS with shadcn/ui
|
|
|
|
|
- TanStack Query configuration
|
|
|
|
|
- Docker Compose for PostgreSQL 17 and Redis 8
|
|
|
|
|
- Environment configuration
|
|
|
|
|
- Basic landing page
|
|
|
|
|
|
|
|
|
|
🚧 **Next Steps:**
|
|
|
|
|
- Set up NestJS backend (BFF)
|
|
|
|
|
- Implement authentication system
|
|
|
|
|
- Create database schema with Prisma
|
|
|
|
|
- Build initial API endpoints
|
|
|
|
|
|
|
|
|
|
## Contributing
|
|
|
|
|
|
|
|
|
|
1. Ensure Docker services are running
|
|
|
|
|
2. Follow the coding standards (ESLint, Prettier)
|
|
|
|
|
3. Write tests for new features
|
|
|
|
|
4. Update documentation as needed
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
[Your License Here]
|