high priority medium complexity backend pending backend specialist Tier 2

Acceptance Criteria

DuplicateActivityWarning exposes chapterName (String), conflictingDate (DateTime), activityTypeLabel (String), dateDeltaDays (int), and conflictingActivityId (String) as typed fields
chapterName contains the human-readable chapter name, not the chapter ID
activityTypeLabel is the localized display string for the activity type (e.g., 'Home visit'), not the raw enum/code value
dateDeltaDays is the signed integer difference (positive = conflicting is after pending, negative = before), allowing the UI to say 'registered 1 day earlier'
conflictingActivityId is the stable database ID of the conflicting record, suitable for deep-linking
DuplicateActivityWarning is immutable (all fields final, const constructor where possible)
The detection service populates all fields from the StoredActivity and Chapter data already retrieved by CrossChapterActivityQuery — no additional async calls are made to build the warning
If the chapter name cannot be resolved, the field falls back to the chapter ID string rather than throwing

Technical Requirements

frameworks
Flutter
BLoC
apis
CrossChapterActivityQuery (internal — must already return chapter name alongside activities)
data models
DuplicateActivityWarning
StoredActivity
Chapter
ActivityType
performance requirements
Warning object construction is synchronous and adds zero additional async calls beyond what task-006 already performs
security requirements
chapterName must not include any contact PII
conflictingActivityId must be an opaque ID, not a human-readable identifier containing PII
ui components
DuplicateActivityWarningDialog (consumer of this model — no changes to UI in this task)

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Ensure CrossChapterActivityQuery's return type already includes chapter name alongside activity data — if not, update its query or result model as part of this task. Keep DuplicateActivityWarning as a plain Dart data class (not an entity/aggregate); it is a read model purely for UI consumption. Use an ActivityTypeLocalization helper or a simple const map to convert raw activity_type codes to display labels; do not embed localization logic inside the warning class itself. Review the dialog widget spec before finalising field names to ensure a 1:1 mapping between model fields and dialog template variables.

Testing Requirements

Unit tests in flutter_test: assert that each field on DuplicateActivityWarning is correctly populated when DuplicateActivityDetectionService returns a warning. Test the fallback behaviour when chapter name is missing. Test that dateDeltaDays sign is correct for both earlier and later conflicts. Reuse the mocks from task-006 tests; extend them to return chapter metadata.

No new integration tests required.

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.