CM10

Booking Confirmation

Duration
~30 seconds
AI Agent
None (Display Only)
External Systems
SendGrid, Twilio
User Action
Read Confirmation
🎨 Layer 1: User Interface (React Native)
Confirmation display with multi-channel notification triggers

📱 Success Confirmation Card

  • Animated Checkmark: Green circular checkmark with scale-in animation (0.5s ease-out)
  • Confirmation Message: "Application Complete!" headline with success messaging
  • Reference Number: Large display of APP-2025-001234 in monospace font
  • Copy Button: One-tap copy reference to clipboard with haptic feedback
  • Visual Hierarchy: Success green (#10b981) theme with white card background
// Success confirmation component const ConfirmationCard = () => { return ( <View style={styles.successCard}> <Animated.View style={checkmarkAnimation}> <Icon name="check-circle" size={80} color="#10b981" /> </Animated.View> <Text style={styles.headline}>Application Complete!</Text> <View style={styles.referenceBox}> <Text style={styles.label}>Reference Number</Text> <Text style={styles.reference}>APP-2025-001234</Text> <TouchableOpacity onPress={copyToClipboard}> <Text style={styles.copyBtn}>📋 Copy</Text> </TouchableOpacity> </View> </View> ); };

📅 Disbursement Timeline

  • Visual Timeline: 3-step horizontal progress indicator with current status highlighted
  • Step 1 - Completed: "Application Signed" with checkmark (23 Dec 2025, 15:45)
  • Step 2 - In Progress: "Processing" with animated spinner (24-26 Dec 2025)
  • Step 3 - Pending: "Funds Arrive" with estimated date (27 Nov 2025)
  • Business Days Note: "Typically 2-3 business days from signature" helper text
  • Color Coding: Completed (green), current (blue pulse), pending (gray)
// Timeline data structure const timeline = [ { step: 1, label: "Application Signed", status: "completed", timestamp: "2025-12-23T15:45:00Z", icon: "✅" }, { step: 2, label: "Processing", status: "in_progress", duration: "2-3 business days", icon: "⏳" }, { step: 3, label: "Funds Arrive", status: "pending", estimated: "2025-11-27", icon: "💰" } ];

📋 Loan Summary Card

  • Amount Display: £150,000 in large bold typography
  • Key Terms Grid: 2×3 grid showing APR (4.5%), Term (36 months), Monthly Payment (£4,440)
  • First Payment Date: "1 December 2025" with calendar icon
  • Purpose: "Opening second café location in Dalston" in italics
  • Total Repayment: £159,840 (includes £9,840 interest) in smaller text

📄 Action Buttons

  • Download Agreement: Primary button to download signed PDF (DocuSign envelope)
  • View Payment Schedule: Secondary button linking to amortization table
  • Contact Support: Tertiary button with phone/email/chat options
  • Return to Dashboard: Text link to navigate back to main app
  • Button States: All buttons have loading, disabled, and pressed states
// Button action handlers const downloadAgreement = async () => { const envelope = "a7f3c5d9-e8b2-4a1c-9f6d-3e4b5a7c8d9e"; const url = `/api/v1/documents/${envelope}/signed`; await downloadFile(url, "AINA-Agreement-APP-2025-001234.pdf"); showToast("Agreement downloaded successfully"); };

ℹ️ What Happens Next Section

  • Step 1: "We'll process your application over the next 2-3 business days"
  • Step 2: "You'll receive email and SMS updates on disbursement status"
  • Step 3: "Funds will arrive in your bank account by 27 November 2025"
  • Step 4: "First payment will be automatically debited on 1 December 2025"
  • Visual Design: Numbered list with icons, light blue background card
✅ User Experience Goal

Provide clear confirmation with no ambiguity about next steps. Customer should feel confident their application is complete and know exactly when to expect funds. Minimize support inquiries through comprehensive information display.
🔌 Layer 2: API Gateway (Express.js)
RESTful endpoints for confirmation and notification orchestration

📡 GET /api/v1/applications/{id}/summary

  • Purpose: Retrieve complete application summary for confirmation display
  • Authentication: Bearer JWT token (expires 1 hour after signature)
  • Rate Limit: 10 requests per minute per user
  • Response Time: ~150ms (database query + enrichment)
  • Cache: Redis cache for 5 minutes (reduce DB load)
// Request GET /api/v1/applications/APP-2025-001234/summary Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... X-Request-ID: req_cm10_20251223_154500 // Response (200 OK) { "application_id": "APP-2025-001234", "reference": "AINA-2025-001234", "status": "completed", "loan": { "amount": 150000.00, "apr": 4.5, "term_months": 36, "monthly_payment": 4440.00, "total_interest": 9840.00, "total_repayment": 159840.00, "purpose": "Opening second café location in Dalston" }, "timeline": { "signed_at": "2025-12-23T15:45:00Z", "estimated_disbursement": "2025-11-27", "first_payment_date": "2025-12-01" }, "customer": { "name": "Olivia Thompson", "email": "olivia@smithscafe.com", "phone": "+447700900123" }, "documents": { "agreement_url": "/api/v1/documents/a7f3c5d9-e8b2-4a1c-9f6d-3e4b5a7c8d9e/signed", "payment_schedule_url": "/api/v1/applications/APP-2025-001234/schedule" } }

📡 POST /api/v1/applications/{id}/confirm

  • Purpose: Mark application as completed and trigger notification workflow
  • Idempotency: Uses idempotency key to prevent duplicate confirmations
  • Side Effects: Updates status, queues notifications, triggers webhooks
  • Transaction: All database updates wrapped in single transaction
  • Async Processing: Notifications sent via SQS queue (non-blocking)
// Request POST /api/v1/applications/APP-2025-001234/confirm Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... Idempotency-Key: idem_cm10_20251223_154501 Content-Type: application/json { "confirmed_at": "2025-12-23T15:45:01Z", "user_agent": "AINA-Mobile/2.1.0 (iOS 17.2)" } // Response (200 OK) { "success": true, "application_id": "APP-2025-001234", "status": "completed", "completed_at": "2025-12-23T15:45:01Z", "notifications": { "email_queued": true, "sms_queued": true, "webhook_queued": true } }

📡 POST /api/v1/notifications/send

  • Purpose: Internal API to trigger email and SMS notifications
  • Called By: Background worker after confirmation (not directly by client)
  • Retry Logic: Exponential backoff (1s, 2s, 4s, 8s) for failed sends
  • Delivery Tracking: Updates notifications table with sent/failed status
  • Template Rendering: Uses Handlebars for dynamic email content
// Internal request payload { "application_id": "APP-2025-001234", "channels": ["email", "sms"], "email": { "to": "olivia@smithscafe.com", "template": "application-confirmation", "data": { "customer_name": "Olivia Thompson", "reference": "APP-2025-001234", "amount": "£150,000", "disbursement_date": "27 November 2025" } }, "sms": { "to": "+447700900123", "message": "AINA: Application APP-2025-001234 complete! £150K disbursement: 27 Nov. Details sent to email." } }

📡 GET /api/v1/documents/{envelope_id}/signed

  • Purpose: Download signed loan agreement PDF with certificate of completion
  • DocuSign Integration: Fetches from DocuSign API, caches in S3
  • Response Type: application/pdf with Content-Disposition: attachment
  • Access Control: Only accessible by application owner (JWT validation)
  • Expiry: Download links valid for 24 hours
💡 API Design Pattern

All confirmation endpoints use idempotency keys to handle network retries gracefully. The confirmation process is designed to be eventually consistent - if notification delivery fails, the background worker will retry automatically without requiring user action.

⚙️ Layer 3: Business Logic (Node.js Services)
Application completion workflow and notification orchestration

🔄 Application Status Transition

  • From Status: "signed" (set by CM09 after DocuSign completion)
  • To Status: "completed" (customer has viewed confirmation)
  • Validation: Ensure signature exists, DocuSign envelope is completed
  • Side Effects: Update completed_at timestamp, trigger notifications, create audit log
  • Next Status: "disbursed" (set by payment processor after fund transfer)
  • State Machine: Uses finite state machine pattern to prevent invalid transitions
// Application completion service class ApplicationService { async completeApplication(applicationId, userId) { // 1. Validate current status const app = await db.applications.findById(applicationId); if (app.current_status !== 'signed') { throw new Error('Application must be signed first'); } // 2. Update status in transaction await db.transaction(async (trx) => { await trx.applications.update(applicationId, { current_status: 'completed', completed_at: new Date() }); // 3. Create audit trail await trx.audit_logs.insert({ application_id: applicationId, event_type: 'application_completed', user_id: userId, timestamp: new Date() }); }); // 4. Queue notifications (async) await notificationQueue.send({ type: 'application_confirmation', application_id: applicationId }); return { success: true, status: 'completed' }; } }

📧 Email Content Generation

  • Template: Handlebars template with AINA branding (logo, colors, footer)
  • Subject Line: "Your AINA Loan Application is Complete! [APP-2025-001234]"
  • Dynamic Content: Customer name, loan amount, disbursement date, reference number
  • Attachments: Signed agreement PDF (if enabled), payment schedule PDF
  • Call-to-Action: "View Application" button linking to mobile app deep link
  • Compliance: Unsubscribe link (required by CAN-SPAM), privacy policy link
// Email template data structure const emailData = { customer_name: "Olivia Thompson", reference_number: "APP-2025-001234", loan_amount: "£150,000", disbursement_date: "27 November 2025", first_payment_date: "1 December 2025", monthly_payment: "£4,440", deep_link: "aina://app/applications/APP-2025-001234", support_email: "support@aina.com", support_phone: "+44 20 1234 5678" };

📱 SMS Content Generation

  • Character Limit: 160 characters (single SMS) to minimize cost
  • Format: "AINA: Application [REF] complete! £[AMOUNT] disbursement: [DATE]. Details sent to email."
  • Example: "AINA: Application APP-2025-001234 complete! £150K disbursement: 27 Nov. Details sent to email."
  • Sender ID: "AINA" (alpha sender ID for UK)
  • Opt-Out: Reply "STOP" to unsubscribe (Twilio handles automatically)

📊 Disbursement Date Calculation

  • Base Rule: T+2 or T+3 business days from signature completion
  • Business Days: Excludes weekends and UK bank holidays
  • Cut-Off Time: Applications signed before 2pm get T+2, after 2pm get T+3
  • Holiday Calendar: Integrates with UK gov bank holiday API
  • Example: Signed Mon 23 Dec 3:45pm → Disbursement Thu 27 Nov (T+3 due to after 2pm)
// Disbursement date calculator function calculateDisbursementDate(signedAt) { const cutoffTime = 14; // 2pm const hour = signedAt.getHours(); const addDays = hour < cutoffTime ? 2 : 3; let date = new Date(signedAt); let businessDays = 0; while (businessDays < addDays) { date.setDate(date.getDate() + 1); if (isBusinessDay(date)) businessDays++; } return date; } // Example: 23 Dec 2025 3:45pm → 27 Nov 2025

🔗 CRM Webhook Trigger

  • Target System: Salesforce or HubSpot (configurable via environment)
  • Payload: Application details, customer info, loan terms, status change
  • Purpose: Notify relationship manager of completed application for follow-up
  • Timing: Sent asynchronously after status update (non-blocking)
  • Retry: Up to 5 retries with exponential backoff if webhook fails
⚠️ Notification Timing: Notifications are queued but not guaranteed to be sent immediately. During high load, email delivery may take 1-2 minutes. SMS typically delivers within 10 seconds due to Twilio's priority routing.
🔗 Layer 4: Integration Layer (AWS Services)
Message queuing and external service orchestration

📨 AWS SQS - Notification Queue

  • Queue Name: aina-notifications-production
  • Message Type: JSON payload with application_id, notification_type, channels
  • Visibility Timeout: 60 seconds (worker has 1 minute to process)
  • Dead Letter Queue: aina-notifications-dlq (messages that fail 3+ times)
  • Throughput: Supports 3,000 messages/second (well above current needs)
  • Cost: $0.40 per 1M requests (essentially free for our volume)
// SQS message payload { "MessageId": "msg_20251223_154502", "Body": { "type": "application_confirmation", "application_id": "APP-2025-001234", "channels": ["email", "sms", "webhook"], "customer": { "email": "olivia@smithscafe.com", "phone": "+447700900123", "name": "Olivia Thompson" }, "priority": "high", "retry_count": 0 } }

⚙️ Background Worker (Node.js Process)

  • Deployment: ECS Fargate container, scales 1-5 instances based on queue depth
  • Polling: Long-polling SQS every 20 seconds (waits up to 20s for messages)
  • Processing: Parallel processing of up to 10 messages at once per worker
  • Error Handling: Caught exceptions log to CloudWatch, message returns to queue
  • Success: Message deleted from queue after all channels successfully sent
  • Monitoring: CloudWatch metrics for queue depth, processing time, error rate
// Worker message processing async function processMessage(message) { const { application_id, channels, customer } = message.Body; try { // Parallel execution for speed const results = await Promise.allSettled([ channels.includes('email') ? sendEmail(customer.email, application_id) : null, channels.includes('sms') ? sendSMS(customer.phone, application_id) : null, channels.includes('webhook') ? sendWebhook(application_id) : null ]); // Log results to database await logNotificationResults(application_id, results); // Delete message from queue await sqs.deleteMessage(message.ReceiptHandle); } catch (error) { logger.error('Notification failed', { application_id, error }); // Message returns to queue automatically } }

🔄 Retry Logic & Dead Letter Queue

  • Max Retries: 3 attempts per message (initial + 2 retries)
  • Retry Delay: Exponential backoff (30s, 2min, 10min)
  • DLQ Trigger: After 3 failed attempts, message moves to dead letter queue
  • DLQ Monitoring: CloudWatch alarm triggers if DLQ depth > 0
  • Manual Intervention: Support team reviews DLQ messages daily, reprocesses manually
  • Customer Impact: If all retries fail, customer support contacts customer directly

📊 S3 Storage for Documents

  • Bucket: s3://aina-agreements/[application_id]/
  • Signed Agreement: Cached copy of DocuSign PDF after completion
  • Payment Schedule: Generated PDF with amortization table
  • Access Control: Pre-signed URLs valid for 24 hours
  • Lifecycle Policy: Transition to Glacier after 7 years (regulatory requirement)
💡 Scalability Design

The queue-based architecture decouples confirmation from notification delivery. This allows the UI to respond immediately while notifications are processed asynchronously. During peak times (e.g., end of month), additional workers spin up automatically to handle increased load.

🌐 Layer 5: External Systems & APIs
Third-party notification and storage services

✉️ SendGrid - Email Service

  • Plan: Pro Plan ($89.95/month for 100K emails, currently using ~5K/month)
  • API Version: v3 REST API with JSON payloads
  • Authentication: API key in Authorization header (Bearer token)
  • Features Used: Transactional templates, attachment support, click tracking
  • Deliverability: 99.2% delivery rate, dedicated IP address for reputation
  • Response Time: ~200ms API response, email typically delivers in 5-30 seconds
  • Webhooks: Event webhook notifies us of opens, clicks, bounces, spam reports
// SendGrid API request POST https://api.sendgrid.com/v3/mail/send Authorization: Bearer SG.xxx... Content-Type: application/json { "personalizations": [{ "to": [{ "email": "olivia@smithscafe.com", "name": "Olivia Thompson" }], "dynamic_template_data": { "customer_name": "Olivia", "reference": "APP-2025-001234", "amount": "£150,000", "disbursement_date": "27 November 2025" } }], "from": { "email": "noreply@aina.com", "name": "AINA" }, "template_id": "d-7f8a9b0c1d2e3f4g", "attachments": [{ "content": "JVBERi0xLjQK...", // base64 PDF "filename": "Loan-Agreement.pdf", "type": "application/pdf" }] } // Response (202 Accepted) { "message": "Queued", "message_id": "sg_20251223154503" }

📱 Twilio - SMS Service

  • Plan: Pay-as-you-go ($0.0075 per SMS to UK numbers)
  • API Version: 2010-04-01 REST API
  • Authentication: Basic auth with Account SID and Auth Token
  • Sender ID: Alpha sender ID "AINA" (approved for UK)
  • Delivery Rate: 99.7% to UK mobile networks
  • Response Time: ~300ms API response, SMS delivers in 2-10 seconds
  • Status Callbacks: Webhook notifies us of delivered/failed/undelivered status
  • Opt-Out Handling: Twilio automatically handles STOP/UNSTOP keywords
// Twilio API request POST https://api.twilio.com/2010-04-01/Accounts/ACxxx.../Messages.json Authorization: Basic QUNxxxxxx... // base64(SID:Token) Content-Type: application/x-www-form-urlencoded To="+447700900123" &From="AINA" &Body="AINA: Application APP-2025-001234 complete! £150K disbursement: 27 Nov. Details sent to email." &StatusCallback="https://api.aina.com/webhooks/twilio/status" // Response (201 Created) { "sid": "SM9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4", "status": "queued", "to": "+447700900123", "from": "AINA", "price": "0.0075", "price_unit": "USD" }

☁️ AWS S3 - Document Storage

  • Region: eu-west-2 (London) for GDPR compliance
  • Storage Class: Standard (frequent access) transitioning to Glacier
  • Encryption: AES-256 server-side encryption (SSE-S3)
  • Versioning: Enabled (keeps history of all document versions)
  • Access Method: Pre-signed URLs valid for 24 hours
  • Cost: ~$0.023 per GB per month (currently ~200GB = $4.60/month)

🔗 CRM Webhook (Salesforce/HubSpot)

  • Target: Salesforce REST API or HubSpot Deals API
  • Purpose: Update deal stage to "Completed" and notify relationship manager
  • Authentication: OAuth 2.0 with refresh token rotation
  • Data Sync: Application status, disbursement date, loan amount
  • Retry: 5 retries with exponential backoff if webhook fails
✅ Service Reliability

SendGrid and Twilio both provide 99.9%+ uptime SLAs. Combined with our retry logic and queue-based architecture, notification delivery is extremely reliable. In the rare case both email and SMS fail, the customer can always access their confirmation in the mobile app.
💾 Layer 6: Data Layer (PostgreSQL)
Status updates and notification tracking

📊 applications Table - Status Update

  • Primary Key: application_id (VARCHAR(50))
  • Status Field: current_status updated from "signed" → "completed"
  • Timestamp: completed_at set to NOW() when status changes
  • Indexes: Index on (current_status, completed_at) for reporting queries
  • Transaction: All updates wrapped in single transaction with audit log insert
-- Update application status UPDATE applications SET current_status = 'completed', completed_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP WHERE application_id = 'APP-2025-001234' AND current_status = 'signed'; -- Optimistic lock -- Result -- application_id: APP-2025-001234 -- current_status: completed -- completed_at: 2025-12-23 15:45:01

📊 notifications Table - Delivery Tracking

  • Schema: Records every notification attempt (email, SMS, webhook)
  • Status Values: queued, sent, delivered, failed, bounced
  • Timestamps: queued_at, sent_at, delivered_at for full lifecycle tracking
  • External IDs: Stores SendGrid message_id and Twilio sid for tracking
  • Error Logging: error_message field captures failure reasons for debugging
  • Retry Tracking: retry_count incremented on each attempt
-- Insert notification records INSERT INTO notifications ( notification_id, application_id, channel, status, recipient, external_id, queued_at ) VALUES ('NOTIF-001-EMAIL', 'APP-2025-001234', 'email', 'queued', 'olivia@smithscafe.com', NULL, CURRENT_TIMESTAMP), ('NOTIF-001-SMS', 'APP-2025-001234', 'sms', 'queued', '+447700900123', NULL, CURRENT_TIMESTAMP); -- Update after successful send UPDATE notifications SET status = 'sent', external_id = 'sg_20251223154503', sent_at = CURRENT_TIMESTAMP WHERE notification_id = 'NOTIF-001-EMAIL';

📊 notifications Table Schema

  • notification_id: VARCHAR(50) PRIMARY KEY
  • application_id: VARCHAR(50) FOREIGN KEY → applications
  • channel: VARCHAR(20) - 'email', 'sms', 'webhook'
  • status: VARCHAR(20) - 'queued', 'sent', 'delivered', 'failed'
  • recipient: VARCHAR(255) - email address or phone number
  • external_id: VARCHAR(100) - SendGrid/Twilio message ID
  • queued_at: TIMESTAMP - when notification was queued
  • sent_at: TIMESTAMP - when sent to external service
  • delivered_at: TIMESTAMP - when confirmed delivered
  • error_message: TEXT - error details if failed
  • retry_count: INTEGER DEFAULT 0 - number of retry attempts

📝 Audit Log Entry

  • Event Type: "application_completed"
  • Indexed to Elasticsearch: For real-time analytics and compliance reporting
  • Retention: 7 years (regulatory requirement for financial services)
  • Searchable Fields: application_id, user_id, timestamp, event_type
-- Audit log JSON structure (indexed to Elasticsearch) { "event_id": "evt_20251223_154501", "application_id": "APP-2025-001234", "event_type": "application_completed", "user_id": "USR-2025-789", "timestamp": "2025-12-23T15:45:01Z", "metadata": { "previous_status": "signed", "new_status": "completed", "ip_address": "81.103.45.67", "user_agent": "AINA-Mobile/2.1.0 (iOS 17.2)", "session_id": "sess_cm10_20251223" }, "changes": { "completed_at": "2025-12-23T15:45:01Z", "notifications_triggered": ["email", "sms", "webhook"] } }
💡 Data Retention Policy

Notification records are retained for 2 years in hot storage (PostgreSQL) for customer service inquiries. After 2 years, records are archived to S3 Glacier for the remaining 5 years to meet the 7-year financial services regulatory requirement.

📊 Complete Sequence: Confirmation Display & Notification Flow
👤
Customer
1. Completes CM09 signature → redirects to CM10
💻
Browser
💻
Browser
2. GET /api/v1/applications/APP-2025-001234/summary
🔒
API Gateway
🔒
API Gateway
3. Query application details (status, loan terms, customer)
💾
PostgreSQL
💾
PostgreSQL
4. Return application data (amount: £150K, APR: 4.5%, etc.)
🔒
API Gateway
🔒
API Gateway
5. Return JSON summary to browser
💻
Browser
💻
Browser
6. Render confirmation screen (success checkmark, timeline, buttons)
👤
Customer
🔒
API Gateway
7. POST /api/v1/applications/APP-2025-001234/confirm (mark complete)
💾
PostgreSQL
💾
PostgreSQL
8. Update status: signed → completed, set completed_at timestamp
🔒
API Gateway
🔒
API Gateway
9. Queue notification message to SQS (async, non-blocking)
📨
AWS SQS
📨
AWS SQS
10. Worker polls queue, retrieves notification job
⚙️
Background Worker
⚙️
Background Worker
11. Send confirmation email (olivia@smithscafe.com)
✉️
SendGrid
⚙️
Background Worker
12. Send SMS (+44 7700 900123): "Application complete! £150K..."
📱
Twilio SMS
⚙️
Background Worker
13. Send CRM webhook (update deal status to "Completed")
🔗
Salesforce CRM
⚙️
Background Worker
14. Update notifications table (status: sent, external IDs)
💾
PostgreSQL
⚙️
Background Worker
15. Delete message from SQS (successful processing)
📨
AWS SQS
✉️
SendGrid
16. Email delivered to inbox (5-30 seconds later)
👤
Customer
📱
Twilio SMS
17. SMS delivered to mobile (2-10 seconds later)
👤
Customer
⚠️ Error Scenarios & Handling

Application Not Found

Customer attempts to view confirmation for non-existent application ID (e.g., manual URL manipulation).

Response: 404 Not Found
UI: "Application not found. Please check your reference number."
Action: Redirect to dashboard after 3 seconds

Already Confirmed

Customer returns to CM10 screen after application already marked as completed (e.g., browser back button).

Response: 200 OK (idempotent)
UI: Show existing confirmation data (no duplicate notifications)
Action: Display same confirmation screen, no side effects

Email Delivery Failed

SendGrid API returns error (invalid email, mailbox full, hard bounce).

Response: SendGrid 400/500
UI: No immediate UI impact (async)
Action: Log failure, retry 3 times, alert support if all fail

SMS Delivery Failed

Twilio API returns error (invalid phone number, carrier rejected, number unreachable).

Response: Twilio 400/500
UI: No immediate UI impact (async)
Action: Log failure, retry 3 times, fallback to email only

Notification Service Unavailable

SendGrid or Twilio experiencing outage (500/503 errors).

Response: HTTP 503 Service Unavailable
UI: Confirmation still shown (services are decoupled)
Action: Queue retries every 5 minutes for 2 hours

Database Update Failed

PostgreSQL connection timeout or transaction deadlock during status update.

Response: 500 Internal Server Error
UI: "Unable to complete confirmation. Please try again."
Action: Rollback transaction, log error, retry with exponential backoff

Invalid Email Address

Customer's email address in system is malformed or invalid (e.g., typo during signup).

Response: Email validation failed
UI: Confirmation shown with note: "Email notification may fail"
Action: Log validation error, skip email, send SMS only

Invalid Phone Number

Customer's phone number is invalid or not a mobile number (e.g., landline, international format issue).

Response: Phone validation failed
UI: No impact (SMS is optional channel)
Action: Log validation error, skip SMS, send email only

CRM Webhook Failed

Salesforce/HubSpot API unavailable or returns authentication error.

Response: CRM API 401/500
UI: No impact (customer-facing flow unaffected)
Action: Retry webhook 5 times, alert ops team if all fail

Document Download Failed

Customer clicks "Download Agreement" but DocuSign envelope or S3 file is unavailable.

Response: 404 Not Found or 500 Error
UI: "Document temporarily unavailable. Try again in a few minutes."
Action: Log error, alert support, provide email copy as fallback

CM10 Architecture Complete - Final screen in Customer Mobile Journey

AINA Architecture Documentation • Customer Mobile Journey • CM10 of 10 ✅