Files
claudetools/projects/msp-tools/quote-wizard/session-logs/2026-03-09-session.md
Mike Swanson fa15b03180 sync: Auto-sync from ACG-M-L5090 at 2026-03-10 19:11:00
Synced files:
- Quote wizard frontend (all components, hooks, types, config)
- API updates (config, models, routers, schemas, services)
- Client work (bg-builders, gurushow)
- Scripts (BGB Lesley termination, CIPP, Datto, migration)
- Temp files (Bardach contacts, VWP investigation, misc)
- Credentials and session logs
- Email service, PHP API, session logs

Machine: ACG-M-L5090
Timestamp: 2026-03-10 19:11:00

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:59:08 -07:00

8.5 KiB

MSP Quote Wizard Session Log - 2026-03-09

Session Summary

Major deployment session for the MSP Quote Wizard. Started from code pulled from MacBook Air (commit a1a19f8), reviewed the full project, fixed 15+ backend model/schema mismatches, deployed frontend to azcomputerguru.com/quote on IX cPanel, debugged and fixed PHP reverse proxy, and applied comprehensive responsive design fixes to all wizard components.

Key Accomplishments

  1. Full backend model alignment with MariaDB schema (12+ field/table/enum fixes)
  2. Frontend deployed to production at https://azcomputerguru.com/quote/
  3. PHP reverse proxy debugged and fixed (CURLOPT_FOLLOWLOCATION for FastAPI 307 redirects)
  4. Comprehensive responsive design fixes across all 9 wizard components
  5. End-to-end API flow verified: create -> get -> add item -> submit

Key Decisions

  • Used PHP curl reverse proxy instead of direct API exposure (API on 172.16.3.30:8001, frontend on IX 172.16.3.10)
  • Made contact_name/contact_email nullable in DB to support draft quotes
  • Wrapped QuoteActivity details in JSON for MariaDB json_valid() CHECK constraint
  • Used CURLOPT_FOLLOWLOCATION to handle FastAPI trailing-slash 307 redirects
  • SSH to IX requires -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 as root (too many keys causes auth failure)

Infrastructure

Servers

  • API Server: 172.16.3.30:8001 (FastAPI/Uvicorn, production ClaudeTools API)
  • IX Server (Hosting): 172.16.3.10 (cPanel/WHM, Apache, PHP 8.1.33)
    • SSH: ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 root@172.16.3.10
    • Root password: Gptf*77ttb!@#!@#
    • Site path: /home/azcomputerguru/public_html/quote/
    • cPanel account: azcomputerguru
  • Database: 172.16.3.30:3306 / MariaDB 10.6.22
    • DB: claudetools
    • User: claudetools
    • Password: CT_e8fcd5a3952030a79ed6debae6c954ed

Deployment Architecture

Browser -> Cloudflare -> IX (172.16.3.10:443)
  -> /quote/ -> index.html (SPA)
  -> /quote/api/* -> .htaccess rewrite -> api-proxy.php -> curl -> 172.16.3.30:8001/api/*

Files on IX (/home/azcomputerguru/public_html/quote/)

  • index.html - SPA entry point
  • assets/ - JS/CSS bundles
  • api-proxy.php - PHP reverse proxy to API
  • .htaccess - Rewrite rules (API proxy + SPA routing)

Backend Fixes Applied

Model Alignment (api/models/quote.py)

  • Status enum: draft/submitted/viewed/followed_up/converted/expired (was reviewing/approved/rejected)
  • ServiceCategory enum: gps_monitoring/support_plan/voip/web_hosting/email/hardware/addon
  • BillingFrequency enum: monthly/yearly/one_time (was quarterly/annual)
  • NotificationType enum: email/webhook (was email_sent/sms_sent/admin_alert/reminder_sent)
  • Removed columns: notes, admin_notes, annual_total (don't exist in DB)
  • Fixed reserved word: metadata -> details (SQLAlchemy reserves metadata)
  • Fixed table name: quote_activities -> quote_activity
  • Removed TimestampMixin from QuoteItem/QuoteActivity/QuoteNotification (no updated_at)
  • Made contact_name/contact_email Optional for draft support
  • QuoteItem fields: service_name->product_name, setup_fee->setup_price, is_required->is_recommended, added product_code/tier, removed sort_order

Database ALTERs Applied

ALTER TABLE quotes MODIFY contact_name VARCHAR(255) NULL;
ALTER TABLE quotes MODIFY contact_email VARCHAR(255) NULL;

Service Layer (api/services/quote_service.py)

  • calculate_totals() returns (monthly, setup) tuple (removed annual)
  • log_activity() wraps details in json.dumps({"message": details}) for json_valid() constraint
  • Removed all references to notes/admin_notes/annual_total
  • Syncro API key moved to env var SYNCRO_API_KEY
  • Admin email from env var ADMIN_NOTIFICATION_EMAIL

API Routers

  • api/routers/quotes.py - 6 public endpoints (create, get, update, add item, remove item, submit)
  • api/routers/admin_quotes.py - 5 admin endpoints (list, stats, detail, update status, sync-syncro)
  • Both registered in api/main.py

Dependencies Installed on Production

pip install email-validator httpx

Frontend Changes

Vite Config

  • base: '/quote/' for subdirectory deployment
  • build.outDir and sourcemap: false

API Client (src/lib/api.ts)

  • Complete rewrite to match actual backend endpoints
  • Exports: createQuote, getQuote, updateQuote, addQuoteItem, removeQuoteItem, submitQuote, getQuotePdf

Responsive Design Fixes (Applied 2026-03-09)

All wizard components updated for mobile-first responsive design:

WizardContainer.tsx:

  • Running totals bar: responsive padding (p-2.5 sm:p-4), text sizes (text-lg sm:text-2xl)
  • Step header: responsive padding (px-4 sm:px-6 md:px-8), icon sizes, truncation
  • Content area: responsive padding

Step1CompanyProfile.tsx:

  • Endpoint count input: flex-col on mobile, w-full sm:w-32

Step2GPSMonitoring.tsx:

  • Tier grid: grid-cols-1 sm:grid-cols-2 md:grid-cols-3
  • Equipment section: flex-shrink-0 on toggle, min-w-0 on text, responsive text sizes
  • Monthly total: responsive text (text-2xl sm:text-3xl), whitespace-nowrap

Step3SupportPlan.tsx:

  • Plan grid: grid-cols-1 sm:grid-cols-2 lg:grid-cols-4
  • Block time grid: grid-cols-1 sm:grid-cols-3
  • Toggle headers: flex-shrink-0, min-w-0, responsive text sizes
  • Monthly total: responsive sizing

Step4VoIP.tsx:

  • Toggle header: responsive icon/text sizes, flex-shrink-0
  • User count: flex-col sm:flex-row, w-full sm:w-24
  • Tier grid: grid-cols-1 sm:grid-cols-2 lg:grid-cols-4
  • Hardware items: completely restructured - stacked layout with flex-wrap controls
  • Monthly total: responsive sizing

Step5WebEmail.tsx:

  • All tier grids: sm:grid-cols-2 md:grid-cols-3 (was md:grid-cols-3 only)
  • Toggle headers: responsive icon/text/padding, flex-shrink-0
  • Mailbox count: flex-col sm:flex-row
  • Monthly total: responsive sizing

Step6Summary.tsx:

  • Grand total: flex-col sm:flex-row for monthly investment header
  • Text: text-3xl sm:text-4xl
  • SummarySection header: responsive padding, truncation, flex-shrink-0

Step7Contact.tsx:

  • Quote preview: flex-col sm:flex-row, responsive text
  • Contact preferences: flex-wrap
  • Trust indicators: flex-col sm:flex-row (was grid-cols-1 md:grid-cols-3)

PHP Reverse Proxy (api-proxy.php)

Key Fix: CURLOPT_FOLLOWLOCATION

FastAPI returns 307 redirects for trailing-slash URLs. PHP curl doesn't follow redirects by default, causing empty response bodies. Fixed by adding:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);

Important: Host Header Required

When testing from internal network, must use Host: azcomputerguru.com header. Direct IP access (172.16.3.10) hits wrong Apache vhost and PHP doesn't execute. Browser access works fine since it sends correct Host header.

# WORKS:
curl -s -H "Host: azcomputerguru.com" "http://172.16.3.10/quote/api/quotes" -X POST -H "Content-Type: application/json" -d '{"employee_count":5}'

# FAILS (wrong vhost):
curl -s "http://172.16.3.10/quote/api/quotes" -X POST ...

Pending/Next Steps

  1. Frontend polish: Run through wizard in browser to visually verify responsive fixes
  2. Admin dashboard: No admin UI yet for viewing submitted quotes (admin API endpoints exist)
  3. Email notifications: ADMIN_NOTIFICATION_EMAIL env var needs to be set on production
  4. Syncro integration: SYNCRO_API_KEY env var needs to be set for lead sync
  5. Remove debug endpoint: Already done (removed _debug path from api-proxy.php)
  6. SSL/CORS: Currently CORS is wide open (Access-Control-Allow-Origin: *) - consider restricting
  7. Quote PDF generation: Endpoint exists but likely needs implementation
  8. Production env vars to set:
    • ADMIN_NOTIFICATION_EMAIL
    • SYNCRO_API_KEY
    • SYNCRO_API_BASE_URL (defaults to computerguru.syncromsp.com)

Commands Reference

Deploy frontend to IX

cd D:/ClaudeTools/projects/msp-tools/quote-wizard/frontend
npm run build
scp -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 -r dist/index.html dist/assets/ root@172.16.3.10:/home/azcomputerguru/public_html/quote/
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 root@172.16.3.10 'chown -R azcomputerguru:azcomputerguru /home/azcomputerguru/public_html/quote/'

Deploy api-proxy.php

scp -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 dist/api-proxy.php root@172.16.3.10:/home/azcomputerguru/public_html/quote/api-proxy.php

Test API through proxy

curl -s -H "Host: azcomputerguru.com" -X POST -H "Content-Type: application/json" -d '{"employee_count":5}' "http://172.16.3.10/quote/api/quotes"

Test API directly

curl -s -X POST -H "Content-Type: application/json" -d '{"employee_count":5}' "http://172.16.3.30:8001/api/quotes/"