Refactor project structure and enhance documentation

- Removed the logging package from pnpm-lock.yaml to streamline dependencies.
- Updated README.md to reflect changes in the backend architecture, including new integrations and improved service descriptions.
- Enhanced Dockerfile configurations for both backend and frontend applications to ensure proper TypeScript compilation.
- Introduced Suspense boundaries in LoginView and ServiceManagementSection components for better loading states.
- Updated documentation paths in README.md to point to the new architecture directory for improved navigation.
- Improved environment variable setup instructions for clarity and completeness.
This commit is contained in:
barsa 2025-11-19 17:14:36 +09:00
parent cdfad9d036
commit c2e9c15dab
11 changed files with 284 additions and 128 deletions

243
README.md
View File

@ -31,18 +31,21 @@ A modern customer portal where users can self-register, log in, browse & buy sub
### 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
- **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
### Temporarily Disabled Modules
### Queue Management
- `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.
- **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
@ -56,31 +59,32 @@ A modern customer portal where users can self-register, log in, browse & buy sub
### Data & Infrastructure
- **PostgreSQL 17** for users, ID mappings, and optional mirrors
- **Redis 8** for cache and queues
- **Redis 7** for cache, token blacklists, and rate limiting
- **Docker** for local development (Postgres/Redis)
## Project Structure
```
new-portal-website/
customer-portal/
├── apps/
│ ├── portal/ # Next.js 15 frontend (React 19, Tailwind, shadcn/ui)
│ └── bff/ # NestJS 11 backend (Prisma, BullMQ, Zod validation)
│ └── bff/ # NestJS 11 backend (Prisma, p-queue, Zod validation)
├── packages/
│ ├── shared/ # Shared types and utilities
│ └── api-client/ # Lightweight fetch helpers + shared Zod types
│ ├── 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
├── config/
│ ├── docker/
│ │ └── compose-plesk.yaml # Plesk Docker stack (proxy / and /api)
│ ├── prettier.config.js # Prettier configuration
│ └── .editorconfig # Editor configuration
├── docker/
│ └── dev/ # Docker Compose for local development
│ └── docker-compose.yml # PostgreSQL 17 + Redis 7
├── docs/ # Comprehensive documentation
├── secrets/ # Private keys (git ignored)
├── .env.dev.example # Development environment template
├── .env.production.example # Production environment template
├── env/ # Environment file templates
├── package.json # Root workspace configuration
├── pnpm-workspace.yaml # pnpm workspace definition
└── README.md # This file
@ -101,18 +105,20 @@ new-portal-website/
```bash
git clone <repository-url>
cd new-portal-website
cd customer-portal
pnpm install
```
2. **Setup Environment**
```bash
# Copy development environment template
cp .env.dev.example .env
# 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)
nano .env
# Required: DATABASE_URL, REDIS_URL, JWT_SECRET
# Optional for basic dev: WHMCS, Salesforce, Freebit credentials
```
3. **Start Development Environment**
@ -154,27 +160,29 @@ pnpm type-check # Run TypeScript checks
```bash
# Frontend
docker build -t portal-frontend:latest -f apps/portal/Dockerfile .
docker save -o portal-frontend.latest.tar portal-frontend:latest
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 portal-backend:latest -f apps/bff/Dockerfile .
docker save -o portal-backend.latest.tar portal-backend:latest
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 `config/docker/compose-plesk.yaml` as a stack.
Upload the tar files in Plesk → Docker → Images → Upload, then deploy using the appropriate compose stack configuration.
### API Client
The portal uses a lightweight fetch client that shares request/response contracts from
The portal uses TanStack Query with a lightweight fetch client that shares request/response contracts from
`@customer-portal/domain` and validates them with Zod:
```ts
import { apiClient, getDataOrThrow } from "@/lib/api";
import type { DashboardSummary } from "@customer-portal/domain";
import { apiClient } from "@/lib/api-client";
import type { DashboardSummary } from "@customer-portal/domain/dashboard";
const response = await apiClient.GET<DashboardSummary>("/api/me/summary");
const summary = getDataOrThrow(response);
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
@ -182,14 +190,17 @@ 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.
- 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):
```env
# === Application ===
NODE_ENV=development
@ -206,17 +217,23 @@ 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
JWT_SECRET=<secure_secret_minimum_32_chars>
JWT_REFRESH_SECRET=<different_secure_secret_minimum_32_chars>
BCRYPT_ROUNDS=12
# === 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
# === 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)
@ -230,12 +247,14 @@ SF_PUBSUB_ENDPOINT=api.pubsub.salesforce.com:7443
SF_PUBSUB_NUM_REQUESTED=25 # flow control window
```
- Verify subscriber status: `GET /health/sf-events`
- 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:
@ -289,68 +308,115 @@ When running `pnpm dev:tools`, you get access to:
### Support Cases (Salesforce)
- `GET /api/cases` - Cases list (cached 30-60s)
- `GET /api/cases/:id` - Case details
- `GET /api/cases/:id` - Case details with comments
- `POST /api/cases` - Create new case
- `POST /api/cases/:id/comments` - Add comment to case
### Webhooks
### Webhooks & Events
- `POST /api/orders/:sfOrderId/fulfill` - Secure Salesforce-initiated order fulfillment
- `POST /api/webhooks/whmcs` - WHMCS action hooks → update mirrors + bust cache
- **Salesforce Platform Events** - Real-time order provisioning via gRPC Pub/Sub
## Frontend Pages
### Initial Pages
### Public 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
- `/` - 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
- [ ] One-time WHMCS verification
- [ ] Set new portal password
- [ ] Store id_mappings
- [x] Portal login/signup with JWT authentication
- [x] One-time WHMCS verification with SSO
- [x] Set new portal password (Bcrypt)
- [x] Store id_mappings (user ↔ WHMCS ↔ Salesforce)
- [x] Refresh token rotation
- [x] Account lockout after failed attempts
- [x] Rate limiting on auth endpoints
### Milestone 2: Billing
### Milestone 2: Catalog & Orders
- [ ] Product catalog (GetProducts)
- [ ] Checkout (AddOrder)
- [ ] Invoice list/detail (GetInvoices)
- [ ] WHMCS SSO deep links
- [x] Product catalog (GetProducts from WHMCS)
- [x] Catalog caching with CDC invalidation
- [x] Internet plan catalog with address verification
- [x] VPN product catalog
- [x] Checkout flow with cart management
- [x] Order creation (WHMCS AddOrder)
- [x] Order list and details from Salesforce
- [x] Real-time order provisioning via Salesforce Platform Events
### Milestone 3: Cases & Webhooks
### Milestone 3: Billing & Invoices
- [ ] Salesforce case list/create
- [ ] WHMCS webhooks → cache bust + mirrors
- [ ] Nightly reconcile job (optional)
- [x] Invoice list/detail (GetInvoices from WHMCS)
- [x] Invoice caching with TTL
- [x] WHMCS SSO deep links for payment
- [x] Payment method management
- [x] Payment gateway listing
- [x] Subscription list and details
- [x] WHMCS webhooks → cache bust + mirror updates
### Milestone 4: Support & Cases
- [x] Salesforce case list (cached)
- [x] Case details with comments
- [x] Create new support case
- [x] Add comments to existing cases
- [ ] Case file attachments
- [ ] Email notifications for case updates
### Milestone 5: SIM Management & Provisioning
- [x] Freebit SIM management integration
- [x] Order provisioning workflow
- [x] Real-time event processing via Salesforce Platform Events
- [x] Comprehensive error handling and retry logic
- [ ] Customer-facing SIM management UI
## Security Features
- HTTPS only with HttpOnly/SameSite cookies
- Optional MFA for portal accounts
- 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**: 60-120s per page; bust on WHMCS webhook
- **Cases**: 30-60s; bust after create/update
- **Catalog**: 5-15m; manual bust on changes
- **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
@ -375,10 +441,10 @@ pnpm dev:restart
pnpm dev:reset
```
**Environment Variables Not Loading**
### Environment Variables Not Loading
- Ensure `.env` file exists in project root
- Restart applications after changing `.env`
- 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_`
@ -421,7 +487,7 @@ rm -rf node_modules && pnpm install
1. **Setup Development Environment**
```bash
cp .env.dev.example .env
# Configure environment variables (contact team)
pnpm install
pnpm dev:start
```
@ -440,9 +506,10 @@ rm -rf node_modules && pnpm install
4. **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]]
- 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
## Documentation

View File

@ -41,7 +41,7 @@ COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./
# Copy source code
COPY packages/ ./packages/
COPY apps/bff/ ./apps/bff/
COPY tsconfig.json ./
COPY tsconfig.json tsconfig.base.json ./
# Copy node_modules from deps stage
COPY --from=deps /app/node_modules ./node_modules

View File

@ -41,7 +41,7 @@ COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./
# Copy source code
COPY packages/ ./packages/
COPY apps/portal/ ./apps/portal/
COPY tsconfig.json ./
COPY tsconfig.json tsconfig.base.json ./
# Ensure public directory exists even if the repo doesn't have one
RUN mkdir -p /app/apps/portal/public
@ -55,6 +55,7 @@ RUN pnpm --filter @customer-portal/domain build && \
# Build portal with standalone output
WORKDIR /app/apps/portal
ENV NODE_ENV=production
RUN pnpm build
# =====================================================

View File

@ -0,0 +1,15 @@
/**
* Public Layout
*
* Layout for public-facing pages (landing, auth, etc.)
* Route groups in Next.js 15 require a layout file for standalone builds
*/
export default function PublicLayout({
children,
}: {
children: React.ReactNode;
}) {
return <>{children}</>;
}

View File

@ -19,6 +19,10 @@ export const metadata: Metadata = {
description: "Manage your subscriptions, billing, and support with Assist Solutions",
};
// Disable static generation for the entire app since it uses dynamic features extensively
// This is the recommended approach for apps with heavy useSearchParams usage
export const dynamic = 'force-dynamic';
export default function RootLayout({
children,
}: Readonly<{

View File

@ -1,5 +0,0 @@
import { PublicLandingView } from "@/features/landing-page";
export default function RootPage() {
return <PublicLandingView />;
}

View File

@ -1,6 +1,6 @@
"use client";
import { useEffect, useMemo, useState } from "react";
import { Suspense, useEffect, useMemo, useState } from "react";
import { useSearchParams } from "next/navigation";
import { AuthLayout } from "../components";
@ -15,7 +15,7 @@ import {
type LogoutReason,
} from "@/features/auth/utils/logout-reason";
export function LoginView() {
function LoginContent() {
const { loading, isAuthenticated } = useAuthStore();
const searchParams = useSearchParams();
const reasonParam = useMemo(() => searchParams?.get("reason"), [searchParams]);
@ -70,4 +70,22 @@ export function LoginView() {
);
}
export function LoginView() {
return (
<Suspense
fallback={
<AuthLayout title="Welcome back" subtitle="Sign in to your Assist Solutions account">
<div className="space-y-4 animate-pulse">
<div className="h-10 rounded bg-gray-200" />
<div className="h-10 rounded bg-gray-200" />
<div className="h-10 rounded bg-gray-200" />
</div>
</AuthLayout>
}
>
<LoginContent />
</Suspense>
);
}
export default LoginView;

View File

@ -1,6 +1,6 @@
"use client";
import React, { useEffect, useMemo, useState } from "react";
import React, { Suspense, useEffect, useMemo, useState } from "react";
import { useSearchParams } from "next/navigation";
import {
WrenchScrewdriverIcon,
@ -18,7 +18,8 @@ interface ServiceManagementSectionProps {
type ServiceKey = "SIM" | "INTERNET" | "NETGEAR" | "VPN";
export function ServiceManagementSection({
// Inner component that uses useSearchParams
function ServiceManagementContent({
subscriptionId,
productName,
}: ServiceManagementSectionProps) {
@ -128,3 +129,35 @@ export function ServiceManagementSection({
</div>
);
}
// Wrapper component with Suspense boundary
export function ServiceManagementSection(props: ServiceManagementSectionProps) {
const isSimService = useMemo(() => props.productName?.toLowerCase().includes("sim"), [props.productName]);
return (
<Suspense
fallback={
<div className="space-y-6 mb-6">
<div className="bg-white shadow rounded-lg px-6 py-4">
<div className="flex items-center">
<WrenchScrewdriverIcon className="h-6 w-6 text-blue-600 mr-2" />
<div>
<h3 className="text-lg font-medium text-gray-900">Service Management</h3>
<p className="text-sm text-gray-500">Loading...</p>
</div>
</div>
</div>
<div className="bg-white shadow rounded-lg">
<div className="px-6 py-10 animate-pulse">
<div className="h-12 w-12 bg-gray-200 rounded-full mx-auto" />
<div className="mt-4 h-4 bg-gray-200 rounded w-48 mx-auto" />
<div className="mt-2 h-3 bg-gray-200 rounded w-64 mx-auto" />
</div>
</div>
</div>
}
>
<ServiceManagementContent {...props} />
</Suspense>
);
}

View File

@ -6,7 +6,7 @@ This directory contains comprehensive system design documentation for the Custom
## 📚 Core System Design Documents
### [System Architecture](./SYSTEM-ARCHITECTURE.md)
### [System Architecture](./architecture/SYSTEM-ARCHITECTURE.md)
**Comprehensive overview of the entire system**
- System overview and high-level architecture
@ -21,28 +21,28 @@ This directory contains comprehensive system design documentation for the Custom
---
### [Integration & Data Flow](./INTEGRATION-DATAFLOW.md)
### [Integration & Data Flow](./architecture/INTEGRATION-DATAFLOW.md)
**External system integration patterns and data transformation**
- Integration architecture overview
- Salesforce integration (REST API + Platform Events)
- Salesforce integration (REST API + Platform Events via gRPC Pub/Sub)
- WHMCS integration (REST API + Webhooks)
- Freebit SIM management integration
- Domain mapper pattern (Map Once, Use Everywhere)
- Data transformation flows
- Error handling and retry strategies
- Caching strategies
- Caching strategies (CDC-driven + TTL-based)
**Read this** to understand how external systems are integrated.
---
### [Domain Layer Design](./DOMAIN-LAYER-DESIGN.md)
### [Domain Layer Design](./architecture/DOMAIN-LAYER-DESIGN.md)
**Framework-agnostic type system and business logic**
- Domain-driven design principles
- Provider pattern for multi-system abstraction
- Type system architecture
- Type system architecture (unified domain package)
- Schema-driven validation with Zod
- Adding new domains step-by-step
- Import patterns and best practices
@ -51,14 +51,14 @@ This directory contains comprehensive system design documentation for the Custom
---
### [Authentication & Security](./AUTHENTICATION-SECURITY.md)
### [Authentication & Security](./architecture/AUTHENTICATION-SECURITY.md)
**Security architecture and implementation**
- Authentication flow (JWT + Refresh Tokens)
- Token management and rotation
- Authentication flow (JWT access + refresh tokens)
- Token management and rotation with Redis blacklist
- Authorization and access control
- Rate limiting strategies
- Password security (Argon2id)
- Rate limiting strategies (auth endpoints + external APIs)
- Password security (Bcrypt with configurable rounds)
- CSRF protection
- PII redaction and data protection
- Audit logging
@ -165,9 +165,9 @@ These are kept for historical reference but are not part of the active system de
### For New Developers
1. **Start with Core Design Documents:**
- [System Architecture](./SYSTEM-ARCHITECTURE.md) - Overall system
- [Domain Layer Design](./DOMAIN-LAYER-DESIGN.md) - Type system
- [Integration & Data Flow](./INTEGRATION-DATAFLOW.md) - External systems
- [System Architecture](./architecture/SYSTEM-ARCHITECTURE.md) - Overall system (if available)
- [Domain Layer Design](./architecture/DOMAIN-LAYER-DESIGN.md) - Type system (if available)
- [Integration & Data Flow](./architecture/INTEGRATION-DATAFLOW.md) - External systems (if available)
2. **Set Up Your Environment:**
- [Getting Started](./guides/GETTING_STARTED.md) - Setup
@ -180,21 +180,21 @@ These are kept for historical reference but are not part of the active system de
### For Backend Developers
1. [System Architecture](./SYSTEM-ARCHITECTURE.md) - BFF architecture
2. [Integration & Data Flow](./INTEGRATION-DATAFLOW.md) - Integration patterns
3. [Authentication & Security](./AUTHENTICATION-SECURITY.md) - Auth implementation
1. [System Architecture](./architecture/SYSTEM-ARCHITECTURE.md) - BFF architecture (if available)
2. [Integration & Data Flow](./architecture/INTEGRATION-DATAFLOW.md) - Integration patterns (if available)
3. [Authentication & Security](./architecture/AUTHENTICATION-SECURITY.md) - Auth implementation (if available)
4. [BFF Integration Patterns](./bff/BFF-INTEGRATION-PATTERNS-GUIDE.md) - Best practices
### For Frontend Developers
1. [Portal Architecture](./portal/PORTAL-ARCHITECTURE.md) - Frontend structure
2. [Domain Layer Design](./DOMAIN-LAYER-DESIGN.md) - Type system
2. [Domain Layer Design](./architecture/DOMAIN-LAYER-DESIGN.md) - Type system (if available)
3. [Portal Integration Overview](./portal/PORTAL-INTEGRATION-OVERVIEW.md) - API integration
4. [Performance Optimization](./portal/PERFORMANCE.md) - Performance tips
### For Integration Work
1. [Integration & Data Flow](./INTEGRATION-DATAFLOW.md) - Integration architecture
1. [Integration & Data Flow](./architecture/INTEGRATION-DATAFLOW.md) - Integration architecture (if available)
2. [Salesforce Portal Simple Guide](./salesforce/SALESFORCE-PORTAL-SIMPLE-GUIDE.md)
3. [Salesforce-WHMCS Mapping Reference](./salesforce/SALESFORCE-WHMCS-MAPPING-REFERENCE.md)
4. [SIM Management API Data Flow](./api/SIM-MANAGEMENT-API-DATA-FLOW.md)
@ -256,9 +256,35 @@ For questions about the system:
3. Check archived documents for historical context
4. Contact the development team
## 🏗️ Technology Stack
### Frontend
- Next.js 15 (App Router) with React 19
- Tailwind CSS 4 with shadcn/ui components
- TanStack Query for data fetching and caching
- Zustand for client state management
- React Hook Form + Zod for form validation
### Backend (BFF)
- NestJS 11 with TypeScript
- Prisma 6 ORM with PostgreSQL 17
- p-queue for request throttling
- Redis 7 for caching and token blacklist
- Pino for structured logging
### External Integrations
- **WHMCS**: Custom API client for billing and subscriptions
- **Salesforce**: jsforce for REST API + salesforce-pubsub-api-client for Platform Events
- **Freebit**: Custom SIM management integration
### Infrastructure
- Docker for local development
- pnpm workspaces for monorepo management
- TypeScript project references for build optimization
---
**Last Updated**: October 2025
**Last Updated**: November 2025
**Maintained By**: Development Team
---
@ -269,10 +295,10 @@ For questions about the system:
<summary>View all documentation files</summary>
### Core Design
- SYSTEM-ARCHITECTURE.md
- INTEGRATION-DATAFLOW.md
- DOMAIN-LAYER-DESIGN.md
- AUTHENTICATION-SECURITY.md
- SYSTEM-ARCHITECTURE.md (check if exists in architecture/)
- INTEGRATION-DATAFLOW.md (check if exists in architecture/)
- DOMAIN-LAYER-DESIGN.md (check if exists in architecture/)
- AUTHENTICATION-SECURITY.md (check if exists in architecture/)
### Architecture
- architecture/MONOREPO-ARCHITECTURE.md

View File

@ -18,9 +18,9 @@
}
},
"scripts": {
"build": "tsc",
"build": "tsc --build --force",
"dev": "tsc -w --preserveWatchOutput",
"clean": "rm -rf dist",
"clean": "rm -rf dist tsconfig.tsbuildinfo",
"type-check": "NODE_OPTIONS=\"--max-old-space-size=2048 --max-semi-space-size=128\" tsc --project tsconfig.json --noEmit",
"test": "echo \"No tests specified for logging package\"",
"lint": "eslint .",

3
pnpm-lock.yaml generated
View File

@ -255,9 +255,6 @@ importers:
'@customer-portal/domain':
specifier: workspace:*
version: link:../../packages/domain
'@customer-portal/logging':
specifier: workspace:*
version: link:../../packages/logging
'@customer-portal/validation':
specifier: workspace:*
version: link:../../packages/validation