high priority low complexity backend pending backend specialist Tier 1

Acceptance Criteria

An abstract class or interface `ReportPeriodValidator` exists in the codebase with a single public method `validate(DateTimeRange range, String orgId)` returning `ValidationResult`.
`ValidationResult` is a sealed class with exactly two subtypes: `ValidationSuccess` (no fields) and `ValidationFailure` containing a typed `ReportPeriodValidationError` enum value.
`ReportPeriodValidationError` enum contains at minimum three values: `invalidBoundary`, `emptyRange`, and `overlapsExistingReport`.
`ValidationFailure` carrying `overlapsExistingReport` also exposes the conflicting `DateTimeRange` so the UI can display it to the user.
The interface and sealed result types are documented with Dart doc comments explaining each rule and error code.
No concrete implementation logic exists in the abstract interface — it is a pure contract.
The file compiles without warnings under `dart analyze`.
Code review confirms the sealed class pattern prevents callers from ignoring failure cases without an exhaustive switch.

Technical Requirements

frameworks
Flutter
Dart sealed classes (Dart 3+)
data models
DateTimeRange
ReportPeriod
Organisation
performance requirements
Interface method signature must be synchronous for boundary/empty checks and async-capable via Future return wrapping for the overlap rule — design signature as `Future<ValidationResult>`.
security requirements
orgId parameter must be treated as an opaque tenant identifier — do not log or expose it in error messages.
Sealed result type ensures compile-time exhaustiveness, preventing silent swallowing of validation failures.

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Use Dart 3 sealed classes: `sealed class ValidationResult {}`, `final class ValidationSuccess extends ValidationResult {}`, `final class ValidationFailure extends ValidationResult { final ReportPeriodValidationError error; final DateTimeRange? conflictingPeriod; }`. Place the interface in `lib/features/bufdir/report_period/domain/report_period_validator.dart`. Keep the enum definition in the same file to avoid circular imports.

The method signature should be `Future validate(DateTimeRange range, String orgId)` — even though early rules are synchronous, the overlap rule requires a repository call, so Future is the correct contract from the start. Do not make two separate method signatures for sync vs async rules.

Testing Requirements

No tests required for this task — it is a pure interface/type definition. However, ensure the exported symbols are importable from the barrel file used by the BLoC layer so downstream test tasks can import without path hacks.

A compile-time check (dart analyze) is sufficient acceptance gate.

Component
Report Period Validator
service low
Epic Risks (2)
medium impact high prob dependency

Detecting overlap with previously submitted reports requires querying a report history table that may not yet exist or may not have a reliable submitted_at / period_end field, making the validator dependent on an incomplete upstream feature (Bufdir Report History & Audit Log).

Mitigation & Contingency

Mitigation: Define the minimum interface (a single repository method: getSubmittedPeriods(orgId) → List<DateTimeRange>) as an abstract class in this epic. Implement a stub that returns an empty list until the history feature is available, so the validator compiles and passes tests without a real data source.

Contingency: If the history feature is delayed beyond this feature's delivery window, ship the validator with the stub returning an empty list (overlap check disabled) and surface a feature-flag-controlled warning banner explaining that overlap detection will be enabled in a future update.

medium impact medium prob scope

Bufdir's structural requirements for reporting periods (complete calendar months, grant-year span restrictions) may be ambiguous or subject to change, causing the validator to enforce rules that are incorrect or overly restrictive for some organisations.

Mitigation & Contingency

Mitigation: Document the specific Bufdir rules being enforced in the validator's source code as named constants with references to the relevant Bufdir guidelines. Review the rules with at least one coordinator representative before implementation is finalised.

Contingency: Expose a per-org configuration flag (strict_bufdir_validation: bool) in the period configuration repository so that rule enforcement can be relaxed for specific organisations without a code deployment.