critical priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

PendingActivity is an immutable value object with at minimum: contactId (String), activityType (String or enum), scheduledDate (DateTime), coordinatorId (String), and chapterId (String) fields
DuplicateActivityWarning is an immutable value object with: matchingActivityId (String), dateDelta (Duration), activityType (String or enum), and matchingCoordinatorId (String) fields
AbstractDuplicateActivityDetectionService declares checkForDuplicates(PendingActivity pending) → Future<DuplicateActivityWarning?> where null return means no duplicate detected
The interface lives in the domain layer with zero infrastructure imports
A Dart doc comment on the interface explains the duplicate detection heuristic (same contact, same activity type, date within configurable threshold)
A named constant kDuplicateDetectionWindowDays is defined (default 7) representing the look-back window
Unit tests for PendingActivity and DuplicateActivityWarning equality and toString() compile and pass
The activityType field uses the same enumeration or string constants already established in the broader activity domain to avoid type drift

Technical Requirements

frameworks
Flutter
data models
PendingActivity
DuplicateActivityWarning
Activity
performance requirements
Value object construction must be O(1) — no database or async calls in constructors
security requirements
DuplicateActivityWarning must not expose personal details of the matched coordinator beyond their ID

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

The duplicate detection use case originates from NHF's requirement to prevent two coordinators from registering the same activity for the same contact. The warning is non-blocking — it informs the user but does not prevent saving. Design the interface to return Future (nullable) rather than a result type, since the absence of a duplicate is the normal/happy path and wrapping it in a result type adds unnecessary ceremony. The date delta field on the warning is important for UI display: 'A similar activity was registered 2 days ago' is more actionable than a raw boolean.

Reuse the existing activityType enumeration from the core activity domain — do not introduce a parallel enum. Place all files under lib/domain/duplicate_detection/.

Testing Requirements

Unit tests (flutter_test) for: (1) PendingActivity equality by field values; (2) DuplicateActivityWarning correctly computes or stores dateDelta; (3) null return from a stub implementation of checkForDuplicates represents no-duplicate correctly. All tests run without network or database dependencies. Target 100% line coverage on domain files introduced in this task.

Component
Duplicate Activity Detection Service
service high
Epic Risks (2)
medium impact medium prob scope

The ±1 day duplicate detection tolerance is specified in the acceptance criteria but timezone handling is not defined. A coordinator in UTC+2 submitting at 23:00 and another in UTC+0 submitting at 01:00 the next calendar day could trigger or miss a duplicate depending on which timezone the comparison uses.

Mitigation & Contingency

Mitigation: Define and document the authoritative timezone for all date comparisons (UTC stored in Supabase, all comparisons performed in UTC). Add timezone boundary unit tests covering the ambiguous ±1 day edges.

Contingency: If false positives or false negatives are reported in production, provide a coordinator-visible audit trail of duplicate detections so erroneous flags can be investigated and cleared manually.

medium impact medium prob technical

The Duplicate Activity Detection Service performs a cross-chapter join query synchronously during the activity submission flow. On slow mobile connections this could cause a perceptible stall on the submission confirmation step, degrading user experience.

Mitigation & Contingency

Mitigation: Pre-fetch the cross-chapter activity dataset for the selected contact immediately when the contact is selected in the activity wizard (not only at submit time), storing the result in the state manager for instant comparison at submission.

Contingency: If latency is still unacceptable, implement a loading indicator on the submit action and add a configurable server-side timeout with graceful degradation: if the check times out, allow submission with a logged 'check skipped' audit entry rather than blocking the user.