Duplicate Activity Detection Service
Component Detail
Description
Compares a pending activity submission against existing activity records for the same contact across all chapters they belong to, checking for matching contact_id, date, and activity_type. Returns a match object if a potential duplicate is found so the UI layer can surface the warning dialog before finalization.
duplicate-activity-detection-service
Summaries
Duplicate activity records are a silent but significant threat to data quality — they inflate engagement metrics, distort coordinator performance reports, and erode trust in the platform when leadership notices discrepancies. This service acts as an intelligent pre-submission checkpoint, automatically comparing a new activity against all existing records for that contact across every chapter they belong to. By catching duplicates before they enter the system, it saves coordinators the effort of manual audits and corrections, and it protects the accuracy of data that informs strategic decisions about chapter performance, contact engagement, and resource allocation.
This is a high-complexity service with two dependencies — the Contact Chapter Repository and a Cross-Chapter Activity Query component — both of which must be stable before end-to-end integration testing can begin. Because this service runs at submission time, its performance characteristics directly affect the perceived responsiveness of the activity submission flow, making performance testing under realistic data volumes a required QA deliverable. The cross-chapter query scope means test data must include contacts with multiple chapter affiliations, which adds setup complexity to the test environment. Given its shared status, any interface changes will have ripple effects on the Duplicate Activity Warning Dialog and must be versioned carefully.
The service's primary entry point is checkForDuplicate(), which accepts an ActivitySubmission and returns a nullable DuplicateActivityMatch. Internally it calls getActivitiesForContactAcrossChapters() to retrieve all activities for that contact across every affiliated chapter via the Cross-Chapter Activity Query, then iterates the result set calling isDuplicateActivity() — a pure comparison function matching on contact_id, date, and activity_type. A match triggers buildDuplicateMatch() to construct the structured result consumed by the warning dialog. The service runs in both mobile and backend contexts: on mobile it acts as a pre-flight check before network submission; on backend it provides a server-side guard.
Ensure that the date comparison uses normalized UTC values to avoid timezone-related false negatives, and that activity_type comparison is case-insensitive.
Responsibilities
- Query activities for all chapters a contact belongs to
- Compare pending activity against stored activities by contact_id, date, and activity_type
- Return structured duplicate match data for warning display
- Run check at submission time before persisting the new activity
Interfaces
checkForDuplicate(ActivitySubmission pending) → Future<DuplicateActivityMatch?>
getActivitiesForContactAcrossChapters(String contactId) → Future<List<Activity>>
buildDuplicateMatch(Activity existing, ActivitySubmission pending) → DuplicateActivityMatch
isDuplicateActivity(Activity a, ActivitySubmission b) → bool
Relationships
Dependencies (2)
Components this component depends on
Related Data Entities (3)
Data entities managed by this component