Iris Debt Collection Management System
Enterprise-Grade Financial Operations Platform
Executive Summary
Iris is a sophisticated, enterprise-scale debt collection and payment processing system built on modern .NET architecture. It exemplifies professional software engineering through clean architecture, domain-driven design, and comprehensive test coverage. The system manages the complete lifecycle of debt collection operations, from case assignment through payment reconciliation and financial reporting.

Key Differentiators:
- Multi-platform deployment (Desktop, Web, Services) from a unified codebase
- Rich domain model with 316+ business entities
- Comprehensive audit trail and compliance features
- Enterprise-grade CI/CD with Azure Pipelines
- Extensible framework architecture supporting multiple products
Table of Contents
- Project Overview
- Technical Architecture
- Technology Stack
- System Components
- Domain Model
- Design Patterns & Best Practices
- Build & Deployment
- Notable Technical Achievements
Project Overview
What is Iris?
Iris is a comprehensive debt collection and case management platform designed for collection agencies and creditor organizations. It automates and streamlines the entire debt recovery process while maintaining compliance with financial regulations and providing detailed audit trails.
Key Features
Case Management
- Complete job lifecycle tracking from assignment to resolution
- Multi-party coordination (agents, coordinators, clients, debtors)
- Task assignment and workflow automation
- Document management and attachment tracking
Financial Operations
- Multi-ledger accounting system
- Payment processing integration (Bpoint gateway)
- Transaction reconciliation and clearing
- Xero accounting software integration
- Comprehensive financial reporting
Communication Hub
- Email integration with Outlook/Exchange
- Communication template management
- Automated email capture and tracking
- SMS and phone call logging
Reporting & Analytics
- Active jobs dashboard
- Financial performance reports
- Agent productivity tracking
- Customizable charts and visualizations
- Export to Word, Excel, and PDF
Batch Processing
- Scheduled task execution via ServerActions
- Payment file processing
- Data synchronization with external systems
- Automated workflow execution
Target Users
- Debt Collection Agencies: Primary users managing collections on behalf of creditors
- Credit Management Teams: In-house collection departments
- Financial Coordinators: Support staff managing administrative tasks
- Management: Executive reporting and oversight
- Client Contacts: Creditor representatives monitoring progress
Technical Architecture
Architectural Overview
Iris employs a layered architecture with clear separation of concerns, built upon the proprietary Torq Framework. This design enables code reuse, maintainability, and testability while supporting multiple deployment targets from a single codebase.
Desktop App] B[Iris.Blazor
Web Application] C[Iris.ServerActions
Batch Service] D[Iris.PaymentProcessor
Payment Service] end subgraph "Application Layer" E[Iris.Services.*
Business Services] F[Iris.Reports
Report Generation] end subgraph "Domain Layer" G[Iris.Model
316+ Domain Entities] H[Business Logic
& Validation] end subgraph "Data Access Layer" I[Torq.Mapping.EntityFrameworkCore] J[Torq.Mapping.Matisse] K[Torq.Mapping.Json] end subgraph "Infrastructure Layer" L[Torq.Foundation
Core Framework] M[Torq.Store
Persistence] end subgraph "External Systems" N[(SQL Server)] O[Bpoint Gateway] P[Xero Accounting] Q[Exchange/SMTP] end A --> E B --> E C --> E D --> E E --> G F --> G G --> H H --> I H --> J H --> K I --> M J --> M K --> M M --> N E --> O E --> P E --> Q style G fill:#4a90e2,color:#fff style L fill:#50c878,color:#fff style N fill:#ff6b6b,color:#fff
Architectural Principles
For Software Developers:
- Separation of Concerns: Each layer has distinct responsibilities with minimal coupling
- Domain-Driven Design: Rich domain model encapsulates business rules and behavior
- Dependency Inversion: High-level modules don’t depend on low-level modules; both depend on abstractions
- Single Responsibility: Components and classes have focused, well-defined purposes
- Open/Closed Principle: Framework is open for extension but closed for modification
For Business Stakeholders:
- Maintainability: Clean architecture reduces technical debt and makes updates faster and safer
- Scalability: Layered design supports horizontal scaling and performance optimization
- Flexibility: Multiple deployment models from one codebase reduces costs
- Quality: Strong separation enables comprehensive testing at each layer
- Risk Reduction: Well-defined boundaries limit the impact of changes
Framework Architecture: The Torq Foundation
The Torq Framework provides enterprise-grade infrastructure that Iris builds upon:
Core Infrastructure] B[Torq.Domain
Common Entities] C[Torq.Mapping
Data Access] D[Torq.Presentation
UI Abstractions] E[Torq.Services
Shared Services] F[Torq.Reports
Reporting Engine] end subgraph "Iris Application" G[Iris.Model
Domain Model] H[Iris Products] end A --> B A --> C A --> D B --> C C --> E D --> F G --> B G --> C H --> G H --> D H --> E H --> F style A fill:#50c878,color:#fff style G fill:#4a90e2,color:#fff
Why This Matters:
- Reusability: Framework components used across multiple products
- Consistency: Standardized patterns throughout the application
- Productivity: Pre-built infrastructure accelerates feature development
- Reliability: Battle-tested framework code reduces bugs
Technology Stack
Core Technologies
Programming Languages & Runtimes
Primary Language: C# 11.0
- Modern language features (pattern matching, records, nullable reference types)
- Language version locked to 11.0 for consistency across .NET 7.0 and .NET Framework projects
- Defined in
Directory.Build.propsto prevent accidental C# 12 usage
Runtime: .NET 7.0
- Cross-platform capability (Windows-focused deployment)
- Performance improvements over .NET Framework
- Modern async/await patterns throughout
- Windows-specific builds (.NET 7.0-windows) for desktop applications
Frontend Technologies
Web: Blazor Server
- Component-based architecture
- Real-time server-side rendering
- SignalR for WebSocket communication
- Reactive patterns via Phork.Blazor.Reactivity
Desktop: Windows Forms
- Custom controls via NineRays layout manager
- Syncfusion chart components for visualizations
- Rich desktop experience for power users
UI Component Libraries
- Syncfusion (v20.1.0.50): Enterprise-grade components for charts, grids, document generation
- Bootstrap 5: Responsive web design framework
Backend Technologies
Data Access
- Entity Framework Core: Modern ORM with LINQ support
- Custom Matisse Mapping: Legacy database integration
- Change Tracking: Audit trail via Torq.Mapping.ChangeReporter
- Multi-database Support: SQL Server (production), SQLite (dev)
Dependency Injection
- Autofac (v6.3.0): Feature-rich IoC container
- Constructor-based injection throughout
- Module-based registration for clean organization
- Integration with ASP.NET Core DI
API Integration
- NSwag: OpenAPI/Swagger client code generation
- Type-safe service clients: Generated from OpenAPI specs
- REST integration: Collect API, Xero API, Bpoint gateway
Development & Build Tools
Build Orchestration: NUKE
- Cross-platform build automation
- Product-specific builders (IrisWindowsBuilder, IrisBlazorBuilder, etc.)
- Local and CI consistency
- Extensible target system
CI/CD: Azure Pipelines
- Multi-stage pipeline (Build, Deploy)
- Parameterized builds for flexibility
- Environment-specific deployment (Production, Staging, Test)
- Artifact management and versioning
Version Control
- Git with GitVersion for semantic versioning
- Branch-based deployment strategy
- Automated changelog generation
External Integrations
Payment Processing
- Bpoint gateway (SOAP web services)
- Xero accounting (OAuth2 REST API)
- Bank file imports (SFTP)
Communication
- Exchange Web Services (EWS)
- Outlook Redemption (COM interop)
- SMTP with fallback (OpenSmtp library)
File Operations
- SSH/SFTP (Renci.SshNet)
- Document generation (Syncfusion DocIO/XlsIO)
- Compression (ProDotNetZip, Xceed.Zip)
Testing Infrastructure
Unit Testing
- NUnit 3 framework
- Moq for mocking dependencies
- Test coverage across domain model and services
Test Data Generation
- Bogus library for realistic fake data
- Iris.Faker custom extensions
- Repeatable test scenarios
System Components
Product Architecture
Iris is delivered as multiple coordinated applications, each built from the shared codebase:
Desktop Client] B[Iris.Blazor
Web Application] end subgraph "Backend Services" C[Iris.ServerActions
Batch Processor] D[Iris.PaymentProcessor
Payment Service] end subgraph "Shared Libraries" E[Iris.Model
Domain Model] F[Iris.Reports
Report Engine] G[Iris.Services.*
Business Services] end subgraph "Data Store" H[(Primary Database)] I[(SQLite
Dev/Testing)] end A --> E B --> E C --> E D --> E E --> F E --> G G --> H G --> I style E fill:#4a90e2,color:#fff style H fill:#ff6b6b,color:#fff
1. Iris.Windows (Desktop Application)
Purpose: Rich client application for power users requiring advanced functionality
Key Features:
- Full CRUD operations on all domain entities
- Advanced filtering and search capabilities
- Bulk operations and batch updates
- Custom report designer
- Offline operation capability
Technology:
- Windows Forms with custom controls
- .NET 7.0-windows runtime
- Supports both x86 and x64 architectures
- ClickOnce-style deployment via network share
Deployment:
- Published to
C:\Iris.Windows\[Version]on terminal servers - Versioned folders enable rollback
- Production and staging deployment paths
Entry Point: /DotNet/Iris/Products/IrisWindows/Program.cs
2. Iris.Blazor (Web Application)
Purpose: Modern web interface accessible from any device
Key Features:
- Responsive design for mobile/tablet/desktop
- Real-time updates via SignalR
- Azure AD authentication
- Session management and user tracking
- Maintenance mode support
Technology:
- ASP.NET Core Blazor Server
- Azure AD authentication (Microsoft Identity Platform)
- IIS deployment via WebDeploy
- Docker containerization support
Configuration: Defined in IrisPages.yml for dynamic page routing
Deployment:
- IIS website at
/irisvirtual application - Automated deployment to Azure DevOps environments
- TakeAppOffline during deployment for zero-downtime
Entry Point: /DotNet/Iris/Products/Iris.Blazor/Program.cs:18
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory(InitializeApp))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
3. Iris.ServerActions (Batch Processing Service)
Purpose: Execute scheduled and long-running background tasks
Key Capabilities:
- Scheduled task execution
- Data import/export operations
- Email processing and sending
- Report generation and distribution
- Data synchronization with external systems
Technology:
- Console application (.NET 7.0-windows)
- Command-line interface (Iris.Cli)
- Windows Task Scheduler integration
- Change reporting and audit logging
Deployment:
- Service-style deployment to
C:\Iris.ServerActions\[Version] - Staging subfolder for testing before production
- Scheduled via Windows Task Scheduler
Entry Point: /DotNet/Iris/Products/IrisServerActions/Program.cs
4. Iris.PaymentProcessor (Payment Service)
Purpose: Automated payment file processing and gateway integration
Key Functions:
- Bank file import via SFTP
- Payment reconciliation
- Bpoint gateway submission
- Payment clearing and posting
- Error handling and retry logic
Technology:
- Console application (.NET 7.0-windows)
- SSH/SFTP connectivity (Renci.SshNet)
- Transactional processing
- Comprehensive logging (Serilog)
Deployment:
- Standalone service at
C:\Iris.PaymentProcessor\[Version] - Scheduled execution via Task Scheduler
- Staging testing path available
Entry Point: /DotNet/Iris/Products/Iris.PaymentProcessor/Program.cs
Subsystem Interactions
Domain Model
Domain-Driven Design
Iris employs a rich domain model with 316+ business entities that encapsulate both data and behavior. This approach ensures business rules are centralized, testable, and maintainable.
Core Domain Entities
Key Domain Areas
1. Party Management
Agent: Collection agency staff assigned to jobsClient: Creditor organizations placing debt for collectionBorrower: Individuals who owe debtsCoordinator: Support staff managing operationsAgency: The collection agency organizationClientContact: Creditor representatives
2. Case Management
Job: Primary work unit representing a debt collection caseTask: Actionable work items within jobsCommunication: Recorded interactions (emails, calls, meetings)Note: Documentation and status updatesSkip: Skip tracing activities to locate debtors
3. Financial Management
Account: General ledger accounts (AR, expenses, revenue)Transaction: Multi-entry financial transactionsEntry: Individual ledger entriesCombinedLedger: Unified view of all financial activityPayment: Payment receipts and allocations
4. Document Management
Attachment: File attachments linked to jobsGeneratedDocument: System-created documentsRequestedDocument: Documents requested from partiesEmailMessage: Email communications and attachments
5. Configuration
ChecklistConfiguration: Workflow checklistsCommunicationTemplate: Email and letter templatesContractNumberStrategy: Contract numbering rulesAnnouncement: System announcements
Authorization Model
The domain model includes attribute-based authorization for fine-grained access control:
[AllowCreate(typeof(Administrator), typeof(Manager), typeof(Coordinator))]
[AllowDelete(typeof(Administrator), typeof(Manager))]
[AllowRead(typeof(Agent), typeof(ClientContact))]
public class Job : TorqObject
{
[AllowWrite(typeof(Administrator), typeof(Manager))]
public Money JobFee { get; set; }
[DenyRead(typeof(ClientContact))]
public Money AgencyCommission { get; set; }
}
This pattern enables:
- Role-based access control at the entity and property level
- Declarative security that’s easy to audit
- Automatic enforcement by the framework
- Clear documentation of security requirements
Object Context Pattern
All domain entities exist within an IObjectContext that provides:
- Identity Map: Ensures single instance per object ID
- Change Tracking: Monitors modifications for persistence
- Lazy Loading: Loads related entities on demand
- Query Interface: LINQ-based querying
- Transaction Management: Unit of work pattern
Example usage from Iris.Blazor:
// Context provides authenticated, change-tracked access to domain model
public class JobService
{
private readonly ITorqIrisObjectContext _context;
public IEnumerable<Job> GetActiveJobs()
{
return _context.Jobs
.Where(j => j.DateClosed == null)
.OrderByDescending(j => j.DateCreated);
}
public void AssignJob(Job job, Agent agent)
{
job.AssignAgent(agent); // Business logic in domain model
_context.SaveChanges(); // Persist changes
}
}
Design Patterns & Best Practices
Architectural Patterns
1. Layered Architecture
The system is organized into distinct layers with one-way dependencies:
Presentation → Application → Domain → Data Access → Infrastructure
Benefits:
- Testability: Each layer can be tested independently
- Maintainability: Changes isolated to specific layers
- Flexibility: Can swap implementations (e.g., database providers)
2. Domain-Driven Design (DDD)
- Ubiquitous Language: Domain model reflects business terminology
- Aggregates: Job is an aggregate root managing related entities
- Value Objects: Money, Address, Phone are immutable value objects
- Domain Services: Complex operations span multiple entities
- Repository Pattern: Abstract data access via object context
3. Dependency Injection
Autofac container manages all dependencies:
// Service registration in Startup.cs
builder.RegisterType<JobService>().AsSelf();
builder.RegisterType<PaymentService>().AsSelf();
builder.RegisterType<SqlServerObjectContext>()
.As<ITorqIrisObjectContext>()
.InstancePerLifetimeScope();
Benefits:
- Loose coupling: Components depend on interfaces
- Testability: Can inject mocks for testing
- Flexibility: Easy to swap implementations
- Lifetime management: Automatic disposal of resources
4. Unit of Work
The IObjectContext implements the Unit of Work pattern:
using (var context = contextFactory.CreateContext())
{
var job = context.Jobs.Find(jobId);
job.Close(DateTime.Now);
var payment = new Payment { Amount = job.Balance };
job.Payments.Add(payment);
context.SaveChanges(); // All changes persisted atomically
}
Benefits:
- Transaction integrity: All-or-nothing persistence
- Performance: Batches database operations
- Consistency: Ensures related changes succeed together
5. Repository Pattern
Object context provides repository-like access:
// Query interface abstracts database details
var overdueJobs = context.Jobs
.Where(j => j.DateClosed == null)
.Where(j => j.DaysOld > 90)
.Include(j => j.Agent)
.Include(j => j.Client)
.ToList();
Creational Patterns
Factory Pattern
Used for complex object creation:
public class ContractNumberFactory
{
public string GenerateContractNumber(Client client, ContractNumberStrategy strategy)
{
return strategy.Type switch
{
StrategyType.Sequential => GenerateSequential(client),
StrategyType.DateBased => GenerateDateBased(client),
StrategyType.ClientPrefixed => GenerateClientPrefixed(client),
_ => throw new ArgumentException($"Unknown strategy: {strategy.Type}")
};
}
}
Singleton Pattern
Application-level singletons:
// Torq application singleton
TorqApplication.DefineSingleton(new IrisBlazorApplication(builder));
var app = TorqApplication.CurrentApplication;
Structural Patterns
Adapter Pattern
Integrates external APIs:
// Xero API adapter
public class XeroPaymentAdapter : IPaymentGateway
{
private readonly XeroClient _client;
public PaymentResult SubmitPayment(Payment payment)
{
var xeroPayment = MapToXeroPayment(payment);
var result = _client.CreatePayment(xeroPayment);
return MapFromXeroResult(result);
}
}
Proxy Pattern
Visual proxies for UI representation:
[VisualProxy("Iris.Images.Jobs.ico")]
[CollectionVisualProxy("Iris.Images.Jobs.ico")]
public class Job : TorqObject
{
// Framework automatically loads icon for UI display
}
Facade Pattern
Service layer provides simplified interface:
public class JobManagementService
{
public void CreateJobFromContract(Contract contract, Agent agent)
{
// Orchestrates multiple operations
var job = CreateJob(contract);
job.AssignAgent(agent);
CreateInitialTasks(job);
SendNotifications(job);
SaveJob(job);
}
}
Behavioral Patterns
Strategy Pattern
Contract number generation strategies:
public interface IContractNumberStrategy
{
string Generate(Client client);
}
public class SequentialStrategy : IContractNumberStrategy { }
public class DateBasedStrategy : IContractNumberStrategy { }
Observer Pattern
Change tracking and event notifications:
public class Job : TorqObject
{
protected override void OnPropertyChanged(string propertyName)
{
base.OnPropertyChanged(propertyName);
// Notify change reporter for audit trail
ChangeReporter.RecordChange(this, propertyName);
}
}
Command Pattern
Server actions execute commands:
public interface IServerAction
{
string Name { get; }
void Execute(ActionContext context);
}
public class SendOverdueNoticesAction : IServerAction
{
public void Execute(ActionContext context)
{
var jobs = GetOverdueJobs();
foreach (var job in jobs)
{
SendNotice(job);
}
}
}
Template Method Pattern
Base builders define build workflow:
public abstract class BaseBuilder
{
public void Publish()
{
PrePublish();
DotNetPublish();
PostPublish();
CreateArtifact();
}
protected virtual void PrePublish() { }
protected abstract void DotNetPublish();
protected virtual void PostPublish() { }
protected abstract void CreateArtifact();
}
Code Organization
Separation of Concerns
Each project has a focused responsibility:
Iris.Model: Domain entities only (no UI, no data access)Iris.Services.*: Business logic and external integrationIris.Blazor: Presentation logic and Blazor componentsIris.Windows: Windows Forms UI logicTorq.Mapping.*: Data access implementations
Convention-Based Configuration
Autofac modules use conventions:
builder.RegisterAssemblyTypes(typeof(JobService).Assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsSelf()
.InstancePerLifetimeScope();
Error Handling
Centralized Exception Handling
- Global exception filters in ASP.NET Core
- Try-catch blocks at service boundaries
- Detailed logging via Serilog
- User-friendly error messages
Validation
- Property-level validation in domain model
- Service-level business rule validation
- Client-side validation in Blazor forms
- Server-side validation always enforced
Testing Strategies
Unit Tests
Test individual components in isolation:
[Test]
public void Job_CalculateInvoiceAmount_IncludesJobFeeAndExpenses()
{
var job = new Job { JobFee = new Money(100) };
job.Expenses.Add(new Expense { Amount = new Money(25) });
Assert.That(job.InvoiceAmount, Is.EqualTo(new Money(125)));
}
Integration Tests
Test database interactions:
[Test]
public void ObjectContext_SaveJob_PersistsToDatabase()
{
using var context = CreateTestContext();
var job = new Job { Number = "TEST001" };
context.Jobs.Add(job);
context.SaveChanges();
var loaded = context.Jobs.Single(j => j.Number == "TEST001");
Assert.That(loaded, Is.Not.Null);
}
Test Data Generation
Bogus/Faker for realistic test data:
var jobFaker = new Faker<Job>()
.RuleFor(j => j.Number, f => f.Random.AlphaNumeric(8))
.RuleFor(j => j.DateCreated, f => f.Date.Past())
.RuleFor(j => j.JobFee, f => new Money(f.Finance.Amount()));
var testJobs = jobFaker.Generate(100);
Build & Deployment
Build System Architecture
Iris uses NUKE Build for cross-platform, type-safe build automation:
NUKE Build System
Key Features:
- Type-safe: Strongly-typed build definitions in C#
- Cross-platform: Runs on Windows, Linux, macOS
- Composable: Reusable build components
- Local/CI consistency: Same build process everywhere
Build Targets:
From /Build/MainBuilder.cs:122:
Target Restore => _ => _
.Description("Restores nuget packages referenced in the selected Iris products.")
.Executes(() => RunSelectedBuilders(b => b.Restore()));
Target Clean => _ => _
.Description("Cleans the temporary build file output.")
.Executes(() => RunSelectedBuilders(b => b.Clean()));
Target Publish => _ => _
.Description("Publishes the build output.")
.After(Clean)
.After(Restore)
.Executes(() => RunSelectedBuilders(b => b.Publish()));
Target Test => _ => _
.Description("Runs the automated tests.")
.After(Publish)
.Executes(() => { /* Run NUnit tests */ });
Usage:
# Build all products in Release configuration
./build.ps1 Publish --configuration Release --product All
# Build specific product for testing
./build.ps1 Publish --product IrisBlazor --configuration Debug
# Run tests
./build.ps1 Test --product All
# Generate API client code
./build.ps1 GenerateCollectApi
Product Builders
Each product has a dedicated builder:
IrisWindowsBuilder:
- Builds x86 and x64 versions
- Creates versioned artifacts
- Packages as ZIP archives
- Output:
Iris.Windows-[Version]-[Platform].zip
IrisBlazorBuilder:
- Publishes web application
- Bundles wwwroot assets
- Prepares for IIS deployment
- Output:
Iris.Blazor-[Version].zip
IrisServerActionsBuilder:
- Compiles console application
- Includes CLI configuration
- Packages dependencies
- Output:
Iris.ServerActions-[Version].zip
IrisPaymentProcessorBuilder:
- Builds payment service
- Includes SSH libraries
- Configures logging
- Output:
Iris.PaymentProcessor-[Version].zip
CI/CD Pipeline
Azure Pipelines Configuration (azure-pipelines.yml):
stages:
- stage: Build
jobs:
- job: BuildApps
steps:
- task: PowerShell@2
inputs:
filePath: build.ps1
arguments: DeepClean Publish Test BackupOpenSourceRepos
--configuration Release
--product All
--artifacts-directory $(Build.ArtifactStagingDirectory)
- task: PublishPipelineArtifact@1
displayName: Publish Iris Blazor Artifact
inputs:
targetPath: $(BuildStep.IrisBlazorArtifact)
artifact: IrisBlazor
- stage: DeployIrisBlazor
dependsOn: Build
jobs:
- deployment: DeployToWebServer
environment: IrisBlazor-Production
strategy:
runOnce:
deploy:
steps:
- task: IISWebAppDeploymentOnMachineGroup@0
inputs:
WebSiteName: 'Default Web Site'
VirtualApplication: 'iris'
Package: '$(Pipeline.Workspace)/IrisBlazor/Iris.Blazor-*.zip'
Pipeline Features:
- Parameterized Builds: Configure products, configuration, verbosity
- Agent Pools: Support for Microsoft-hosted and self-hosted agents
- Branch-Based Deployment: Automatic environment selection
productionbranch → Production serversstagingbranch → Staging environmenttestbranch → Test servers
- Multi-Stage Deployment: Sequential deployment with approvals
- Rollback Support: Versioned deployments enable quick rollback
Deployment Architecture
Iris.Blazor] G[Terminal Server
Iris.Windows] H[Service Host
ServerActions] I[Service Host
PaymentProcessor] end subgraph "Data Tier" J[(Production)] end A --> B B --> C C --> D D --> E E --> F E --> G E --> H E --> I F --> J G --> J H --> J I --> J style C fill:#0078d4,color:#fff style J fill:#ff6b6b,color:#fff style F fill:#50c878,color:#fff
Deployment Targets:
From azure-pipelines.yml:49:
-
Production Branch:
- IrisBlazor → IIS virtual application
/iris - IrisWindows x64 → Terminal Server
C:\Iris.Windows\[Version] - ServerActions →
C:\Iris.ServerActions\[Version] - PaymentProcessor →
C:\Iris.PaymentProcessor\[Version]
- IrisBlazor → IIS virtual application
-
Staging Branch:
- IrisBlazor → Staging IIS site
- ServerActions/PaymentProcessor →
C:\[Product]\Staging
Versioning:
- GitVersion for semantic versioning
- Version embedded in artifacts
- Enables side-by-side deployment
- Quick rollback by switching folders
Docker Support
Iris.Blazor includes Dockerfile for containerization:
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["Iris.Blazor.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet build -c Release -o /app/build
FROM build AS publish
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Iris.Blazor.dll"]
Benefits:
- Platform-independent deployment
- Consistent runtime environment
- Scalability via container orchestration
- Development/production parity
Notable Technical Achievements
1. Unified Multi-Platform Architecture
Challenge: Support desktop, web, and service applications from a single codebase without code duplication.
Solution: Layered architecture with framework abstraction.
Technical Details:
- Torq Framework provides platform-agnostic core
- Domain model shared across all presentation layers
- Dependency injection enables platform-specific implementations
- 316 domain entities used by all 4 products
Business Value:
- Reduced development costs through code reuse
- Consistent behavior across platforms
- Single domain model simplifies testing
- Feature parity across desktop and web
2. Comprehensive Audit Trail System
Challenge: Financial regulations require complete audit trails of all data changes.
Solution: Automatic change tracking via Torq.Mapping.ChangeReporter.
Technical Details:
- Property-level change detection
- Before/after value capture
- User and timestamp attribution
- Async change reporting for performance
Implementation:
public class Job : TorqObject
{
protected override void OnPropertyChanged(string propertyName)
{
base.OnPropertyChanged(propertyName);
// Framework automatically captures change
// - Old value
// - New value
// - User making change
// - Timestamp
// - Property metadata
}
}
Business Value:
- Regulatory compliance (financial audits)
- Dispute resolution (who changed what when)
- Debugging and troubleshooting
- Security and accountability
3. Type-Safe Build System
Challenge: Traditional build scripts (batch files, shell scripts) are error-prone and platform-specific.
Solution: NUKE build system with C# build definitions.
Technical Details:
- Strongly-typed build configuration
- Compile-time verification of build logic
- IDE support (IntelliSense, refactoring)
- Cross-platform execution
From /Build/MainBuilder.cs:35:
public class MainBuilder : NukeBuild
{
[Parameter("Which Iris products to build")]
public readonly Product Product = Product.All;
[Solution("DotNet/Iris/Products/IrisWindows/Iris.Windows.sln")]
public readonly Solution IrisWindowsSolution;
Target Publish => _ => _
.After(Clean)
.After(Restore)
.Executes(() => RunSelectedBuilders(b => b.Publish()));
}
Benefits:
- Build breaks at compile-time, not runtime
- Refactoring build code is safe
- Same build process locally and in CI
- Easier to maintain than scripts
4. OAuth2 Integration with Xero
Challenge: Integrate with Xero accounting software using modern OAuth2 authentication.
Solution: Custom OAuth2 flow with token refresh management.
Technical Details:
Iris.Services.XeroAuth2service library- Automatic token refresh before expiry
- Secure token storage
- Type-safe API client generation
Business Value:
- Automated accounting synchronization
- Reduced manual data entry
- Real-time financial reporting
- Improved accuracy
5. OpenAPI Code Generation
Challenge: Maintain type-safe client code for external REST APIs as they evolve.
Solution: Automated code generation from OpenAPI/Swagger specifications.
From /Build/MainBuilder.cs:146:
Target GenerateCollectApi => _ => _
.Description("Generates CSharp client code from a Swagger/OpenAPI specification.")
.Executes(async () =>
{
string json = File.ReadAllText("swaggerCollectClient.json");
OpenApiDocument document = await OpenApiDocument.FromJsonAsync(json);
var generator = new CSharpClientGenerator(document, settings);
string code = generator.GenerateFile();
File.WriteAllText("CollectClient.Generated.cs", code);
});
Benefits:
- Type-safe API clients
- Compile-time verification of API calls
- Automatic updates when API changes
- IntelliSense support for API methods
6. Attribute-Based Authorization
Challenge: Enforce fine-grained access control across 316 domain entities.
Solution: Declarative authorization via attributes on domain model.
Technical Details:
From /DotNet/Iris/Model/Domain/Job.cs:84:
[AllowCreate(typeof(Administrator), typeof(Manager), typeof(Coordinator))]
[AllowDelete(typeof(Administrator), typeof(Manager))]
public class Job : TorqObject
{
[AllowWrite(typeof(Administrator), typeof(Manager))]
public Money JobFee { get; set; }
[DenyRead(typeof(ClientContact))]
public Money AgencyCommission { get; set; }
}
Framework enforcement:
- Automatic checks before property access
- Runtime exceptions for unauthorized access
- UI layer can query permissions for display logic
Benefits:
- Security rules documented in code Challenge: Support production SQL Server, development SQLite, and legacy Oracle/Matisse databases.
- Easy to audit and review
- Prevents accidental data exposure Challenge: Support production SQL Server, development SQLite, and legacy Oracle/Matisse databases.
7. Multi-Database Support
Challenge: Support production SQL Server, development SQLite, and legacy Oracle/Matisse databases.
Solution: Abstract data access layer with pluggable providers.
Technical Details:
ITorqIrisObjectContextabstraction- Entity Framework Core for SQL Server/SQLite
- Custom Matisse mapping for legacy
- Migration support for schema evolution
Configuration:
{
"ConnectionStrings": {
"SqlServer": "Server=prod-sql;Database=Iris",
"Sqlite": "Data Source=iris.db"
},
"Iris": {
"Matisse": {
"Server": "ins-irs-001",
"Database": "Insight"
}
}
}
Business Value:
- Development against lightweight SQLite
- Production on enterprise SQL Server
- Gradual migration from legacy systems
- Testing flexibility
8. Comprehensive Document Generation
Challenge: Generate professional documents (letters, reports, invoices) in multiple formats.
Solution: Syncfusion DocIO and XlsIO integration.
Capabilities:
- Word document generation and manipulation
- Excel spreadsheet creation
- PDF conversion
- Mail merge with domain data
- Chart and graph generation
Technical Integration:
Torq.Reports.DocIOlibrary- Template-based generation
- Dynamic data binding
- Multi-format export (DOCX, PDF, XLSX)
Business Value:
- Automated document workflows
- Consistent branding and formatting
- Reduced manual document creation
- Professional client communications
9. Branch-Based Deployment Strategy
Challenge: Support multiple environments with different deployment needs.
Solution: Intelligent branch-based deployment in Azure Pipelines.
From azure-pipelines.yml:49:
variables:
${{ if eq(variables['Build.SourceBranch'], 'refs/heads/production') }}:
webTarget: 'IrisBlazor-Production'
win64Target: 'IrisWindows-Production.INS-RDS-01'
branchTitle: 'Production'
${{ elseif eq(variables['Build.SourceBranch'], 'refs/heads/staging') }}:
webTarget: 'IrisBlazor-Staging'
branchTitle: 'Staging'
${{ elseif eq(variables['Build.SourceBranch'], 'refs/heads/test') }}:
webTarget: 'Iris-Test.INS-TST-01'
branchTitle: 'Test'
Workflow:
- Developer merges to
stagingbranch - Pipeline automatically deploys to staging servers
- After testing, merge to
productionbranch - Pipeline automatically deploys to production servers
Benefits:
- No manual deployment steps
- Consistent deployment process
- Environment-specific configuration
- Fast, reliable deployments
10. Reactive Blazor Components
Challenge: Build responsive, reactive web UI without JavaScript frameworks.
Solution: Blazor Server with Phork.Blazor.Reactivity.
Technical Details:
- Server-side rendering with SignalR
- Reactive state management
- Component lifecycle management
- Real-time updates without page refresh
Integration:
public class JobDashboard : ComponentBase
{
[Inject] private IReactiveState<JobStats> JobStatsState { get; set; }
protected override void OnInitialized()
{
// Automatically re-renders when state changes
JobStatsState.Subscribe(StateHasChanged);
}
}
Business Value:
- Modern web experience
- No separate JavaScript codebase
- Real-time collaboration features
- Reduced development complexity
Conclusion
Iris represents a sophisticated, enterprise-grade debt collection management system built with modern software engineering practices. Its layered architecture, rich domain model, and comprehensive test coverage demonstrate professional software craftsmanship.
Key Strengths
Technical Excellence:
- Clean architecture with clear separation of concerns
- Domain-driven design with 316+ business entities
- Type-safe build system and code generation
- Comprehensive test coverage
Business Value:
- Multi-platform support from unified codebase
- Automated CI/CD for rapid deployment
- Regulatory compliance with audit trails
- Extensible framework for future products
Development Quality:
- SOLID principles throughout
- Design patterns applied appropriately
- Extensive documentation (DocFx)
- Modern development practices
Technologies Demonstrated
- .NET 7.0 with C# 11.0
- Blazor Server for modern web UI
- Entity Framework Core for data access
- Autofac for dependency injection
- NUKE Build for type-safe builds
- Azure Pipelines for CI/CD
- Docker for containerization
- NUnit for comprehensive testing
Architecture Highlights
- Layered Architecture with framework abstraction
- Domain-Driven Design with rich domain model
- Dependency Injection throughout
- Repository/Unit of Work patterns
- Attribute-Based Authorization
- Multi-Database Support
- OpenAPI Code Generation
- Comprehensive Audit Trails
Contact & Further Information
This documentation showcases the Iris system as an example of professional software development capabilities, demonstrating expertise in:
- Enterprise application architecture
- Domain-driven design
- Modern .NET development
- CI/CD automation
- Multi-platform development
- External system integration
- Financial system compliance