diff --git a/.env.dev.example b/.env.dev.example deleted file mode 100644 index 20084b04..00000000 --- a/.env.dev.example +++ /dev/null @@ -1,103 +0,0 @@ -# ๐Ÿš€ Customer Portal - Development Environment -# Copy this file to .env for local development -# This configuration is optimized for development with hot-reloading - -# ============================================================================= -# ๐ŸŒ APPLICATION CONFIGURATION -# ============================================================================= -NODE_ENV=development -APP_NAME=customer-portal-bff -BFF_PORT=4000 -APP_BASE_URL=http://localhost:3000 - -# ============================================================================= -# ๐Ÿ” SECURITY CONFIGURATION (Development) -# ============================================================================= -# Development JWT secret (OK to use simple secret for local dev) -JWT_SECRET=dev_secret_for_local_development_minimum_32_chars_long -JWT_EXPIRES_IN=7d - -# Password Hashing (Minimum rounds for security compliance) -BCRYPT_ROUNDS=10 - -# ============================================================================= -# ๐Ÿ—„๏ธ DATABASE & CACHE (Development) -# ============================================================================= -# Local Docker services -DATABASE_URL=postgresql://dev:dev@localhost:5432/portal_dev?schema=public -REDIS_URL=redis://localhost:6379 - -# ============================================================================= -# ๐ŸŒ NETWORK & CORS (Development) -# ============================================================================= -# Allow local frontend -CORS_ORIGIN=http://localhost:3000 -TRUST_PROXY=false - -# ============================================================================= -# ๐Ÿšฆ RATE LIMITING (Development) -# ============================================================================= -# Relaxed rate limiting for development -RATE_LIMIT_TTL=60000 -RATE_LIMIT_LIMIT=100 -AUTH_RATE_LIMIT_TTL=900000 -AUTH_RATE_LIMIT_LIMIT=3 - -# ============================================================================= -# ๐Ÿข EXTERNAL INTEGRATIONS (Development) -# ============================================================================= -# WHMCS Integration (Demo/Test Environment) -WHMCS_BASE_URL=https://demo.whmcs.com -WHMCS_API_IDENTIFIER=your_demo_identifier -WHMCS_API_SECRET=your_demo_secret -WHMCS_WEBHOOK_SECRET=your_dev_webhook_secret - -# Salesforce Integration (Sandbox Environment) -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 -SF_WEBHOOK_SECRET=your_dev_webhook_secret - -# ============================================================================= -# ๐Ÿ“Š LOGGING (Development) -# ============================================================================= -# Verbose logging for development -LOG_LEVEL=debug - -# ============================================================================= -# ๐ŸŽฏ FRONTEND CONFIGURATION (Development) -# ============================================================================= -# NEXT_PUBLIC_ variables are exposed to browser -NEXT_PUBLIC_APP_NAME=Customer Portal (Dev) -NEXT_PUBLIC_APP_VERSION=1.0.0-dev -NEXT_PUBLIC_API_BASE=http://localhost:4000 -NEXT_PUBLIC_ENABLE_DEVTOOLS=true - -# ============================================================================= -# ๐ŸŽ›๏ธ DEVELOPMENT OPTIONS -# ============================================================================= -# Node.js options for development -NODE_OPTIONS=--no-deprecation - -# ============================================================================= -# โœ‰๏ธ EMAIL (SendGrid) - Development -# ============================================================================= -SENDGRID_API_KEY= -EMAIL_FROM=no-reply@localhost.test -EMAIL_FROM_NAME=Assist Solutions (Dev) -EMAIL_ENABLED=true -EMAIL_USE_QUEUE=true -SENDGRID_SANDBOX=true -# Optional: dynamic template IDs (use {{resetUrl}} in reset template) -EMAIL_TEMPLATE_RESET= -EMAIL_TEMPLATE_WELCOME= - -# ============================================================================= -# ๐Ÿš€ QUICK START (Development) -# ============================================================================= -# 1. Copy this template: cp .env.dev.example .env -# 2. Edit .env with your development values -# 3. Start services: pnpm dev:start -# 4. Start apps: pnpm dev -# 5. Access: Frontend http://localhost:3000, Backend http://localhost:4000 diff --git a/.env.example b/.env.example index 252dc20e..702afd19 100644 --- a/.env.example +++ b/.env.example @@ -1,72 +1,93 @@ -# ====== Core ====== -NODE_ENV=production +plesk# ๐Ÿš€ Customer Portal - Development Environment Example +# Copy this file to .env for local development +# This configuration is optimized for development with hot-reloading -# ====== Frontend (Next.js) ====== -NEXT_PUBLIC_APP_NAME=Customer Portal -NEXT_PUBLIC_APP_VERSION=1.0.0 -# If using Plesk single domain with /api proxied to backend, set to your main domain -# Example: https://portal.example.com or https://example.com -NEXT_PUBLIC_API_BASE=https://CHANGE_THIS +# ============================================================================= +# ๐Ÿ—„๏ธ DATABASE CONFIGURATION (Development) +# ============================================================================= +DATABASE_URL="postgresql://dev:dev@localhost:5432/portal_dev?schema=public" -# ====== Backend (NestJS BFF) ====== +# ============================================================================= +# ๐Ÿ”ด REDIS CONFIGURATION (Development) +# ============================================================================= +REDIS_URL="redis://localhost:6379" + +# ============================================================================= +# ๐ŸŒ APPLICATION CONFIGURATION (Development) +# ============================================================================= +# Backend Configuration BFF_PORT=4000 -APP_BASE_URL=https://CHANGE_THIS +APP_NAME="customer-portal-bff" +NODE_ENV="development" -# ====== Database (PostgreSQL) ====== -POSTGRES_DB=portal_prod -POSTGRES_USER=portal -POSTGRES_PASSWORD=CHANGE_THIS +# Frontend Configuration (NEXT_PUBLIC_ variables are exposed to browser) +NEXT_PORT=3000 +NEXT_PUBLIC_APP_NAME="Customer Portal (Dev)" +NEXT_PUBLIC_APP_VERSION="1.0.0-dev" +NEXT_PUBLIC_API_BASE="http://localhost:4000" +NEXT_PUBLIC_ENABLE_DEVTOOLS="true" -# Prisma style DATABASE_URL for Postgres inside Compose network -# For Plesk Compose, hostname is the service name 'database' -DATABASE_URL=postgresql://portal:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB}?schema=public +# ============================================================================= +# ๐Ÿ” SECURITY CONFIGURATION (Development) +# ============================================================================= +# JWT Secret (Development - OK to use simple secret) +JWT_SECRET="HjHsUyTE3WhPn5N07iSvurdV4hk2VEkIuN+lIflHhVQ=" +JWT_EXPIRES_IN="7d" -# ====== Redis ====== -REDIS_URL=redis://cache:6379/0 +# Password Hashing (Minimum rounds for security compliance) +BCRYPT_ROUNDS=10 -# ====== Security ====== -JWT_SECRET=CHANGE_THIS -JWT_EXPIRES_IN=7d -BCRYPT_ROUNDS=12 +# CORS (Allow local frontend) +CORS_ORIGIN="http://localhost:3000" -# ====== CORS ====== -# If portal: https://portal.example.com ; if root domain: https://example.com -CORS_ORIGIN=https://CHANGE_THIS +# ============================================================================= +# ๐Ÿข EXTERNAL API CONFIGURATION (Development) +# ============================================================================= +# WHMCS Integration (use your actual credentials) +WHMCS_BASE_URL="https://accounts.asolutions.co.jp" +WHMCS_API_IDENTIFIER="your_whmcs_api_identifier" +WHMCS_API_SECRET="your_whmcs_api_secret" -# ====== External APIs (optional) ====== -WHMCS_BASE_URL= -WHMCS_API_IDENTIFIER= -WHMCS_API_SECRET= -SF_LOGIN_URL= -SF_CLIENT_ID= -SF_PRIVATE_KEY_PATH=/app/secrets/salesforce.key -SF_USERNAME= +# Salesforce Integration (use your actual credentials) +SF_LOGIN_URL="https://asolutions.my.salesforce.com" +SF_CLIENT_ID="your_salesforce_client_id" +SF_PRIVATE_KEY_PATH="./secrets/sf-private.key" +SF_USERNAME="your_salesforce_username" -# ====== Salesforce Pricing ====== -# Portal Pricebook ID for product pricing (defaults to Portal pricebook) -PORTAL_PRICEBOOK_ID=01sTL000008eLVlYAM +# Salesforce Pricing +PORTAL_PRICEBOOK_ID="01sTL000008eLVlYAM" -# ====== Logging ====== -LOG_LEVEL=info -LOG_FORMAT=json +# ============================================================================= +# ๐Ÿ“Š LOGGING CONFIGURATION (Development) +# ============================================================================= +LOG_LEVEL="debug" +LOG_FORMAT="pretty" -# ====== Email (SendGrid) ====== -# API key: https://app.sendgrid.com/settings/api_keys -SENDGRID_API_KEY= -# From address for outbound email -EMAIL_FROM=no-reply@yourdomain.com -EMAIL_FROM_NAME=Assist Solutions -# Master email switch -EMAIL_ENABLED=true -# Queue emails for async delivery (recommended) -EMAIL_USE_QUEUE=true -# Enable SendGrid sandbox mode (use true in non-prod to avoid delivery) -SENDGRID_SANDBOX=false -# Optional: dynamic template IDs (use {{resetUrl}} for reset template) -EMAIL_TEMPLATE_RESET= -EMAIL_TEMPLATE_WELCOME= +# ============================================================================= +# ๐Ÿ“ง EMAIL CONFIGURATION (Development) +# ============================================================================= +# SendGrid (optional for development) +SENDGRID_API_KEY="" +EMAIL_FROM="no-reply@yourdomain.com" +EMAIL_FROM_NAME="Assist Solutions" +EMAIL_ENABLED=false +EMAIL_USE_QUEUE=false +SENDGRID_SANDBOX=true +EMAIL_TEMPLATE_RESET="" +EMAIL_TEMPLATE_WELCOME="" -# ====== Node options ====== -NODE_OPTIONS=--max-old-space-size=512 +# ============================================================================= +# ๐ŸŽ›๏ธ DEVELOPMENT CONFIGURATION +# ============================================================================= +# Node.js options for development +NODE_OPTIONS="--no-deprecation" + +# ============================================================================= +# ๐Ÿณ DOCKER DEVELOPMENT NOTES +# ============================================================================= +# For Docker development services (PostgreSQL + Redis only): +# 1. Run: pnpm dev:start +# 2. Frontend and Backend run locally (outside containers) for hot-reloading +# 3. Only database and cache services run in containers diff --git a/.env.plesk b/.env.plesk new file mode 100644 index 00000000..1778ac6a --- /dev/null +++ b/.env.plesk @@ -0,0 +1,7 @@ + +# GitHub Container Registry Authentication +# Replace with your actual GitHub personal access token (with read:packages scope) +GITHUB_TOKEN=your_github_personal_access_token_here + +# Security note: Keep this file secure and don't commit it to Git +# This token allows pulling private images from GitHub Container Registry diff --git a/.env.production.example b/.env.production.example deleted file mode 100644 index d5ad59da..00000000 --- a/.env.production.example +++ /dev/null @@ -1,117 +0,0 @@ -# ๐Ÿš€ Customer Portal - Production Environment -# Copy this file to .env for production deployment -# This configuration is optimized for production with security and performance - -# ============================================================================= -# ๐ŸŒ APPLICATION CONFIGURATION -# ============================================================================= -NODE_ENV=production -APP_NAME=customer-portal-bff -BFF_PORT=4000 -APP_BASE_URL=https://portal.yourdomain.com - -# ============================================================================= -# ๐Ÿ” SECURITY CONFIGURATION (Production) -# ============================================================================= -# CRITICAL: Generate with: openssl rand -base64 32 -JWT_SECRET=GENERATE_SECURE_JWT_SECRET_HERE_MINIMUM_32_CHARS -JWT_EXPIRES_IN=7d - -# Password Hashing (High rounds for security) -BCRYPT_ROUNDS=12 - -# ============================================================================= -# ๐Ÿ—„๏ธ DATABASE & CACHE (Production) -# ============================================================================= -# Docker internal networking (container names as hostnames) -DATABASE_URL=postgresql://portal:YOUR_SECURE_DB_PASSWORD@database:5432/portal_prod?schema=public -REDIS_URL=redis://cache:6379 - -# ============================================================================= -# ๐ŸŒ NETWORK & CORS (Production) -# ============================================================================= -# Your production domain -CORS_ORIGIN=https://yourdomain.com -TRUST_PROXY=true - -# ============================================================================= -# ๐Ÿšฆ RATE LIMITING (Production) -# ============================================================================= -# Strict rate limiting for production -RATE_LIMIT_TTL=60000 -RATE_LIMIT_LIMIT=100 -AUTH_RATE_LIMIT_TTL=900000 -AUTH_RATE_LIMIT_LIMIT=3 - -# ============================================================================= -# ๐Ÿข EXTERNAL INTEGRATIONS (Production) -# ============================================================================= -# WHMCS Integration (Production Environment) -WHMCS_BASE_URL=https://your-whmcs-domain.com -WHMCS_API_IDENTIFIER=your_production_identifier -WHMCS_API_SECRET=your_production_secret -WHMCS_WEBHOOK_SECRET=your_whmcs_webhook_secret - -# Salesforce Integration (Production Environment) -SF_LOGIN_URL=https://login.salesforce.com -SF_CLIENT_ID=your_production_client_id -SF_PRIVATE_KEY_PATH=/app/secrets/sf-prod.key -SF_USERNAME=production@yourcompany.com -SF_WEBHOOK_SECRET=your_salesforce_webhook_secret - -# ============================================================================= -# ๐Ÿ“Š LOGGING (Production) -# ============================================================================= -# Production logging level -LOG_LEVEL=info - -# ============================================================================= -# ๐ŸŽฏ FRONTEND CONFIGURATION (Production) -# ============================================================================= -# NEXT_PUBLIC_ variables are exposed to browser -NEXT_PUBLIC_APP_NAME=Customer Portal -NEXT_PUBLIC_APP_VERSION=1.0.0 -NEXT_PUBLIC_API_BASE=https://yourdomain.com -NEXT_PUBLIC_ENABLE_DEVTOOLS=false - -# ============================================================================= -# ๐ŸŽ›๏ธ PRODUCTION OPTIONS -# ============================================================================= -# Node.js options for production -NODE_OPTIONS=--max-old-space-size=2048 - -# ============================================================================= -# โœ‰๏ธ EMAIL (SendGrid) - Production -# ============================================================================= -# Create and store securely (e.g., KMS/Secrets Manager) -SENDGRID_API_KEY= -EMAIL_FROM=no-reply@yourdomain.com -EMAIL_FROM_NAME=Assist Solutions -EMAIL_ENABLED=true -EMAIL_USE_QUEUE=true -SENDGRID_SANDBOX=false -# Optional: Dynamic Template IDs (recommended) -EMAIL_TEMPLATE_RESET= -EMAIL_TEMPLATE_WELCOME= - -# ============================================================================= -# ๐Ÿ”’ PRODUCTION SECURITY CHECKLIST -# ============================================================================= -# โœ… Replace ALL default/demo values with real credentials -# โœ… Use strong, unique passwords and secrets (minimum 32 characters for JWT) -# โœ… Ensure SF_PRIVATE_KEY_PATH points to actual key file -# โœ… Set correct CORS_ORIGIN for your domain -# โœ… Use HTTPS URLs for all external services -# โœ… Verify DATABASE_URL password matches docker-compose.yml -# โœ… Test all integrations before going live -# โœ… Configure webhook secrets for security -# โœ… Set appropriate rate limiting values -# โœ… Enable trust proxy if behind reverse proxy - -# ============================================================================= -# ๐Ÿš€ QUICK START (Production) -# ============================================================================= -# 1. Copy this template: cp .env.production.example .env -# 2. Edit .env with your production values (REQUIRED!) -# 3. Deploy: pnpm prod:deploy -# 4. Access: https://yourdomain.com diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..49a65b86 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,93 @@ +name: Build & Push Images + +on: + push: + branches: [main] + workflow_dispatch: # Allow manual triggers + +env: + REGISTRY: ghcr.io + IMAGE_NAME_PREFIX: ntumurbars/customer-portal + +jobs: + build-and-push: + name: Build & Push Docker Images + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for frontend + id: meta-frontend + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_PREFIX }}-frontend + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=sha,prefix=main- + + - name: Extract metadata for backend + id: meta-backend + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_PREFIX }}-backend + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=sha,prefix=main- + + - name: Build and push frontend image + uses: docker/build-push-action@v5 + with: + context: . + file: ./apps/portal/Dockerfile + platforms: linux/amd64 + push: true + tags: ${{ steps.meta-frontend.outputs.tags }} + labels: ${{ steps.meta-frontend.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Build and push backend image + uses: docker/build-push-action@v5 + with: + context: . + file: ./apps/bff/Dockerfile + platforms: linux/amd64 + push: true + tags: ${{ steps.meta-backend.outputs.tags }} + labels: ${{ steps.meta-backend.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Build Summary + run: | + echo "## ๐Ÿš€ Build Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Frontend Image:** \`${{ steps.meta-frontend.outputs.tags }}\`" >> $GITHUB_STEP_SUMMARY + echo "**Backend Image:** \`${{ steps.meta-backend.outputs.tags }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿ“ฆ Images Built:" >> $GITHUB_STEP_SUMMARY + echo "- **Frontend**: [ghcr.io/${{ env.IMAGE_NAME_PREFIX }}-frontend](https://github.com/NTumurbars/customer-portal/pkgs/container/customer-portal-frontend)" >> $GITHUB_STEP_SUMMARY + echo "- **Backend**: [ghcr.io/${{ env.IMAGE_NAME_PREFIX }}-backend](https://github.com/NTumurbars/customer-portal/pkgs/container/customer-portal-backend)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### ๐Ÿš€ Next Steps:" >> $GITHUB_STEP_SUMMARY + echo "1. **SSH to Plesk server** and run:" >> $GITHUB_STEP_SUMMARY + echo " \`\`\`bash" >> $GITHUB_STEP_SUMMARY + echo " docker compose -f compose-plesk.yaml pull" >> $GITHUB_STEP_SUMMARY + echo " docker compose -f compose-plesk.yaml up -d" >> $GITHUB_STEP_SUMMARY + echo " \`\`\`" >> $GITHUB_STEP_SUMMARY + echo "2. **Or update via Plesk UI**: Docker โ†’ Stacks โ†’ customer-portal โ†’ Pull โ†’ Up" >> $GITHUB_STEP_SUMMARY diff --git a/ARCHITECTURE_RECOMMENDATION.md b/ARCHITECTURE_RECOMMENDATION.md deleted file mode 100644 index f2994454..00000000 --- a/ARCHITECTURE_RECOMMENDATION.md +++ /dev/null @@ -1,128 +0,0 @@ -# Order Services Architecture Recommendation - -## Recommended Structure: Enhanced Separation of Concerns - -### 1. **Controller Layer** (`orders.controller.ts`) -**Responsibility**: API contract and basic validation -- DTO validation (format, types, required fields) -- Authentication/authorization -- HTTP response handling -- Minimal business logic - -### 2. **Orchestrator Layer** (`order-orchestrator.service.ts`) -**Responsibility**: Workflow coordination and transaction management -- Coordinates the order creation flow -- Manages transaction boundaries -- Handles high-level error scenarios -- Calls other services in correct sequence - -### 3. **Validator Layer** (`order-validator.service.ts`) -**Responsibility**: ALL validation logic (business + technical) -```typescript -class OrderValidator { - // API-level validation (move from DTO) - validateRequestFormat(body: any): CreateOrderBody - - // Business validation (current) - validateUserMapping(userId: string): Promise - validatePaymentMethod(userId: string, clientId: number): Promise - validateSKUs(skus: string[], pricebookId: string): Promise - validateBusinessRules(orderType: string, skus: string[]): void - validateInternetDuplication(userId: string, clientId: number): Promise - - // Complete validation (orchestrates all checks) - async validateCompleteOrder(userId: string, body: any): Promise<{ - validatedBody: CreateOrderBody, - userMapping: UserMapping - }> -} -``` - -### 4. **Builder Layer** (`order-builder.service.ts`) -**Responsibility**: Data transformation and mapping -- Transform business data to Salesforce format -- Apply business rules to field mapping -- Handle conditional field logic - -### 5. **ItemBuilder Layer** (`order-item-builder.service.ts`) -**Responsibility**: Order item creation and pricing -- Create order line items -- Handle pricing calculations -- Manage product metadata - -## Benefits of This Structure: - -### โœ… **Single Responsibility Principle** -- Each service has one clear purpose -- Easy to test and maintain -- Clear boundaries - -### โœ… **Validator as Single Source of Truth** -- All validation logic in one place -- Easy to find and modify validation rules -- Consistent error handling - -### โœ… **Orchestrator for Workflow Management** -- Clear sequence of operations -- Transaction management -- Error recovery logic - -### โœ… **Testability** -- Each layer can be unit tested independently -- Mock dependencies easily -- Clear input/output contracts - -## Implementation Changes: - -### Move DTO validation to Validator: -```typescript -// Before: Controller has DTO validation -@Body() body: CreateOrderDto - -// After: Controller accepts any, Validator validates -@Body() body: any -``` - -### Enhanced Validator: -```typescript -async validateCompleteOrder(userId: string, rawBody: any) { - // 1. Format validation (was DTO) - const body = this.validateRequestFormat(rawBody); - - // 2. Business validation (current) - const userMapping = await this.validateUserMapping(userId); - await this.validatePaymentMethod(userId, userMapping.whmcsClientId); - - // 3. SKU validation (move here) - const pricebookId = await this.findPricebookId(); - await this.validateSKUs(body.skus, pricebookId); - this.validateBusinessRules(body.orderType, body.skus); - - // 4. Order-specific validation - if (body.orderType === "Internet") { - await this.validateInternetDuplication(userId, userMapping.whmcsClientId); - } - - return { validatedBody: body, userMapping, pricebookId }; -} -``` - -### Simplified Orchestrator: -```typescript -async createOrder(userId: string, rawBody: any) { - // 1. Complete validation - const { validatedBody, userMapping, pricebookId } = - await this.validator.validateCompleteOrder(userId, rawBody); - - // 2. Build order - const orderFields = this.builder.buildOrderFields(validatedBody, userMapping, pricebookId); - - // 3. Create in Salesforce - const created = await this.sf.sobject("Order").create(orderFields); - - // 4. Create items - await this.itemBuilder.createOrderItemsFromSKUs(created.id, validatedBody.skus, pricebookId); - - return { sfOrderId: created.id, status: "Created" }; -} -``` diff --git a/DEPLOYMENT-GUIDE.md b/DEPLOYMENT-GUIDE.md new file mode 100644 index 00000000..f4919d86 --- /dev/null +++ b/DEPLOYMENT-GUIDE.md @@ -0,0 +1,141 @@ +# ๐Ÿš€ Pre-built Images Deployment Guide + +This guide shows how to deploy using pre-built Docker images instead of building on Plesk. + +## Benefits +- โœ… No build failures on Plesk +- โœ… Faster deployments (no compilation time) +- โœ… Consistent images across environments +- โœ… Better security (build in controlled environment) +- โœ… Easy rollbacks and version control + +## Prerequisites + +1. **GitHub Account** (for free container registry) +2. **Docker installed locally** (for building images) +3. **Plesk with Docker extension** + +## Step 1: Setup GitHub Container Registry + +1. Go to GitHub โ†’ Settings โ†’ Developer settings โ†’ Personal access tokens โ†’ Tokens (classic) +2. Create a new token with these permissions: + - `write:packages` (to push images) + - `read:packages` (to pull images) +3. Save the token securely + +## Step 2: Login to GitHub Container Registry + +```bash +# Replace YOUR_USERNAME and YOUR_TOKEN +echo "YOUR_TOKEN" | docker login ghcr.io -u YOUR_USERNAME --password-stdin +``` + +## Step 3: Update Build Script + +Edit `scripts/build-and-push.sh`: +```bash +# Change this line: +NAMESPACE="your-github-username" # Replace with your actual GitHub username +``` + +## Step 4: Build and Push Images + +```bash +# Build and push with version tag +./scripts/build-and-push.sh v1.0.0 + +# Or build and push as latest +./scripts/build-and-push.sh +``` + +## Step 5: Update Plesk Compose File + +Edit `compose-plesk.yaml` and replace: +```yaml +image: ghcr.io/your-github-username/portal-frontend:latest +image: ghcr.io/your-github-username/portal-backend:latest +``` + +With your actual GitHub username. + +## Step 6: Deploy to Plesk + +1. **Upload compose-plesk.yaml** to your Plesk server +2. **Plesk โ†’ Docker โ†’ Add Stack** +3. **Paste the contents** of `compose-plesk.yaml` +4. **Deploy** + +## Step 7: Configure Plesk Reverse Proxy + +1. **Plesk โ†’ Domains โ†’ your-domain.com โ†’ Apache & Nginx Settings** +2. **Add to "Additional directives for HTTP":** +```nginx +location / { + proxy_pass http://127.0.0.1:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; +} + +location /api { + proxy_pass http://127.0.0.1:4000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; +} +``` + +## Step 8: Secure Database Access + +Add to Plesk Firewall: +``` +# Allow Docker bridge network +ACCEPT from 172.17.0.0/16 to any port 5432 +ACCEPT from 172.17.0.0/16 to any port 6379 + +# Deny external access to database +DROP from any to any port 5432 +DROP from any to any port 6379 +``` + +## Updating Your Application + +1. **Make code changes** +2. **Build and push new images:** + ```bash + ./scripts/build-and-push.sh v1.0.1 + ``` +3. **Update compose-plesk.yaml** with new version tag +4. **Redeploy in Plesk** + +## Troubleshooting + +### Images not found +- Check if you're logged in: `docker login ghcr.io` +- Verify image names match your GitHub username +- Ensure images are public or Plesk can authenticate + +### Build failures +- Run locally first: `docker build -f apps/portal/Dockerfile .` +- Check Docker logs for specific errors +- Ensure all dependencies are in package.json + +### Connection issues +- Verify firewall allows Docker bridge network (172.17.0.0/16) +- Check that DATABASE_URL uses correct IP (172.17.0.1) +- Test database connection from backend container + +## Security Notes + +- Database is only accessible from Docker bridge network +- Backend API is only accessible via reverse proxy +- Use strong passwords and JWT secrets +- Consider using Docker secrets for sensitive data +- Regularly update base images for security patches diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 00000000..46cccc86 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,75 @@ +# ๐Ÿš€ Deployment Guide + +## ๐Ÿ“ **Environment Files Overview** + +### **Development:** +- `.env` - Your local development environment (active) +- `.env.example` - Development template for new developers + +### **Production:** +- `.env.production` - Production environment for Plesk deployment +- `compose-plesk.yaml` - Docker Stack definition + +## ๐Ÿ”ง **Plesk Deployment Steps** + +### **Step 1: Authenticate Docker (One-time)** +```bash +# SSH to Plesk server +echo "YOUR_GITHUB_TOKEN" | docker login ghcr.io -u ntumurbars --password-stdin +``` + +### **Step 2: Upload Files to Plesk** +Upload these files to your domain directory: +1. `compose-plesk.yaml` - Docker Stack definition +2. `.env.production` - Environment variables (rename to `.env`) + +### **Step 3: Deploy Stack** +1. **Plesk โ†’ Docker โ†’ Stacks โ†’ Add Stack** +2. **Project name**: `customer-portal` +3. **Method**: Upload file or paste `compose-plesk.yaml` content +4. **Deploy** + +### **Step 4: Configure Nginx Proxy** +1. **Plesk โ†’ Websites & Domains โ†’ yourdomain.com โ†’ Docker Proxy Rules** +2. **Add rule**: `/` โ†’ `portal-frontend` โ†’ port `3000` +3. **Add rule**: `/api` โ†’ `portal-backend` โ†’ port `4000` + +## ๐Ÿ”„ **Update Workflow** + +### **When You Push Code:** +1. **GitHub Actions** builds new images automatically +2. **SSH to Plesk** and update: + ```bash + cd /var/www/vhosts/yourdomain.com/httpdocs/ + docker compose -f compose-plesk.yaml pull + docker compose -f compose-plesk.yaml up -d + ``` + +## ๐Ÿ” **Environment Variables** + +Your compose file uses these key variables from `.env.production`: + +### **Database:** +- `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD` +- `DATABASE_URL` - Full connection string + +### **Application:** +- `JWT_SECRET`, `CORS_ORIGIN` +- `NEXT_PUBLIC_API_BASE`, `NEXT_PUBLIC_APP_NAME` + +### **External APIs:** +- `WHMCS_BASE_URL`, `WHMCS_API_IDENTIFIER`, `WHMCS_API_SECRET` +- `SF_LOGIN_URL`, `SF_CLIENT_ID`, `SF_USERNAME` + +### **Email & Logging:** +- `SENDGRID_API_KEY`, `EMAIL_FROM` +- `LOG_LEVEL`, `LOG_FORMAT` + +## โœ… **Ready to Deploy!** + +Your setup is clean and production-ready: +- โœ… Environment variables properly configured +- โœ… Docker secrets via environment variables +- โœ… Database and Redis secured (localhost only) +- โœ… Automated image building +- โœ… Clean file structure diff --git a/FINAL_CODE_QUALITY_REPORT.md b/FINAL_CODE_QUALITY_REPORT.md deleted file mode 100644 index 7f2b2179..00000000 --- a/FINAL_CODE_QUALITY_REPORT.md +++ /dev/null @@ -1,181 +0,0 @@ -# ๐ŸŽฏ Final Code Quality & Documentation Compliance Report - -## ๐Ÿ† **Overall Assessment: EXCELLENT** - -The order system demonstrates **enterprise-grade code quality** with proper architecture, maintainable patterns, and full documentation compliance. - ---- - -## โœ… **Architecture Quality: A+** - -### **Clean Architecture Implementation** -```typescript -Controller (Thin API Layer) - โ†“ -OrderValidator (Complete Validation) - โ†“ -OrderOrchestrator (Workflow Coordination) - โ†“ -OrderBuilder + OrderItemBuilder (Data Transformation) - โ†“ -Salesforce (External System) -``` - -**โœ… Strengths:** -- **Single Responsibility Principle**: Each service has one clear purpose -- **Dependency Injection**: Proper NestJS patterns throughout -- **Separation of Concerns**: API, validation, business logic, and data layers clearly separated -- **Testability**: Each component can be unit tested independently - ---- - -## โœ… **Field Mapping: A+** - -### **No Hardcoded Salesforce Fields** -```typescript -// โœ… GOOD: Using field mapping -orderFields[fields.order.internetPlanTier] = serviceProduct.internetPlanTier; -orderFields[fields.order.accessMode] = config.accessMode; - -// โŒ BAD: Hardcoded (eliminated) -// orderFields.Internet_Plan_Tier__c = serviceProduct.internetPlanTier; -``` - -**โœ… Benefits:** -- **Environment Configurable**: All field names can be overridden via `process.env` -- **Maintainable**: Single source of truth in `field-map.ts` -- **Flexible**: Easy to adapt to different Salesforce orgs -- **Type Safe**: Full TypeScript support with proper interfaces - ---- - -## โœ… **Validation Logic: A+** - -### **Comprehensive Validation Pipeline** -```typescript -validateCompleteOrder() { - 1. Format Validation (replaces DTO) - 2. User Mapping Validation - 3. Payment Method Validation - 4. SKU Existence Validation - 5. Business Rules Validation - 6. Order-specific Validation -} -``` - -**โœ… Validation Coverage:** -- **Format**: Field types, required fields, enum values -- **Business**: User mapping, payment methods, duplicate orders -- **Data**: SKU existence in Salesforce, business rule compliance -- **Security**: Proper error handling without sensitive data exposure [[memory:6689308]] - ---- - -## โœ… **Documentation Compliance: A** - -### **Salesforce Order Fields - 100% Compliant** - -| Documentation Requirement | Implementation Status | -|---------------------------|----------------------| -| **Core Fields (5)** | โœ… `AccountId`, `EffectiveDate`, `Status`, `Pricebook2Id`, `Order_Type__c` | -| **Activation Fields (3)** | โœ… `Activation_Type__c`, `Activation_Scheduled_At__c`, `Activation_Status__c` | -| **Internet Fields (5)** | โœ… `Internet_Plan_Tier__c`, `Installation_Type__c`, `Weekend_Install__c`, `Access_Mode__c`, `Hikari_Denwa__c` | -| **SIM Fields (4+11)** | โœ… `SIM_Type__c`, `EID__c`, `SIM_Voice_Mail__c`, `SIM_Call_Waiting__c` + all MNP fields | -| **VPN Fields (1)** | โœ… `VPN_Region__c` | - -### **API Requirements - Compliant** -- โœ… **Server-side checks**: WHMCS mapping โœ“, payment method โœ“ -- โœ… **Order status**: Creates "Pending Review" status โœ“ -- โœ… **Return format**: `{ sfOrderId, status }` โœ“ - -### **โš ๏ธ Minor Documentation Discrepancy** -**Issue**: Documentation shows item-based API structure, implementation uses SKU-based structure. - -**Documentation:** -```json -{ "items": [{ "productId": "...", "billingCycle": "..." }] } -``` - -**Implementation:** -```json -{ "orderType": "Internet", "skus": ["INTERNET-SILVER-HOME-1G"] } -``` - -**Recommendation**: Update documentation to match the superior SKU-based implementation. - ---- - -## โœ… **Code Quality Standards: A+** - -### **Error Handling** -```typescript -// โœ… Proper error handling with context -this.logger.error({ error, orderFields }, "Failed to create Salesforce Order"); -throw new BadRequestException("Order creation failed"); -``` - -### **Logging** -```typescript -// โœ… Structured logging throughout -this.logger.log({ userId, orderType, skuCount }, "Order validation completed"); -``` - -### **Type Safety** -```typescript -// โœ… Strong typing everywhere -async validateCompleteOrder(userId: string, rawBody: any): Promise<{ - validatedBody: CreateOrderBody; - userMapping: UserMapping; - pricebookId: string; -}> -``` - ---- - -## โœ… **Production Readiness: A+** - -### **Security** [[memory:6689308]] -- โœ… **Input validation**: Comprehensive DTO validation -- โœ… **Error handling**: No sensitive data exposure -- โœ… **Authentication**: JWT guards on all endpoints -- โœ… **Authorization**: User-specific data access - -### **Performance** -- โœ… **Efficient validation**: Single validation pipeline -- โœ… **Database optimization**: Proper SOQL queries -- โœ… **Error recovery**: Graceful handling of external API failures - -### **Maintainability** -- โœ… **Modular design**: Easy to extend and modify -- โœ… **Clear interfaces**: Well-defined contracts between layers -- โœ… **Consistent patterns**: Uniform error handling and logging -- โœ… **Documentation**: Comprehensive inline documentation - ---- - -## ๐ŸŽฏ **Final Recommendations** - -### **Immediate Actions: None Required** โœ… -The code is production-ready as-is. - -### **Future Enhancements (Optional)** -1. **API Documentation Update**: Align docs with SKU-based implementation -2. **Integration Tests**: Add end-to-end order flow tests -3. **Monitoring**: Add business metrics for order success rates - ---- - -## ๐Ÿ† **Summary** - -This order system represents **exemplary enterprise software development**: - -- โœ… **Clean Architecture**: Proper separation of concerns -- โœ… **Maintainable Code**: No hardcoded values, configurable fields -- โœ… **Production Ready**: Comprehensive validation, error handling, security -- โœ… **Documentation Compliant**: All Salesforce fields properly mapped -- โœ… **Type Safe**: Full TypeScript coverage -- โœ… **Testable**: Modular design enables comprehensive testing - -**Grade: A+ (Excellent)** - -The system is ready for production deployment with confidence! ๐Ÿš€ diff --git a/SECURITY_AUDIT_REPORT.md b/SECURITY_AUDIT_REPORT.md deleted file mode 100644 index 0d67853b..00000000 --- a/SECURITY_AUDIT_REPORT.md +++ /dev/null @@ -1,202 +0,0 @@ -# ๐Ÿ”’ COMPREHENSIVE SECURITY AUDIT REPORT - -**Date**: August 28, 2025 -**Auditor**: AI Security Assistant -**Scope**: Complete NestJS BFF Application Security Review -**Status**: โœ… **PRODUCTION READY** - -## ๐ŸŽฏ **EXECUTIVE SUMMARY** - -The application has been upgraded to implement **2025 NestJS Security Best Practices** with a comprehensive **Global Authentication Architecture**. All critical security vulnerabilities have been addressed and the system is now **ENTERPRISE-GRADE SECURE**. - -### **๐Ÿ† SECURITY GRADE: A+** - -## ๐Ÿ›ก๏ธ **SECURITY ARCHITECTURE OVERVIEW** - -### **Global Authentication Guard (2025 Standard)** -- โœ… **Single Point of Control**: All authentication handled by `GlobalAuthGuard` -- โœ… **JWT Validation**: Automatic token signature and expiration checking -- โœ… **Token Blacklist Integration**: Real-time revoked token checking -- โœ… **Decorator-Based Public Routes**: Clean `@Public()` decorator system -- โœ… **Comprehensive Logging**: Security event tracking and monitoring - -### **Authentication Flow** -```typescript -Request โ†’ GlobalAuthGuard โ†’ @Public() Check โ†’ JWT Validation โ†’ Blacklist Check โ†’ Route Handler -``` - -## ๐Ÿ” **DETAILED SECURITY AUDIT** - -### **1. Authentication & Authorization** โœ… **SECURE** - -| Component | Status | Details | -|-----------|--------|---------| -| JWT Strategy | โœ… SECURE | Proper signature validation, no body parsing interference | -| Token Blacklist | โœ… SECURE | Redis-based, automatic cleanup, logout integration | -| Global Guard | โœ… SECURE | Centralized, comprehensive, production-ready | -| Public Routes | โœ… SECURE | Properly marked, validated, minimal exposure | -| Admin Routes | โœ… SECURE | Additional AdminGuard protection | - -### **2. Public Route Security** โœ… **VALIDATED** - -| Route | Purpose | Security Measures | -|-------|---------|-------------------| -| `POST /auth/signup` | User registration | Rate limiting, input validation | -| `POST /auth/login` | User authentication | Rate limiting, LocalAuthGuard | -| `POST /auth/request-password-reset` | Password reset | Rate limiting, email validation | -| `POST /auth/reset-password` | Password reset | Rate limiting, token validation | -| `POST /auth/link-whmcs` | WHMCS linking | Rate limiting, input validation | -| `POST /auth/set-password` | Password setting | Rate limiting, input validation | -| `POST /auth/check-password-needed` | Password status | Input validation | -| `GET /health` | Health checks | No sensitive data exposure | -| `POST /webhooks/*` | Webhook endpoints | HMAC signature verification | - -### **3. Protected Route Security** โœ… **VALIDATED** - -| Route Category | Protection Level | Validation | -|----------------|------------------|------------| -| User Management (`/api/me`) | JWT + Blacklist | โœ… Tested | -| Orders (`/api/orders`) | JWT + Blacklist | โœ… Tested | -| Catalog (`/api/catalog`) | JWT + Blacklist | โœ… Tested | -| Subscriptions (`/api/subscriptions`) | JWT + Blacklist | โœ… Tested | -| Invoices (`/api/invoices`) | JWT + Blacklist | โœ… Tested | -| Admin (`/api/auth/admin`) | JWT + Blacklist + AdminGuard | โœ… Tested | - -### **4. Webhook Security** โœ… **ENTERPRISE-GRADE** - -- โœ… **HMAC-SHA256 Signature Verification**: All webhooks require valid signatures -- โœ… **Rate Limiting**: Prevents webhook abuse -- โœ… **Public Route Marking**: Properly excluded from JWT authentication -- โœ… **Separate Authentication**: Uses signature-based auth instead of JWT - -### **5. Input Validation & Sanitization** โœ… **COMPREHENSIVE** - -- โœ… **Global ValidationPipe**: Whitelist mode, forbid unknown values -- โœ… **DTO Validation**: class-validator decorators on all inputs -- โœ… **Request Size Limits**: Helmet.js protection -- โœ… **Production Error Handling**: Sanitized error messages - -### **6. Security Headers & CORS** โœ… **HARDENED** - -- โœ… **Helmet.js**: Comprehensive security headers -- โœ… **CSP**: Content Security Policy configured -- โœ… **CORS**: Restrictive origin validation -- โœ… **Security Headers**: X-Frame-Options, X-Content-Type-Options, etc. - -## ๐Ÿงช **SECURITY TESTING RESULTS** - -### **Authentication Tests** โœ… **PASSED** - -| Test Case | Expected | Actual | Status | -|-----------|----------|--------|--------| -| Public route without auth | 200/400 (validation) | โœ… 400 (validation) | PASS | -| Protected route without auth | 401 Unauthorized | โœ… 401 Unauthorized | PASS | -| Protected route with valid JWT | 200 + data | โœ… 200 + data | PASS | -| Webhook without signature | 401 Unauthorized | โœ… 401 Unauthorized | PASS | -| Password reset public access | 200 + message | โœ… 200 + message | PASS | - -### **Edge Case Tests** โœ… **PASSED** - -- โœ… **Malformed JWT**: Properly rejected -- โœ… **Expired JWT**: Properly rejected -- โœ… **Missing Authorization Header**: Properly rejected -- โœ… **Invalid Webhook Signature**: Properly rejected -- โœ… **Rate Limit Exceeded**: Properly throttled - -## ๐Ÿšจ **SECURITY VULNERABILITIES FIXED** - -### **Critical Issues Resolved** โœ… - -1. **Missing @Public Decorators**: - - โŒ **BEFORE**: Auth routes required JWT (impossible to login) - - โœ… **AFTER**: Proper public route marking - -2. **Inconsistent Guard Usage**: - - โŒ **BEFORE**: Manual guards on each controller (error-prone) - - โœ… **AFTER**: Global guard with decorator-based exceptions - -3. **Token Blacklist Gaps**: - - โŒ **BEFORE**: Separate guard implementation (complex) - - โœ… **AFTER**: Integrated into global guard (seamless) - -4. **Webhook Security**: - - โŒ **BEFORE**: Would require JWT (breaking webhooks) - - โœ… **AFTER**: Proper signature-based authentication - -## ๐ŸŽฏ **SECURITY RECOMMENDATIONS IMPLEMENTED** - -### **2025 Best Practices** โœ… **IMPLEMENTED** - -1. โœ… **Global Authentication Guard**: Single point of control -2. โœ… **Decorator-Based Public Routes**: Clean architecture -3. โœ… **Token Blacklisting**: Proper logout functionality -4. โœ… **Comprehensive Logging**: Security event monitoring -5. โœ… **Rate Limiting**: Abuse prevention -6. โœ… **Input Validation**: XSS and injection prevention -7. โœ… **Security Headers**: Browser-level protection -8. โœ… **CORS Configuration**: Origin validation - -## ๐Ÿ“Š **SECURITY METRICS** - -| Metric | Value | Status | -|--------|-------|--------| -| Protected Endpoints | 100% | โœ… SECURE | -| Public Endpoints | 8 routes | โœ… VALIDATED | -| Authentication Coverage | 100% | โœ… COMPLETE | -| Token Blacklist Coverage | 100% | โœ… COMPLETE | -| Input Validation Coverage | 100% | โœ… COMPLETE | -| Rate Limiting Coverage | 100% | โœ… COMPLETE | -| Security Headers | All configured | โœ… COMPLETE | - -## ๐Ÿ”ง **TECHNICAL IMPLEMENTATION** - -### **Global Guard Architecture** -```typescript -@Injectable() -export class GlobalAuthGuard extends AuthGuard('jwt') { - // 1. Check @Public() decorator - // 2. Validate JWT if not public - // 3. Check token blacklist - // 4. Log security events - // 5. Allow/deny access -} -``` - -### **Security Features** -- **JWT Validation**: Signature, expiration, format -- **Token Blacklisting**: Redis-based, automatic cleanup -- **Public Route Handling**: Decorator-based exceptions -- **Comprehensive Logging**: Debug, warn, error levels -- **Error Handling**: Production-safe messages - -## ๐ŸŽ‰ **CONCLUSION** - -### **โœ… SECURITY STATUS: PRODUCTION READY** - -The application now implements **enterprise-grade security** following **2025 NestJS best practices**: - -1. **๐Ÿ”’ Authentication**: Bulletproof JWT + blacklist system -2. **๐Ÿ›ก๏ธ Authorization**: Proper role-based access control -3. **๐Ÿšซ Input Validation**: Comprehensive XSS/injection prevention -4. **โšก Rate Limiting**: Abuse and DoS protection -5. **๐Ÿ” Security Headers**: Browser-level security -6. **๐Ÿ“ Audit Logging**: Complete security event tracking -7. **๐ŸŒ CORS**: Proper origin validation -8. **๐Ÿ”ง Webhook Security**: HMAC signature verification - -### **๐Ÿ† ACHIEVEMENTS** - -- โœ… **Zero Security Vulnerabilities** -- โœ… **100% Authentication Coverage** -- โœ… **Modern Architecture (2025 Standards)** -- โœ… **Production-Ready Implementation** -- โœ… **Comprehensive Testing Validated** - -### **๐Ÿš€ READY FOR PRODUCTION DEPLOYMENT** - -The security implementation is now **enterprise-grade** and ready for production use with confidence. - ---- - -**Security Audit Completed**: August 28, 2025 -**Next Review**: Recommended in 6 months or after major changes diff --git a/SECURITY_FIXES_REQUIRED.md b/SECURITY_FIXES_REQUIRED.md deleted file mode 100644 index da22ec82..00000000 --- a/SECURITY_FIXES_REQUIRED.md +++ /dev/null @@ -1,169 +0,0 @@ -# ๐Ÿšจ CRITICAL SECURITY FIXES REQUIRED - -## **IMMEDIATE ACTION NEEDED** - -The ESLint scan revealed **204 ERRORS** and **479 WARNINGS** with critical security vulnerabilities: - -### **๐Ÿ”ด CRITICAL SECURITY ISSUES** - -1. **Unsafe `any` Types** - 50+ instances - - **Risk**: Type safety bypass, potential injection attacks - - **Impact**: HIGH - Can lead to runtime errors and security vulnerabilities - -2. **Unsafe Member Access** - 100+ instances - - **Risk**: Accessing properties on potentially undefined objects - - **Impact**: HIGH - Runtime errors, potential crashes - -3. **No Type Validation** - Salesforce responses not validated - - **Risk**: Malformed data can crash the application - - **Impact**: MEDIUM - Stability and reliability issues - -## **๐Ÿ›ก๏ธ MODERN SECURITY FIXES IMPLEMENTED** - -### **1. Type Safety Enhancement** -```typescript -// โŒ BEFORE (UNSAFE) -async createOrder(userId: string, rawBody: any) { - const result = await this.sf.query(sql) as any; - return result.records[0].Id; // Unsafe! -} - -// โœ… AFTER (SECURE) -async createOrder(userId: string, rawBody: unknown) { - const result = await this.sf.query(sql) as SalesforceQueryResult; - if (!isSalesforceQueryResult(result, isSalesforceOrder)) { - throw new BadRequestException('Invalid Salesforce response'); - } - return result.records[0]?.Id; -} -``` - -### **2. Runtime Type Validation** -```typescript -// โœ… NEW: Type Guards for Security -export function isSalesforceOrder(obj: unknown): obj is SalesforceOrder { - return ( - typeof obj === 'object' && - obj !== null && - typeof (obj as SalesforceOrder).Id === 'string' && - typeof (obj as SalesforceOrder).OrderNumber === 'string' - ); -} -``` - -### **3. Proper Error Handling** -```typescript -// โœ… NEW: Secure Error Handling -try { - const validatedBody = this.validateRequestFormat(rawBody); - // Process with type safety -} catch (error) { - this.logger.error('Validation failed', { error: error.message }); - throw new BadRequestException('Invalid request format'); -} -``` - -## **๐Ÿ“‹ FIXES APPLIED** - -### **โœ… Completed** -1. Created `SalesforceOrder` and `SalesforceOrderItem` types -2. Added type guards for runtime validation -3. Replaced critical `any` types with `unknown` -4. Enhanced GlobalAuthGuard with proper logging -5. Fixed public route security - -### **๐Ÿ”„ In Progress** -1. Replacing all `any` types with proper interfaces -2. Adding runtime validation for all external data -3. Implementing proper error boundaries -4. Adding comprehensive type checking - -### **โณ Remaining** -1. Fix all ESLint errors (204 remaining) -2. Add comprehensive input validation -3. Implement data sanitization -4. Add security headers validation - -## **๐ŸŽฏ NEXT STEPS** - -### **Immediate (Critical)** -1. **Fix Type Safety**: Replace all `any` with proper types -2. **Add Validation**: Validate all external API responses -3. **Secure Error Handling**: Sanitize all error messages - -### **Short Term (Important)** -1. **Run ESLint Fix**: `npm run lint:fix` -2. **Add Unit Tests**: Test all type guards and validation -3. **Security Audit**: Review all external integrations - -### **Long Term (Maintenance)** -1. **Automated Security Scanning**: Add to CI/CD -2. **Regular Type Audits**: Monthly type safety reviews -3. **Security Training**: Team education on TypeScript security - -## **๐Ÿš€ RECOMMENDED APPROACH** - -### **Phase 1: Critical Security (Now)** -```bash -# 1. Fix immediate type safety issues -npm run lint:fix - -# 2. Add proper types for all Salesforce interactions -# 3. Implement runtime validation for all external data -# 4. Add comprehensive error handling -``` - -### **Phase 2: Comprehensive Security (This Week)** -```bash -# 1. Complete type safety overhaul -# 2. Add comprehensive input validation -# 3. Implement security testing -# 4. Add monitoring and alerting -``` - -## **๐Ÿ’ก MODERN NESTJS PATTERNS** - -### **Use Proper DTOs with Validation** -```typescript -// โœ… Modern NestJS Pattern -export class CreateOrderDto { - @IsString() - @IsNotEmpty() - @IsIn(['Internet', 'SIM', 'VPN', 'Other']) - orderType: 'Internet' | 'SIM' | 'VPN' | 'Other'; - - @IsArray() - @IsString({ each: true }) - @IsNotEmpty({ each: true }) - skus: string[]; -} -``` - -### **Use Type Guards for External Data** -```typescript -// โœ… Secure External Data Handling -function validateSalesforceResponse( - data: unknown, - validator: (obj: unknown) => obj is T -): T { - if (!validator(data)) { - throw new BadRequestException('Invalid external data format'); - } - return data; -} -``` - -## **๐Ÿ”’ SECURITY COMPLIANCE** - -After implementing these fixes, the application will be: -- โœ… **Type Safe**: No `any` types, full TypeScript compliance -- โœ… **Runtime Safe**: All external data validated -- โœ… **Error Safe**: Proper error handling and sanitization -- โœ… **Modern**: Following 2025 NestJS best practices -- โœ… **Secure**: Production-ready security implementation - ---- - -**Status**: ๐Ÿ”ด **CRITICAL FIXES IN PROGRESS** -**ETA**: 2-4 hours for complete security overhaul -**Priority**: **HIGHEST** - Security vulnerabilities must be fixed before production diff --git a/VALIDATION_AUDIT_REPORT.md b/VALIDATION_AUDIT_REPORT.md deleted file mode 100644 index 70798143..00000000 --- a/VALIDATION_AUDIT_REPORT.md +++ /dev/null @@ -1,125 +0,0 @@ -# Order Validation & Salesforce Field Mapping Audit Report - -## ๐Ÿ” **Audit Summary** - -### โœ… **What's Working Correctly:** - -1. **Core Order Fields** - All documented fields are properly mapped: - - `AccountId`, `EffectiveDate`, `Status`, `Pricebook2Id`, `Order_Type__c` โœ… - -2. **Activation Fields** - Correctly implemented: - - `Activation_Type__c`, `Activation_Scheduled_At__c`, `Activation_Status__c` โœ… - -3. **Internet Fields** - All documented fields mapped: - - `Internet_Plan_Tier__c`, `Installation_Type__c`, `Weekend_Install__c`, `Access_Mode__c`, `Hikari_Denwa__c` โœ… - -4. **SIM Fields** - All documented fields mapped: - - `SIM_Type__c`, `EID__c`, `SIM_Voice_Mail__c`, `SIM_Call_Waiting__c` + MNP fields โœ… - -5. **VPN Fields** - Correctly implemented: - - `VPN_Region__c` โœ… - -### โš ๏ธ **Issues Found:** - -## **Issue 1: Field Mapping Not Used in Order Builder** - -**Problem**: Our `order-builder.service.ts` is hardcoding field names instead of using the field mapping configuration. - -**Current Implementation:** -```typescript -// Hardcoded field names -orderFields.Internet_Plan_Tier__c = serviceProduct.internetPlanTier; -orderFields.Access_Mode__c = config.accessMode; -orderFields.Installation_Type__c = installType; -``` - -**Should Be:** -```typescript -// Using field mapping -const fields = getSalesforceFieldMap(); -orderFields[fields.order.internetPlanTier] = serviceProduct.internetPlanTier; -orderFields[fields.order.accessMode] = config.accessMode; -orderFields[fields.order.installationType] = installType; -``` - -## **Issue 2: Missing Documentation Alignment** - -**Problem**: Documentation shows different API structure than implementation. - -**Documentation Says:** -```json -{ - "items": [ - { "productId": "...", "billingCycle": "...", "configOptions": {...} } - ], - "promoCode": "...", - "notes": "..." -} -``` - -**Current Implementation:** -```json -{ - "orderType": "Internet", - "skus": ["INTERNET-SILVER-HOME-1G", "..."], - "configurations": { "accessMode": "PPPoE" } -} -``` - -## **Issue 3: Validation Logic vs Documentation** - -**Problem**: Our validation doesn't match documented requirements exactly. - -**Documentation Requirements:** -- "Server-side checks: require WHMCS mapping; require `hasPaymentMethod=true`" -- "Create Salesforce Order (Pending Review)" - -**Current Implementation:** โœ… Correctly implemented - -## **Issue 4: Missing Order Status Progression** - -**Documentation Shows:** -- Initial Status: "Pending Review" -- After Approval: "Provisioned" -- Error States: "Failed" - -**Current Implementation:** โœ… Sets "Pending Review" correctly - -## **Issue 5: MNP Field Mapping Inconsistency** - -**Problem**: Some MNP fields use different patterns. - -**Field Map Shows:** -```typescript -mnp: { - application: "MNP_Application__c", - reservationNumber: "MNP_Reservation_Number__c", - // ... -} -``` - -**Order Builder Uses:** -```typescript -orderFields.MNP_Application__c = true; // โœ… Correct -orderFields.MNP_Reservation_Number__c = config.mnpNumber; // โœ… Correct -``` - -## **Recommendations:** - -### 1. **Fix Field Mapping Usage** (High Priority) -Update `order-builder.service.ts` to use the field mapping configuration instead of hardcoded field names. - -### 2. **API Structure Alignment** (Medium Priority) -Decide whether to: -- Update documentation to match current SKU-based implementation -- OR update implementation to match item-based documentation - -### 3. **Add Field Validation** (Medium Priority) -Add validation to ensure all required Salesforce fields are present before order creation. - -### 4. **Environment Configuration** (Low Priority) -Ensure all field mappings can be overridden via environment variables for different Salesforce orgs. - -## **Overall Assessment: ๐ŸŸก MOSTLY CORRECT** - -The core functionality is working correctly, but we need to fix the field mapping usage for better maintainability and environment flexibility. diff --git a/apps/bff/Dockerfile b/apps/bff/Dockerfile index fa92c8e5..03c6bc10 100644 --- a/apps/bff/Dockerfile +++ b/apps/bff/Dockerfile @@ -79,7 +79,7 @@ COPY apps/bff/package.json ./apps/bff/ # Install only production dependencies; skip lifecycle scripts to avoid Husky prepare # Prisma client and native assets are generated in the builder stage and copied below ENV HUSKY=0 -RUN pnpm install --frozen-lockfile --prod --ignore-scripts +RUN pnpm install --recursive --frozen-lockfile --prod --ignore-scripts # Copy built applications and Prisma client COPY --from=builder /app/packages/shared/dist ./packages/shared/dist diff --git a/compose-plesk.yaml b/compose-plesk.yaml new file mode 100644 index 00000000..7995888b --- /dev/null +++ b/compose-plesk.yaml @@ -0,0 +1,113 @@ +# ๐Ÿš€ Customer Portal - Plesk Docker Stack +# Deploy via: Plesk โ†’ Docker โ†’ Stacks โ†’ Add Stack +# Project name: customer-portal + +services: + frontend: + image: ghcr.io/ntumurbars/customer-portal-frontend:latest + container_name: portal-frontend + network_mode: bridge + ports: + - "3000:3000" + environment: + - NODE_ENV=production + - PORT=3000 + - HOSTNAME=0.0.0.0 + - NEXT_PUBLIC_API_BASE=${NEXT_PUBLIC_API_BASE} + - NEXT_PUBLIC_APP_NAME=${NEXT_PUBLIC_APP_NAME} + - NEXT_PUBLIC_APP_VERSION=${NEXT_PUBLIC_APP_VERSION} + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"] + interval: 30s + timeout: 10s + start_period: 40s + retries: 3 + + backend: + image: ghcr.io/ntumurbars/customer-portal-backend:latest + container_name: portal-backend + network_mode: bridge + ports: + - "127.0.0.1:4000:4000" + environment: + - NODE_ENV=production + - PORT=4000 + - DATABASE_URL=${DATABASE_URL} + - REDIS_URL=${REDIS_URL} + - JWT_SECRET=${JWT_SECRET} + - JWT_EXPIRES_IN=${JWT_EXPIRES_IN} + - BCRYPT_ROUNDS=${BCRYPT_ROUNDS} + - CORS_ORIGIN=${CORS_ORIGIN} + - TRUST_PROXY=${TRUST_PROXY} + - WHMCS_BASE_URL=${WHMCS_BASE_URL} + - WHMCS_API_IDENTIFIER=${WHMCS_API_IDENTIFIER} + - WHMCS_API_SECRET=${WHMCS_API_SECRET} + - SF_LOGIN_URL=${SF_LOGIN_URL} + - SF_CLIENT_ID=${SF_CLIENT_ID} + - SF_PRIVATE_KEY_PATH=${SF_PRIVATE_KEY_PATH} + - SF_USERNAME=${SF_USERNAME} + - PORTAL_PRICEBOOK_ID=${PORTAL_PRICEBOOK_ID} + - LOG_LEVEL=${LOG_LEVEL} + - LOG_FORMAT=${LOG_FORMAT} + - SENDGRID_API_KEY=${SENDGRID_API_KEY} + - EMAIL_FROM=${EMAIL_FROM} + - EMAIL_FROM_NAME=${EMAIL_FROM_NAME} + - EMAIL_ENABLED=${EMAIL_ENABLED} + - EMAIL_USE_QUEUE=${EMAIL_USE_QUEUE} + - SENDGRID_SANDBOX=${SENDGRID_SANDBOX} + - EMAIL_TEMPLATE_RESET=${EMAIL_TEMPLATE_RESET} + - EMAIL_TEMPLATE_WELCOME=${EMAIL_TEMPLATE_WELCOME} + - NODE_OPTIONS=${NODE_OPTIONS} + restart: unless-stopped + depends_on: + - database + - cache + command: sh -c "pnpm prisma migrate deploy && node dist/main" + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:4000/health"] + interval: 30s + timeout: 10s + start_period: 60s + retries: 3 + + database: + image: postgres:17-alpine + container_name: portal-database + network_mode: bridge + ports: + - "127.0.0.1:5432:5432" # Only accessible from localhost for security + environment: + - POSTGRES_DB=${POSTGRES_DB} + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C + volumes: + - postgres_data:/var/lib/postgresql/data + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "pg_isready -U portal_user -d portal_db"] + interval: 10s + timeout: 5s + retries: 5 + + cache: + image: redis:7-alpine + container_name: portal-cache + network_mode: bridge + ports: + - "127.0.0.1:6379:6379" # Only accessible from localhost for security + volumes: + - redis_data:/data + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + postgres_data: + driver: local + redis_data: + driver: local diff --git a/package.json b/package.json index 5ec54bf6..2b447931 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "update:safe": "pnpm update --recursive && pnpm audit && pnpm type-check" }, "devDependencies": { + "@eslint/js": "^9.13.0", "@eslint/eslintrc": "^3.3.1", "@types/node": "^24.3.0", "eslint": "^9.33.0",