┌─────────────────────────────────────────────────────────────────┐
│ Azure Blob Storage │
│ (Invoice Upload) │
└───────────────────────┬─────────────────────────────────────────┘
│ Blob Trigger
▼
┌─────────────────────────────────────────────────────────────────┐
│ InvoiceUploadFunction │
│ (Azure Function - Blob Trigger) │
└───────────────────────┬─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ IInvoiceProcessingService │
│ (Business Logic Orchestration) │
└─────┬─────────────────┬──────────────────┬──────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌─────────────────┐ ┌─────────────────┐
│Document │ │ Validation │ │ Repository │
│Intel. │ │ Service │ │ (CosmosDB) │
│Service │ │ │ │ │
└──────────┘ └─────────────────┘ └─────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────────┐
│Azure AI │ │ CosmosDB │
│Document │ │ - Invoice Data │
│Intelligence │ │ - Status │
└──────────────┘ │ - History │
└──────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ EmailReminderFunction (Timer Trigger) │
│ - Daily at 9 AM │
│ - Every 5 minutes (for retries) │
└───────────────────────┬─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ IInvoiceProcessingService │
│ ProcessScheduledRemindersAsync() │
└─────┬──────────────────────────────────────────────────────┬────┘
│ │
▼ ▼
┌──────────────┐ ┌─────────────┐
│ Repository │ │ Email │
│ (Query) │ │ Service │
└──────────────┘ │ (SendGrid) │
└─────────────┘
InvoiceReminderSystem.Core/
├── Models/
│ ├── Invoice.cs (Aggregate Root)
│ ├── BlobMetadata.cs
│ ├── ExtractedData.cs
│ ├── ProcessingStatus.cs
│ ├── EmailNotification.cs
│ └── ...
├── Interfaces/
│ ├── IInvoiceRepository.cs
│ ├── IDocumentIntelligenceService.cs
│ ├── IEmailService.cs
│ ├── IInvoiceValidationService.cs
│ └── IInvoiceProcessingService.cs
├── Enums/
│ ├── InvoiceStatus.cs
│ ├── EmailSendStatus.cs
│ └── AttemptResult.cs
└── Exceptions/
├── ValidationException.cs
└── DocumentExtractionException.cs
InvoiceReminderSystem.Infrastructure/
├── Repositories/
│ └── InvoiceRepository.cs
├── Services/
│ ├── DocumentIntelligenceService.cs
│ ├── SendGridEmailService.cs
│ ├── InvoiceValidationService.cs
│ └── InvoiceProcessingService.cs
└── [Settings Classes]
InvoiceReminderSystem.FunctionApp/
├── Functions/
│ ├── InvoiceUploadFunction.cs
│ └── EmailReminderFunction.cs
├── Extensions/
│ └── ServiceCollectionExtensions.cs
├── Program.cs
├── host.json
└── local.settings.json
User uploads PDF
↓
Blob Storage receives file
↓
Blob Trigger fires
↓
InvoiceUploadFunction executes
↓
InvoiceProcessingService.ProcessNewInvoiceAsync()
↓
┌─────────────────────────────────────┐
│ 1. Extract data (Document Intel) │
│ 2. Validate data │
│ 3. Calculate reminder date │
│ 4. Save to CosmosDB │
└─────────────────────────────────────┘
Timer Trigger fires (9 AM daily)
↓
EmailReminderFunction executes
↓
InvoiceProcessingService.ProcessScheduledRemindersAsync()
↓
Query CosmosDB for due invoices
↓
For each invoice:
├─ Update status to "Sending"
├─ Send email via SendGrid
├─ Log attempt in history
└─ Update final status (Sent/Failed)
InvoiceRepository: Only handles data accessDocumentIntelligenceService: Only extracts data from documentsSendGridEmailService: Only sends emailsInvoiceValidationService: Only validates dataInvoiceProcessingService: Orchestrates the workflow
- All services implement interfaces
- New implementations can be added without modifying existing code
- Example: Could add
AzureCommunicationEmailServiceimplementingIEmailService
- Any
IEmailServiceimplementation can replaceSendGridEmailService - Any
IInvoiceRepositoryimplementation can replaceInvoiceRepository
- Small, focused interfaces (e.g.,
IEmailServiceonly has one method) - Functions depend only on interfaces they need
- High-level modules (Functions) depend on abstractions (Interfaces)
- Low-level modules (Services) implement abstractions
- All dependencies injected via constructor
┌─────────────────────────────────────┐
│ Validation Errors │
│ (Low confidence, missing data) │
└───────────────┬─────────────────────┘
│
▼
Mark as "ValidationFailed"
Store errors in CosmosDB
Alert via Application Insights
┌─────────────────────────────────────┐
│ Transient Email Errors │
│ (Rate limits, network issues) │
└───────────────┬─────────────────────┘
│
▼
Retry with exponential backoff
Attempt 1: +1 min
Attempt 2: +5 min
Attempt 3: +15 min
┌─────────────────────────────────────┐
│ Permanent Email Errors │
│ (Invalid email, blocked) │
└───────────────┬─────────────────────┘
│
▼
Mark as "SendFailed"
No retry
Alert for manual review
-
Application Insights
- Function execution times
- Success/failure rates
- Exception tracking
-
CosmosDB Metrics
- Request units consumed
- Query performance
- Storage size
-
Custom Logging
- Invoice processing status changes
- Validation failures with details
- Email sending attempts and results
-
Secrets Management
- API keys stored in Azure Key Vault (production)
- local.settings.json for development (not committed)
-
Data Protection
- CosmosDB uses encryption at rest
- Blob storage uses HTTPS
- SendGrid API uses TLS
-
Access Control
- Managed Identity for Azure resources
- RBAC for CosmosDB and Storage
- Least privilege principle
-
Horizontal Scaling
- Azure Functions scale automatically
- CosmosDB can be scaled via RU/s
- Blob storage has unlimited capacity
-
Partition Strategy
- CosmosDB partitioned by
invoiceMonth - Distributes load evenly across months
- CosmosDB partitioned by
-
Performance Optimization
- Indexed queries on status and date fields
- Batch processing for reminders
- Async/await throughout