Activity
Data Entity
Description
A logged interaction between a peer mentor and a contact — such as a home visit, phone call, group meeting, or event attendance. Activities are the primary unit of work tracked in Meander and form the basis for Bufdir reporting, expense reimbursements, and statistics.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key, generated server-side | PKrequiredunique |
organization_id |
uuid |
Foreign key to organizations — enforces multi-tenant data isolation | required |
user_id |
uuid |
Foreign key to the peer mentor who performed (or is credited with) the activity. For proxy registrations this is the peer mentor, not the coordinator. | required |
registered_by_user_id |
uuid |
Foreign key to the user who created the record. Equal to user_id for self-registered activities; set to coordinator's user_id for proxy/bulk registrations. | required |
contact_id |
uuid |
Foreign key to the contact the activity was performed with. Nullable for group/organizational activities where no single contact applies. | - |
activity_type_id |
uuid |
Foreign key to activity_types — classifies the kind of interaction (home visit, phone call, group meeting, etc.) | required |
activity_date |
datetime |
Date and time the activity took place. Defaults to current date at time of registration. Stored in UTC. | required |
duration_minutes |
integer |
Duration of the activity in minutes. Defaults to 30 when not explicitly set by the user. | required |
summary |
text |
Free-text summary or notes describing what happened during the activity. Supports speech-to-text input. Marked as a sensitive field for screen reader warning. | - |
location |
string |
Optional location description (e.g. 'Home visit', 'Phone call', 'Community centre'). Not a structured geocoordinate. | - |
status |
enum |
Workflow status of the activity record | required |
is_proxy |
boolean |
True when the activity was registered by a coordinator on behalf of a peer mentor | required |
is_bulk |
boolean |
True when this record was created as part of a bulk registration batch | required |
bulk_batch_id |
uuid |
References the batch_reference_repository batch ID when is_bulk = true. Null for individual registrations. | - |
requires_reimbursement |
boolean |
Indicates whether any travel expense claim is attached to this activity. 60-70% of activities have no reimbursement claim per HLF data. | required |
bufdir_reportable |
boolean |
Whether this activity should be included in Bufdir reports. Certain activity types or statuses may be excluded. | required |
reporting_period_id |
uuid |
Optional link to a Bufdir reporting period. Set when the activity is included in a finalized Bufdir report. | - |
flag_reason |
text |
Admin-entered reason when the activity has status = 'flagged'. Null otherwise. | - |
rejection_reason |
text |
Coordinator or admin-entered reason when the activity is rejected during approval workflow. | - |
approved_by_user_id |
uuid |
Foreign key to the user (coordinator or admin) who approved or rejected this activity. Null until reviewed. | - |
approved_at |
datetime |
Timestamp when the activity was approved or rejected. Null until reviewed. | - |
metadata |
json |
Flexible JSON bag for activity-type-specific fields, calendar event references, or speech-to-text session metadata. Schema varies by activity_type. | - |
created_at |
datetime |
Record creation timestamp in UTC | required |
updated_at |
datetime |
Record last-modified timestamp in UTC | required |
deleted_at |
datetime |
Soft-delete timestamp. NULL means active record. Activities are never hard-deleted to preserve Bufdir audit trail. | - |
Database Indexes
idx_activities_org_date
Columns: organization_id, activity_date
idx_activities_user_date
Columns: user_id, activity_date
idx_activities_contact
Columns: contact_id
idx_activities_status
Columns: organization_id, status
idx_activities_reporting_period
Columns: reporting_period_id
idx_activities_bulk_batch
Columns: bulk_batch_id
idx_activities_registered_by
Columns: registered_by_user_id
idx_activities_deleted_at
Columns: deleted_at
Validation Rules
activity_date_not_future
error
Validation failed
duration_range
error
Validation failed
activity_type_belongs_to_org
error
Validation failed
contact_same_org
error
Validation failed
user_same_org
error
Validation failed
summary_sensitive_field_warning
warning
Validation failed
status_transition_valid
error
Validation failed
offline_conflict_resolution
warning
Validation failed
Business Rules
tenant_isolation
Every activity query MUST be scoped by organization_id. Cross-organization data access is prohibited even for Global Admins reading operational data.
soft_delete_only
Activities must never be hard-deleted. Set deleted_at to preserve Bufdir audit trail and historical statistics integrity.
proxy_registration_coordinator_only
is_proxy = true may only be set by users with Coordinator or Org Admin role. registered_by_user_id must differ from user_id in this case.
approval_workflow
Activities above organization-configured thresholds (e.g. with reimbursement or from proxy registration) transition to 'submitted' and require coordinator approval before becoming 'approved'. Activities under threshold auto-approve.
bufdir_locked_after_export
Once an activity is included in a finalized Bufdir report (reporting_period_id is set and period is closed), the record becomes immutable. Updates and deletes are blocked.
duplicate_detection
When a new activity is created, check for duplicate records with same user_id + contact_id + activity_date + activity_type_id within the same organization. Surface a warning to the registering user. Required by NHF to prevent coordinator double-reporting.
default_values_applied
If activity_date is not supplied, default to current date. If duration_minutes is not supplied, default to 30. These defaults are managed by DefaultValuesManager and configurable per organization.
bulk_batch_consistency
When is_bulk = true, bulk_batch_id must be present and reference a valid batch. All activities in a batch share the same activity_type_id and activity_date.
reimbursement_sync
When the last expense linked to this activity is deleted, requires_reimbursement must be set to false. When the first expense is linked, it must be set to true.
flag_requires_reason
Setting status = 'flagged' requires a non-empty flag_reason. Performed by coordinator or admin only.