Funding Programs Domain (funding_programs_v1)
The funding_programs_v1 domain manages grant and funding programs, including application workflows, funding program definitions (such as Perseus), benefit claims, and verification processes. It handles the complete lifecycle of funding applications and program-based benefit claims with energy efficiency and sustainability focus.
Overview
Section titled “Overview”This bounded context manages two primary workflows:
- Traditional Funding Applications: Direct grant applications with energy calculations and retrofit verification
- Perseus Program Claims: Scheme-based benefit claims with evidence submission and verification
The domain enforces business rules around:
- Application lifecycle and status transitions
- Program scheme definitions and benefits
- Claim submission, verification, and benefit awards
- Evidence tracking and compliance
- Energy baseline measurements and retrofit verification
Package Location
Section titled “Package Location”dart_packages/co2/domains/funding_programs_v1/├── lib/│ ├── funding_programs_v1.dart # Main exports and registration│ └── src/│ ├── aggregates/ # Domain aggregates│ │ ├── funding_application_aggregate.dart│ │ ├── funding_program_definition_aggregate.dart│ │ ├── funding_program_claim_aggregate.dart│ │ ├── metered_energy_baseline_aggregate.dart│ │ ├── regional_cost_benchmark_aggregate.dart│ │ └── retrofit_verification_aggregate.dart│ ├── events/ # Domain events│ │ ├── funding_program_events.dart│ │ ├── program_definition_events.dart│ │ └── claim_events.dart│ ├── directives/ # Command payloads│ │ ├── funding_program_directives.dart│ │ ├── program_definition_directives.dart│ │ └── claim_directives.dart│ └── services/ # Domain services│ ├── perseus_eligibility_policy.dart│ ├── perseus_benefit_calculator.dart│ ├── perseus_evidence_validator.dart│ └── retrofit_compliance_service.dart├── docs/│ └── PERSEUS.md # Perseus program documentation├── pubspec.yaml└── test/Key Concepts
Section titled “Key Concepts”Funding Application Lifecycle
Section titled “Funding Application Lifecycle”A funding application progresses through distinct states:
- Submitted: Initial state when application is created
- Under Review: Application being evaluated
- Approved: Application has been approved with an approved amount
- Rejected: Application has been rejected with a reason
- Withdrawn: Application has been withdrawn by applicant
Applications include energy calculations to assess eligibility and justify funding amounts.
Perseus Program Framework
Section titled “Perseus Program Framework”Perseus is a government-backed scheme for sustainability-linked finance and grant funding. It includes:
- Program Definitions: Scheme rules, benefits, eligibility criteria, and evidence requirements
- Benefit Claims: Organizations apply for specific benefits under a program
- Evidence Submission: Claims require evidence (certificates, reports, calculations)
- Verification: Third-party verification of claims and energy reductions
- Monitoring: Post-award monitoring of benefit compliance
Key Aggregates
Section titled “Key Aggregates”FundingApplicationAggregate
Section titled “FundingApplicationAggregate”Manages the lifecycle of traditional funding applications with energy calculations.
class FundingApplicationAggregate extends Aggregate<FundingApplicationAggregate> { final FundingApplicationId applicationId; final FundingProgramId programId; final UserId applicantId; final ApplicationTitle projectTitle; final double requestedAmount; final FundingApplicationStatus status;
// Energy calculations Map<EnergyCalculationId, EnergyCalculation> energyCalculations;
// Approval details double? approvedAmount; DomainText? rejectionReason;}Key Methods:
canBeApproved(): Checks if application can transition to approvedcanBeRejected(): Checks if application can be rejectedallCalculationsMeetCriteria: Validates that all energy calculations meet funding criteria
FundingProgramDefinitionAggregate
Section titled “FundingProgramDefinitionAggregate”Defines the rules, benefits, and requirements of a funding program like Perseus.
class FundingProgramDefinitionAggregate extends Aggregate<FundingProgramDefinitionAggregate> { final FundingProgramId programId; final FundingProgramCode programCode; final ProgramVersion version; final List<BenefitDefinition> benefitCatalog; final EligibilityPolicy eligibilityPolicy; final List<EvidenceRequirement> evidenceRequirements; final AssurancePolicy assurancePolicy; final bool isActive;}Key Responsibilities:
- Maintain program scheme definition and benefits
- Track program versions and updates
- Define eligibility rules and evidence requirements
- Support program activation/deactivation
FundingProgramClaimAggregate
Section titled “FundingProgramClaimAggregate”Represents an organization’s claim for a benefit under a funding program.
class FundingProgramClaimAggregate extends Aggregate<FundingProgramClaimAggregate> { final FundingProgramClaimId claimId; final FundingProgramId programId; final OrganizationId claimantId; final BenefitType selectedBenefitType; final ClaimStatus status; final List<ClaimEvidence> evidenceRefs; final VerificationOutcome? verificationOutcome; final AwardTerms? awardTerms;}Claim Lifecycle:
- Draft: Claim being prepared
- Submitted: Claim submitted to program
- Evidence Pending: Awaiting evidence submission/verification
- Verified: Evidence has been verified
- Awarded: Benefit has been awarded
- Active Monitoring: Post-award monitoring phase
- Completed: Monitoring period completed
- Revoked: Claim revoked due to non-compliance
MeteredEnergyBaselineAggregate
Section titled “MeteredEnergyBaselineAggregate”Tracks electricity consumption baselines from smart metering.
class MeteredEnergyBaselineAggregate extends Aggregate<MeteredEnergyBaselineAggregate> { final MeteredEnergyBaselineId baselineId; final SiteId siteId; final List<ElectricityReading> electricityReadings; final List<String> validationErrors;}RetrofitVerificationAggregate
Section titled “RetrofitVerificationAggregate”Verifies that retrofitting work has been completed to specification.
class RetrofitVerificationAggregate extends Aggregate<RetrofitVerificationAggregate> { final RetrofitVerificationId verificationId; final FundingApplicationId applicationId; final bool installedAsSpecified; final String status; // 'pending' | 'completed' | 'failed' final List<AttachmentId> evidenceAttachmentIds;}RegionalCostBenchmarkAggregate
Section titled “RegionalCostBenchmarkAggregate”Defines cost benchmarks for retrofit measures by region and measure type.
class RegionalCostBenchmarkAggregate extends Aggregate<RegionalCostBenchmarkAggregate> { final RegionalCostBenchmarkId benchmarkId; final String region; final String measureType; final double maxCostPerUnit;}Domain Events
Section titled “Domain Events”Funding Application Events
Section titled “Funding Application Events”FundingApplicationSubmittedEvent
Section titled “FundingApplicationSubmittedEvent”Fired when an organization submits a funding application.
class FundingApplicationSubmittedEvent implements Event { final FundingApplicationId applicationId; final FundingProgramId programId; final UserId applicantId; final ApplicationTitle projectTitle; final double requestedAmount; final FundingProjectData fundingProjectData; final List<AttachmentId> attachmentIds;}FundingApplicationStatusChangedEvent
Section titled “FundingApplicationStatusChangedEvent”Fired when application status changes (approved, rejected, withdrawn).
class FundingApplicationStatusChangedEvent implements Event { final FundingApplicationId applicationId; final FundingApplicationStatus newStatus; final double? approvedAmount; final DomainText? rejectionReason;}EnergyCalculationCompletedEvent
Section titled “EnergyCalculationCompletedEvent”Fired when energy efficiency calculations are completed for an application.
class EnergyCalculationCompletedEvent implements Event { final EnergyCalculationId calculationId; final EnergyCalculationType calculationType; final double totalEnergyLoss; final double totalArea; final double averageEfficiency; final bool meetsCriteria; final EnergyCalculationData energyCalculationData;}Program Definition Events
Section titled “Program Definition Events”FundingProgramDefinedEvent
Section titled “FundingProgramDefinedEvent”Fired when a new funding program scheme is created.
class FundingProgramDefinedEvent implements Event { final FundingProgramId programId; final FundingProgramCode programCode; final ProgramVersion version; final List<BenefitDefinition> benefitCatalog; final EligibilityPolicy eligibilityPolicy; final List<EvidenceRequirement> evidenceRequirements; final AssurancePolicy assurancePolicy;}BenefitAddedToProgramEvent
Section titled “BenefitAddedToProgramEvent”Fired when a new benefit is added to an active program.
class BenefitAddedToProgramEvent implements Event { final FundingProgramId programId; final BenefitDefinition benefit;}ProgramDeactivatedEvent
Section titled “ProgramDeactivatedEvent”Fired when a program is deactivated.
class ProgramDeactivatedEvent implements Event { final FundingProgramId programId;}Claim Events
Section titled “Claim Events”ClaimSubmittedEvent
Section titled “ClaimSubmittedEvent”Fired when an organization submits a claim for a program benefit.
class ClaimSubmittedEvent implements Event { final FundingProgramClaimId claimId; final FundingProgramId programId; final OrganizationId claimantId; final BenefitType selectedBenefitType; final ReductionTarget? declaredTarget; final MonitoringPeriod? monitoringPeriod;}EvidenceAttachedToClaimEvent
Section titled “EvidenceAttachedToClaimEvent”Fired when evidence is attached to support a claim.
class EvidenceAttachedToClaimEvent implements Event { final FundingProgramClaimId claimId; final ClaimEvidence evidence;}ClaimVerificationRequestedEvent
Section titled “ClaimVerificationRequestedEvent”Fired when verification is requested for a claim.
class ClaimVerificationRequestedEvent implements Event { final FundingProgramClaimId claimId; final UserId verifierId;}ClaimVerificationCompletedEvent
Section titled “ClaimVerificationCompletedEvent”Fired when claim verification is completed.
class ClaimVerificationCompletedEvent implements Event { final FundingProgramClaimId claimId; final VerificationOutcome outcome;}BenefitAwardedEvent
Section titled “BenefitAwardedEvent”Fired when a benefit is awarded following successful verification.
class BenefitAwardedEvent implements Event { final FundingProgramClaimId claimId; final AwardTerms awardTerms;}ClaimMonitoringStartedEvent
Section titled “ClaimMonitoringStartedEvent”Fired when post-award monitoring begins.
class ClaimMonitoringStartedEvent implements Event { final FundingProgramClaimId claimId; final MonitoringPeriod period;}MonitoringPeriodCompletedEvent
Section titled “MonitoringPeriodCompletedEvent”Fired when the monitoring period ends successfully.
class MonitoringPeriodCompletedEvent implements Event { final FundingProgramClaimId claimId;}ClaimRevokedEvent
Section titled “ClaimRevokedEvent”Fired when a claim is revoked due to non-compliance.
class ClaimRevokedEvent implements Event { final FundingProgramClaimId claimId; final String reason;}Directives (Commands)
Section titled “Directives (Commands)”Directives represent commands that trigger state changes in the domain.
Funding Application Directives
Section titled “Funding Application Directives”SubmitFundingApplicationDirective
Section titled “SubmitFundingApplicationDirective”Submit a new funding application.
class SubmitFundingApplicationPayload extends Payload { final FundingApplicationId applicationId; final FundingProgramId programId; final UserId applicantId; final ApplicationTitle projectTitle; final ApplicationDescription projectDescription; final double requestedAmount; final CurrencyCode currency; final Map<String, dynamic> projectData; final List<AttachmentId> attachmentIds;}UpdateFundingApplicationStatusDirective
Section titled “UpdateFundingApplicationStatusDirective”Change the status of an application (approve, reject, withdraw).
class UpdateFundingApplicationStatusPayload extends Payload { final FundingApplicationId applicationId; final FundingApplicationStatus newStatus; final double? approvedAmount; final DomainText? rejectionReason;}CompleteEnergyCalculationDirective
Section titled “CompleteEnergyCalculationDirective”Submit completed energy efficiency calculations for an application.
class CompleteEnergyCalculationPayload extends Payload { final EnergyCalculationId calculationId; final FundingApplicationId applicationId; final EnergyCalculationType calculationType; final double totalEnergyLoss; final double totalArea; final double averageEfficiency; final bool meetsCriteria;}Program Definition Directives
Section titled “Program Definition Directives”DefineFundingProgramDirective
Section titled “DefineFundingProgramDirective”Create a new funding program scheme (like Perseus).
class DefineFundingProgramPayload extends Payload { final FundingProgramId programId; final FundingProgramCode programCode; final ProgramVersion version; final List<BenefitDefinition> benefitCatalog; final EligibilityPolicy eligibilityPolicy; final List<EvidenceRequirement> evidenceRequirements; final AssurancePolicy assurancePolicy;}Claim Directives
Section titled “Claim Directives”SubmitFundingProgramClaimDirective
Section titled “SubmitFundingProgramClaimDirective”Submit a claim for a program benefit.
class SubmitFundingProgramClaimPayload extends Payload { final FundingProgramClaimId claimId; final FundingProgramId programId; final OrganizationId claimantId; final BenefitType selectedBenefitType; final ReductionTarget? declaredTarget;}AttachEvidenceToClaimDirective
Section titled “AttachEvidenceToClaimDirective”Attach evidence supporting the claim.
class AttachEvidenceToClaimPayload extends Payload { final FundingProgramClaimId claimId; final ClaimEvidence evidence;}RequestClaimVerificationDirective
Section titled “RequestClaimVerificationDirective”Request verification of a claim.
class RequestClaimVerificationPayload extends Payload { final FundingProgramClaimId claimId; final UserId verifierId;}CompleteClaimVerificationDirective
Section titled “CompleteClaimVerificationDirective”Complete the verification of a claim.
class CompleteClaimVerificationPayload extends Payload { final FundingProgramClaimId claimId; final VerificationOutcome outcome;}AwardBenefitDirective
Section titled “AwardBenefitDirective”Award the benefit after successful verification.
class AwardBenefitPayload extends Payload { final FundingProgramClaimId claimId; final AwardTerms awardTerms;}Funding Program Lifecycle
Section titled “Funding Program Lifecycle”Traditional Funding Application Flow
Section titled “Traditional Funding Application Flow”1. Submit Application └─> FundingApplicationSubmittedEvent └─> Application in "Submitted" state
2. Energy Calculations └─> CompleteEnergyCalculationDirective └─> EnergyCalculationCompletedEvent └─> Calculations stored in aggregate
3. Review & Decision └─> UpdateFundingApplicationStatusDirective └─> FundingApplicationStatusChangedEvent └─> Application moves to "Approved" or "Rejected"
4. Retrofit Verification (if approved) └─> Verify work completed to specification └─> RetrofitVerificationCompletedEventPerseus Benefit Claim Flow
Section titled “Perseus Benefit Claim Flow”1. Create Program Definition └─> DefineFundingProgramDirective └─> FundingProgramDefinedEvent └─> Program with benefits active
2. Submit Claim └─> SubmitFundingProgramClaimDirective └─> ClaimSubmittedEvent └─> Claim in "Submitted" state
3. Attach Evidence └─> AttachEvidenceToClaimDirective └─> EvidenceAttachedToClaimEvent (multiple times) └─> Claim in "Evidence Pending" state
4. Request Verification └─> RequestClaimVerificationDirective └─> ClaimVerificationRequestedEvent └─> Third party verifies evidence
5. Complete Verification └─> CompleteClaimVerificationDirective └─> ClaimVerificationCompletedEvent └─> Claim moves to "Verified"
6. Award Benefit └─> AwardBenefitDirective └─> BenefitAwardedEvent └─> Claim in "Awarded" state
7. Post-Award Monitoring └─> ClaimMonitoringStartedEvent └─> Track compliance during monitoring period └─> MonitoringPeriodCompletedEvent └─> Claim "Completed"Value Objects & Identifiers
Section titled “Value Objects & Identifiers”The domain uses strongly-typed identifiers from the contracts package:
| Type | Purpose |
|---|---|
FundingApplicationId | Unique application identifier |
FundingProgramId | Funding program identifier |
FundingProgramCode | Program code (e.g., “PERSEUS-2024”) |
FundingProgramClaimId | Unique claim identifier |
ApplicationTitle | Application project title |
ApplicationDescription | Detailed project description |
ProgramName | Human-readable program name |
ProgramVersion | Program version (e.g., “1.0.0”) |
BenefitType | Type of benefit (e.g., sustainabilityLinkedLoanRateReduction) |
ClaimStatus | Status of claim (draft, submitted, awarded, etc.) |
FundingApplicationStatus | Status of application (submitted, approved, rejected, etc.) |
EnergyCalculationId | Energy calculation identifier |
EnergyCalculationType | Type of calculation (general, ashp, boiler, etc.) |
CurrencyCode | Currency (GBP, EUR, USD) |
JurisdictionCode | Jurisdiction (UK, EU, etc.) |
Domain Services
Section titled “Domain Services”PerseusEligibilityPolicy
Section titled “PerseusEligibilityPolicy”Evaluates claim eligibility against program rules.
abstract class PerseusEligibilityPolicy { /// Check if organization meets program eligibility criteria bool isOrganizationEligible( OrganizationId organizationId, FundingProgramDefinitionAggregate program, );
/// Check if claimed benefit is available in program bool isBenefitAvailable( BenefitType benefit, FundingProgramDefinitionAggregate program, );}PerseusBenefitCalculator
Section titled “PerseusBenefitCalculator”Calculates benefit amounts based on program rules and claim details.
abstract class PerseusBenefitCalculator { /// Calculate monetary benefit for a claim Money calculateMonetaryBenefit( FundingProgramClaimAggregate claim, FundingProgramDefinitionAggregate program, );
/// Calculate loan rate reduction benefit double calculateLoanRateReduction( double loanAmount, int loanTermMonths, ReductionTarget target, );}PerseusEvidenceValidator
Section titled “PerseusEvidenceValidator”Validates that submitted evidence meets program requirements.
abstract class PerseusEvidenceValidator { /// Validate evidence against program requirements EvidenceValidationResult validateEvidence( List<ClaimEvidence> evidence, List<EvidenceRequirement> requirements, );
/// Check completeness of evidence package bool isEvidenceComplete( List<ClaimEvidence> evidence, List<EvidenceRequirement> requirements, );}RetrofitComplianceService
Section titled “RetrofitComplianceService”Validates retrofit work compliance.
abstract class RetrofitComplianceService { /// Validate that retrofit meets building regulations ComplianceCheckResult validateCompliance( RetrofitVerificationAggregate verification, FundingProjectData projectData, );}Domain Registration
Section titled “Domain Registration”All types must be registered for serialization/deserialization:
// In main application setup:registerFundingProgramsV1();
// Or use the module interface:final module = FundingProgramsV1();module.registerDomainTypes();The registerFundingProgramsV1() function registers:
- All aggregates (creation and deserialization factories)
- All events and their factories
- All payloads (directives)
- All custom types with the TypeRegistry
Usage Examples
Section titled “Usage Examples”Creating a Funding Application
Section titled “Creating a Funding Application”import 'package:funding_programs_v1/funding_programs_v1.dart';import 'package:contracts_v1/contracts_v1.dart';
// Create and submit applicationfinal directive = SubmitFundingApplicationPayload( applicationId: const FundingApplicationId('app-001'), programId: const FundingProgramId('prog-001'), applicantId: const UserId('user-123'), organizationId: const OrganizationId('org-456'), projectTitle: ApplicationTitle.fromString('Solar Panel Installation'), projectDescription: ApplicationDescription.fromString( 'Installing 10kW solar panels on warehouse roof', ), requestedAmount: 50000.0, currency: const CurrencyCode('GBP'), submittedBy: const UserId('user-123'), projectData: { 'buildingType': 'warehouse', 'location': 'Manchester', 'estimatedSavings': 30000.0, },);
// This would be processed by the application service// which creates an event and stores the aggregateCompleting Energy Calculations
Section titled “Completing Energy Calculations”// Complete energy efficiency calculationfinal calcDirective = CompleteEnergyCalculationPayload( calculationId: const EnergyCalculationId('calc-001'), applicationId: const FundingApplicationId('app-001'), calculationType: EnergyCalculationType.ashp, totalEnergyLoss: 45000.0, totalArea: 1200.0, averageEfficiency: 0.85, meetsCriteria: true,);
// Event is created and aggregate is updatedSubmitting a Perseus Claim
Section titled “Submitting a Perseus Claim”// Submit claim for funding program benefitfinal claimDirective = SubmitFundingProgramClaimPayload( claimId: const FundingProgramClaimId('claim-001'), programId: const FundingProgramId('PERSEUS-2024'), claimantId: const OrganizationId('org-456'), selectedBenefitType: BenefitType.sustainabilityLinkedLoanRateReduction, declaredTarget: ReductionTarget( targetPercentage: 20.0, baselineYear: 2024, targetYear: 2027, ),);
// Claim is created and processing beginsAttaching Evidence
Section titled “Attaching Evidence”// Attach evidence to support claimfinal evidenceDirective = AttachEvidenceToClaimPayload( claimId: const FundingProgramClaimId('claim-001'), evidence: ClaimEvidence( evidenceType: 'EnergyAudit', attachmentId: const AttachmentId('attach-001'), uploadedAt: DateTime.now(), uploadedBy: const UserId('user-123'), description: 'Professional energy audit report', ),);
// Evidence is attached to claimIntegration Points
Section titled “Integration Points”With Trackable Assets Domain
Section titled “With Trackable Assets Domain”- Applications may reference trackable assets (buildings, sites)
- Energy calculations use asset baseline data
- Retrofit verification confirms changes to asset configuration
With Attachments Domain
Section titled “With Attachments Domain”- Applications and claims attach supporting documents
- Evidence submission uses attachment references
- Verification requires attachment access
With Contracts Package
Section titled “With Contracts Package”- All identifiers and value objects come from contracts
- Cross-domain communication uses payload types
- Event publishing uses contract event interfaces
Business Rules
Section titled “Business Rules”-
Application Approval Rule: An application can only be approved if:
- It is in “Under Review” status
- All energy calculations meet criteria
- Approved amount does not exceed requested amount
-
Rejection Rule: Rejected applications must have a rejection reason
-
Claim Verification Rule: Claims can only be verified if:
- All required evidence has been submitted
- Evidence passes validation
- Organization meets eligibility criteria
-
Benefit Award Rule: Benefits can only be awarded after:
- Claim is verified
- Verification outcome is positive
- Monitoring period (if required) has started
-
Retrofit Completion Rule: Completed retrofit verification requires:
- Evidence attachments
- Specification compliance confirmation
-
Calculation Validity Rule: Energy calculations must meet:
- Non-empty areas
- Valid efficiency values (0-1 or percentage range)
- Consistent data across all calculations
Error Handling
Section titled “Error Handling”The domain throws StateError for validation failures:
// Application validation errorsStateError('Application ID cannot be unresolved')StateError('Project title cannot be empty')StateError('Requested amount must be positive')StateError('Approved applications must have an approved amount')StateError('Rejected applications must have a rejection reason')StateError('Approved amount cannot exceed requested amount')
// Claim validation errorsStateError('Claim ID cannot be unresolved')StateError('Program ID cannot be unresolved')StateError('Claimant ID cannot be unresolved')Testing
Section titled “Testing”The domain includes comprehensive tests for aggregates:
// Run testsdart test
// Tests cover creation, validation, event applicationPerseus Program Documentation
Section titled “Perseus Program Documentation”For detailed information about the Perseus program scheme, including:
- Program objectives and scope
- Financial product opportunities
- User roles and responsibilities
- Ecosystem map
- Future innovation cases
See: /docs/PERSEUS.md
Migration Guidance
Section titled “Migration Guidance”From Untyped to Typed Project Data
Section titled “From Untyped to Typed Project Data”The domain has been updated to use typed FundingProjectData and EnergyCalculationData value objects instead of raw Map<String, dynamic>.
// Old (deprecated)final projectData = event.projectData as Map<String, dynamic>;
// New (recommended)final typedData = event.fundingProjectData;final category = typedData.category;Access the typedProjectData property on aggregates and events for type-safe access.
Performance Considerations
Section titled “Performance Considerations”- Applications can have multiple energy calculations; consider pagination in UI
- Claims can have many evidence attachments; use lazy loading
- Program definitions with large benefit catalogs should be cached
- Monitoring periods can span months; use background jobs for completion checks