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>
210 lines
8.5 KiB
Markdown
210 lines
8.5 KiB
Markdown
# 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
|
|
```sql
|
|
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
|
|
```bash
|
|
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:
|
|
```php
|
|
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.
|
|
|
|
```bash
|
|
# 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
|
|
```bash
|
|
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
|
|
```bash
|
|
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
|
|
```bash
|
|
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
|
|
```bash
|
|
curl -s -X POST -H "Content-Type: application/json" -d '{"employee_count":5}' "http://172.16.3.30:8001/api/quotes/"
|
|
```
|