AI & Estimating
Garage Door Quote Tool
Implementation guide for the visual garage door quote builder and AI-assisted pricing.
10 min readGarage Door Quote Tool - Implementation Documentation
🚪 Overview
This document provides detailed implementation guidance for the Garage Door Quote Tool integrated into ServiceFlow Pro. The tool provides a comprehensive solution for garage door repair services to create, manage, and share professional quotes with customers.
🏗️ Architecture Overview
Database Schema
The tool extends ServiceFlow Pro with garage door-specific tables:
-- Core garage door entities
GarageDoorColor -- Door colors with hex codes
GarageDoorStyle -- Door styles with preview images
GarageDoorManufacturer -- Door manufacturers
GarageDoorInsulation -- Insulation types with R-values
GarageDoorMotor -- Motor options and pricing
GarageDoorWindow -- Window options
-- Pricing system
DoorPriceList -- Base pricing by specifications
DoorMaster -- Door configurations
DoorMarkup -- Business-specific markup rates
-- Quote management
GarageDoorQuote -- Main quote entity
DoorPicture -- Visual assets for doors
-- Custom attributes
GarageDoorAttribute -- Business-specific attributes
GarageDoorAttributeField -- Attribute fields
GarageDoorAttributeInputValue -- Attribute values
Key Features
- Visual Quote Builder - Interactive door configuration
- Real-time Pricing - Instant price calculations with markup
- Customer Links - Shareable quote links for customer review
- PDF Generation - Professional quote documents
- Mobile Integration - Field technician quote creation
- Business Rules - Customizable pricing rules per business
📋 Implementation Checklist
Phase 1: Database Setup ✅
- Database schema design
- Prisma schema integration
- Migration files
- Seed data creation
- Index optimization
Phase 2: API Development ✅
- Quote management endpoints
- Pricing calculation service
- Customer sharing endpoints
- Conversion endpoints (job/estimate/invoice)
- Validation schemas
- Error handling
Phase 3: Web Interface ✅
- Quote builder component
- Visual door preview
- Pricing breakdown
- Customer quote view
- Quote management pages
- PDF generation
- Email templates
Phase 4: Mobile Integration 🔄
- Mobile quote creation
- Offline functionality
- Photo integration
- Field measurements
Phase 5: Advanced Features 📋
- AI-powered recommendations
- Competitor pricing analysis
- Bulk quote generation
- Integration with job management
🔧 Configuration Guide
Business Settings
Each business can configure:
// Example business configuration
const businessConfig = {
defaultMarkup: 1.25, // 25% markup
availableVendors: ['vendor1', 'vendor2'],
customAttributes: [
{ name: 'Installation Type', type: 'SELECT', options: ['New', 'Replacement'] },
{ name: 'Warranty Level', type: 'SELECT', options: ['Standard', 'Extended'] }
],
pricingRules: {
volumeDiscounts: true,
seasonalPricing: false,
competitorMatching: true
}
}
Quote Templates
Professional PDF templates with customizable branding:
// PDF template configuration
const pdfConfig = {
template: 'professional',
branding: {
logo: 'business-logo.png',
colors: ['#1890ff', '#52c41a'],
fonts: ['Arial', 'Times New Roman']
},
sections: [
'header',
'customer_info',
'door_specifications',
'pricing_breakdown',
'terms_conditions',
'footer'
]
}
🚀 Quick Start Guide
1. Database Setup
# Navigate to garage door tool directory
cd garage_door_quote_tool
# Run migrations
npx prisma migrate dev
# Seed sample data
npx prisma db seed
2. API Integration
# Install dependencies
npm install
# Start development server
npm run dev
3. Web Interface
# Navigate to web app
cd ../apps/web
# Add garage door routes
# Add to src/routes/index.tsx:
{
path: '/garage-door-quotes',
element: <GarageDoorQuotesPage />
}
# Start web app
npm run dev
4. Mobile Integration
# Navigate to mobile app
cd ../apps/mobile
# Add garage door screens
# Add to navigation
# Start mobile app
npm run dev
📊 API Reference
Quote Management
// Create quote
POST /api/garage-door-quotes
{
length: 16,
height: 8,
colorId: "color_123",
styleId: "style_456",
insulationId: "insulation_789",
hasWindows: false,
manufacturerId: "manufacturer_abc",
motorId: "motor_def",
onePieceConversion: false,
dumpFee: true,
framingRequired: false,
customerId: "customer_xyz",
notes: "Customer prefers morning installation"
}
// Get quote
GET /api/garage-door-quotes/:id
// Update quote
PUT /api/garage-door-quotes/:id
// Delete quote
DELETE /api/garage-door-quotes/:id
Pricing
// Get pricing options
GET /api/garage-door-pricing/options
// Calculate price
POST /api/garage-door-pricing/calculate
{
length: 16,
height: 8,
colorId: "color_123",
styleId: "style_456",
insulationId: "insulation_789",
hasWindows: false,
manufacturerId: "manufacturer_abc"
}
Customer Sharing
// Share quote
POST /api/garage-door-quotes/:id/share
{
email: "customer@example.com",
message: "Here's your garage door quote"
}
// Public quote view
GET /api/garage-door-quotes/:id/public?token=abc123
// Accept quote
POST /api/garage-door-quotes/:id/accept
{
token: "abc123",
customerInfo: {
firstName: "John",
lastName: "Doe",
email: "john@example.com",
phone: "555-0123"
}
}
// Decline quote
POST /api/garage-door-quotes/:id/decline
{
token: "abc123",
reason: "Price too high"
}
Conversion
// Convert to job
POST /api/garage-door-quotes/:id/convert-to-job
{
customerId: "customer_xyz",
scheduledDate: "2025-01-15T09:00:00Z",
notes: "Morning installation preferred"
}
// Convert to estimate
POST /api/garage-door-quotes/:id/convert-to-estimate
{
customerId: "customer_xyz",
validUntil: "2025-02-15T23:59:59Z",
notes: "Valid for 30 days"
}
// Convert to invoice
POST /api/garage-door-quotes/:id/convert-to-invoice
{
customerId: "customer_xyz",
dueDate: "2025-01-30T23:59:59Z",
notes: "Net 30 terms"
}
🎨 UI Components
Quote Builder
import { GarageDoorQuoteBuilder } from './components/GarageDoorQuoteBuilder'
<GarageDoorQuoteBuilder
onSuccess={(quote) => {
// Handle successful quote creation
navigate(`/garage-door-quotes/${quote.id}`)
}}
onCancel={() => {
// Handle cancellation
navigate('/garage-door-quotes')
}}
initialData={{
length: 16,
height: 8,
customerId: 'customer_123'
}}
/>
Customer View
import { CustomerQuoteView } from './components/CustomerQuoteView'
<CustomerQuoteView
quote={quote}
onAccept={(customerInfo) => {
// Handle quote acceptance
acceptQuote(quote.id, customerInfo)
}}
onDecline={(reason) => {
// Handle quote decline
declineQuote(quote.id, reason)
}}
/>
Door Preview
import { DoorPreview } from './components/DoorPreview'
<DoorPreview
specifications={{
length: 16,
height: 8,
color: 'White',
style: 'Traditional',
insulation: 'R-16',
manufacturer: 'Clopay',
hasWindows: true
}}
/>
Pricing Breakdown
import { PricingBreakdown } from './components/PricingBreakdown'
<PricingBreakdown
pricing={{
baseCost: new Decimal(1200),
markupRate: new Decimal(1.25),
markupAmount: new Decimal(300),
totalPrice: new Decimal(1500),
optionsBreakdown: [
{
name: 'Motor',
cost: new Decimal(250),
description: 'Chamberlain 1/2 HP'
}
],
doorDescription: 'Clopay-Traditional, 16 X 8, R-16, White, Traditional, No Windows',
modelCode: 'ModelGDD-1200MI123/'
}}
/>
📱 Mobile Integration
Mobile Quote Creation
// Mobile quote builder
import { MobileQuoteBuilder } from './components/MobileQuoteBuilder'
<MobileQuoteBuilder
onSuccess={(quote) => {
// Handle successful quote creation
navigation.navigate('QuoteDetail', { quoteId: quote.id })
}}
offlineMode={true}
photoIntegration={true}
/>
Offline Functionality
// Offline quote storage
const offlineService = new OfflineService()
// Save quote offline
await offlineService.saveQuoteOffline(quote)
// Sync when online
await offlineService.syncPendingQuotes()
🔒 Security & Permissions
Access Control
// Business-scoped data access
const quotes = await db.garageDoorQuote.findMany({
where: { businessId: user.businessId }
})
// User role permissions
const canCreateQuotes = user.roles.includes('ADMIN') || user.roles.includes('SALES')
const canViewPricing = user.roles.includes('ADMIN') || user.roles.includes('MANAGER')
Quote Sharing Security
// Secure share tokens
const shareToken = generateSecureToken()
// Token validation
const isValidToken = await validateShareToken(quoteId, token)
📈 Analytics & Reporting
Quote Analytics
// Quote statistics
const stats = await garageDoorQuoteService.getQuoteStats(businessId)
// Conversion rates
const conversionRate = (stats.acceptedQuotes / stats.totalQuotes) * 100
// Popular configurations
const popularConfigs = await getPopularDoorConfigurations(businessId)
Business Intelligence
// Revenue tracking
const revenue = await getQuoteRevenue(businessId, dateRange)
// Customer preferences
const preferences = await getCustomerPreferences(businessId)
// Market trends
const trends = await analyzeMarketTrends(businessId)
🚀 Deployment
Production Setup
# Environment variables
GARAGE_DOOR_QUOTE_ENABLED=true
GARAGE_DOOR_PDF_ENABLED=true
GARAGE_DOOR_SHARING_ENABLED=true
GARAGE_DOOR_EMAIL_ENABLED=true
# Database migration
npx prisma migrate deploy
# Build and deploy
npm run build
npm run deploy
Monitoring
// Quote generation metrics
const metrics = {
quotesCreated: 150,
quotesShared: 120,
quotesAccepted: 45,
conversionRate: 30,
averageQuoteValue: 2500
}
// Performance monitoring
const performance = {
averageResponseTime: 250,
errorRate: 0.1,
uptime: 99.9
}
🤝 Integration Points
ServiceFlow Pro Integration
// Customer management
const customer = await customerService.getById(customerId)
const customerQuotes = await garageDoorQuoteService.getQuotesByCustomer(customerId)
// Job creation
const job = await garageDoorQuoteService.convertToJob(quoteId, jobData)
// Invoice generation
const invoice = await garageDoorQuoteService.convertToInvoice(quoteId, invoiceData)
// Payment processing
const payment = await paymentService.processPayment(invoiceId, paymentData)
Third-party Services
// PDF generation
const pdf = await pdfService.generateQuotePDF(quote)
// Email notifications
await emailService.sendQuoteShareEmail(email, quoteData)
// SMS alerts
await smsService.sendQuoteNotification(phone, quoteData)
// Payment processing
const payment = await stripeService.processPayment(amount, paymentMethod)
📚 Testing Guide
Unit Tests
// Test pricing calculation
describe('GarageDoorPricingService', () => {
it('should calculate correct pricing', async () => {
const pricing = await pricingService.calculatePrice(businessId, quoteData)
expect(pricing.totalPrice.toNumber()).toBe(1500)
})
})
// Test quote creation
describe('GarageDoorQuoteService', () => {
it('should create quote successfully', async () => {
const quote = await quoteService.create(businessId, userId, quoteData)
expect(quote.quoteNumber).toBeDefined()
})
})
Integration Tests
// Test API endpoints
describe('Garage Door Quote API', () => {
it('should create and retrieve quote', async () => {
const quote = await createQuote(quoteData)
const retrieved = await getQuote(quote.id)
expect(retrieved.id).toBe(quote.id)
})
})
E2E Tests
// Test complete workflow
describe('Garage Door Quote Workflow', () => {
it('should create and share quote', async () => {
await page.goto('/garage-door-quotes/new')
await page.fill('[data-testid="length-input"]', '16')
await page.fill('[data-testid="height-input"]', '8')
await page.click('[data-testid="create-quote-button"]')
await expect(page.locator('.ant-message-success')).toBeVisible()
})
})
🆘 Troubleshooting
Common Issues
-
Pricing not calculating
- Check if all required fields are filled
- Verify pricing data exists for the configuration
- Check markup rates are configured
-
Quote sharing not working
- Verify share token generation
- Check email service configuration
- Validate share URL format
-
Mobile offline sync issues
- Check offline storage permissions
- Verify sync queue implementation
- Test network connectivity handling
Performance Optimization
-
Database queries
- Add indexes on frequently queried fields
- Use pagination for large datasets
- Implement query caching
-
API responses
- Compress large responses
- Implement response caching
- Use pagination for list endpoints
-
Frontend performance
- Lazy load components
- Implement virtual scrolling for large lists
- Optimize image loading
📞 Support
For technical support or feature requests:
- Create an issue in the repository
- Contact the development team
- Check the troubleshooting guide
- Review the API documentation
Version: 1.0.0
Last Updated: January 2025
Status: Active Development
Last Updated: January 2025
Status: Active Development