Activity
Data Entity
Description
A logged interaction between a peer mentor and a contact, such as a home visit, phone call, or meeting. The central operational record of the Meander platform, feeding statistics, Bufdir reporting, and expense reimbursement.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key | PKrequiredunique |
user_id |
uuid |
Peer mentor who performed the activity | required |
contact_id |
uuid |
Contact the activity was performed with. Nullable for group/event-type activities. | - |
organization_id |
uuid |
Organization the activity belongs to for multi-tenant isolation | required |
activity_type_id |
uuid |
Type/category of activity (home visit, phone call, etc.) | required |
performed_by_user_id |
uuid |
Actual user who registered the activity — differs from user_id when coordinator uses proxy registration | required |
activity_date |
datetime |
Date and time the activity took place. Defaults to current date/time. | required |
duration_minutes |
integer |
Duration of the activity in minutes. Defaults to 30. | required |
notes |
text |
Free-text notes or dictated report content for the activity | - |
status |
enum |
Approval status of the activity | required |
is_proxy |
boolean |
True when a coordinator registered this activity on behalf of the peer mentor | required |
is_bulk |
boolean |
True when created via bulk registration | required |
location |
string |
Optional freetext location of the activity | - |
is_reimbursable |
boolean |
Whether this activity has associated expense reimbursement | required |
approved_by_user_id |
uuid |
User (coordinator/admin) who approved the activity | - |
approved_at |
datetime |
Timestamp when activity was approved | - |
rejection_reason |
text |
Reason for rejection when status is rejected | - |
duplicate_of_activity_id |
uuid |
References original activity if this is detected as a duplicate | - |
bufdir_eligible |
boolean |
Whether this activity qualifies for Bufdir reporting | required |
local_id |
string |
Client-generated UUID used to track offline-created activities before server sync assigns the canonical id | - |
synced_at |
datetime |
Timestamp when offline activity was synced to server | - |
created_at |
datetime |
Record creation timestamp | required |
updated_at |
datetime |
Record last-updated timestamp | required |
Database Indexes
idx_activities_user_id
Columns: user_id
idx_activities_organization_id
Columns: organization_id
idx_activities_contact_id
Columns: contact_id
idx_activities_activity_date
Columns: activity_date
idx_activities_status
Columns: status
idx_activities_org_user_date
Columns: organization_id, user_id, activity_date
idx_activities_org_date_bufdir
Columns: organization_id, activity_date, bufdir_eligible
idx_activities_local_id
Columns: local_id
Validation Rules
duration_positive
error
Validation failed
user_belongs_to_organization
error
Validation failed
contact_belongs_to_organization
error
Validation failed
activity_type_valid
error
Validation failed
notes_max_length
error
Validation failed
status_transition_valid
error
Validation failed
Business Rules
activity_date_not_future
Activity date cannot be set to a future date — activities record past interactions
proxy_requires_coordinator_role
Only users with Coordinator or Org Admin role may set is_proxy=true
bulk_requires_coordinator_role
Only Coordinators may create bulk activities
approval_requires_coordinator_or_admin
Only Coordinator or Org Admin may approve or reject activities
rejection_requires_reason
When setting status to rejected, rejection_reason must be provided
approved_at_set_on_approval
approved_at and approved_by_user_id are auto-set when status transitions to approved
organization_tenant_isolation
Activities are always scoped to a single organization — cross-org reads are forbidden
duplicate_detection_on_create
On activity creation, check for potential duplicates (same user_id, contact_id, activity_type_id, and activity_date within ±30 min) and flag if found
bufdir_eligibility
Activities are bufdir_eligible by default; system may mark ineligible based on org config or activity type
offline_sync_conflict_resolution
When an offline-created activity (identified by local_id) is synced, if a server-side record with the same local_id exists the conflict resolver determines winner