Activity
Data Entity
Description
A logged interaction between a peer mentor and a contact — home visits, phone calls, group meetings, or any other peer mentoring engagement. Activities are the core operational unit of the platform: they feed Bufdir compliance reports, drive reimbursement flows, power statistics dashboards, and form the audit trail that organizations submit to government funders. Activities can be created directly by peer mentors, registered by coordinators on behalf of mentors (proxy), or created in bulk for recurring group events.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key. Globally unique identifier for the activity record. | PKrequiredunique |
organization_id |
uuid |
Foreign key to organizations. Enforces multi-tenant data isolation — every query must scope to this column. | required |
local_association_id |
uuid |
Foreign key to local_associations. Scopes the activity to the local branch within an organization for coordinator-level reporting and access control. | - |
user_id |
uuid |
Foreign key to users. The peer mentor who performed (or is credited with) the activity. In proxy registration, this is the mentor being reported for, not the submitting coordinator. | required |
contact_id |
uuid |
Foreign key to contacts. The contact person who received support during this activity. May be null for group activities where no single contact is applicable. | - |
activity_type |
enum |
Categorizes the type of peer mentor interaction. Used for Bufdir field mapping and mutual-exclusivity validation. | required |
date |
datetime |
The date and time when the activity took place. Defaults to the current date on the client. Used for calendar sync, Bufdir period filtering, and statistics aggregation. | required |
duration_minutes |
integer |
Duration of the activity in minutes. Default is 30 minutes. Used for hours-based statistics, coordinator team reports, and Bufdir reporting. | required |
summary |
text |
Free-text description of the activity. Optional but encouraged. Supports speech-to-text input on mobile. Not included in Bufdir exports directly but retained for internal audit. | - |
status |
enum |
Lifecycle state of the activity through the review and approval workflow. | required |
is_proxy |
boolean |
True if the activity was registered by a coordinator on behalf of a peer mentor. Stored for audit trail and Bufdir attribution. | required |
proxy_user_id |
uuid |
Foreign key to users. The coordinator who submitted the activity on behalf of the peer mentor. Non-null only when is_proxy = true. | - |
is_bulk |
boolean |
True if this activity was created as part of a bulk registration operation. Links to bulk_operation_id for batch traceability. | required |
bulk_operation_id |
uuid |
Groups all activity records created in a single bulk registration transaction. Non-null only when is_bulk = true. Supports rollback and audit. | - |
location |
string |
Optional free-text location description for the activity (e.g., 'Mentor's home', 'Community center'). Used in formalized report structures. | - |
is_flagged |
boolean |
True if this activity has been flagged for review as a suspected duplicate or non-compliant entry. Separate from status to allow flagging of already-approved activities. | required |
flag_reason |
text |
Human-readable explanation for why the activity was flagged. Set by coordinator or by the automatic duplicate detection service. | - |
flagged_by_user_id |
uuid |
Foreign key to users. The coordinator or system process that raised the flag. Null for system-initiated flags only if flagging logic stores 'system' sentinel. | - |
rejection_reason |
text |
Reason provided by the reviewer when status is set to 'rejected'. Required for all rejection decisions. | - |
reviewed_by_user_id |
uuid |
Foreign key to users. The coordinator or org admin who last performed an approval or rejection action. | - |
reviewed_at |
datetime |
Timestamp of the most recent review action (approve/reject). Null if no review has occurred. | - |
version |
integer |
Optimistic locking version counter. Incremented on every update. Used by approval service to prevent concurrent modification conflicts. | required |
calendar_event_id |
string |
External calendar event ID from device or Google Calendar. Populated by Calendar Sync Service when an activity is pushed to an external calendar. Enables bidirectional sync. | - |
metadata |
json |
Extensible JSON blob for organization-specific fields, custom activity attributes, or future Bufdir format extensions without schema migrations. | - |
created_at |
datetime |
Timestamp of record creation. Set automatically on insert. Used for feed ordering, statistics bucketing, and audit logs. | required |
updated_at |
datetime |
Timestamp of the most recent record update. Auto-maintained by trigger or ORM. Used for sync conflict detection. | required |
Database Indexes
idx_activity_org_created
Columns: organization_id, created_at
idx_activity_user_date
Columns: user_id, date
idx_activity_local_assoc_created
Columns: local_association_id, created_at
idx_activity_contact
Columns: contact_id
idx_activity_status
Columns: status
idx_activity_org_status
Columns: organization_id, status
idx_activity_bulk_operation
Columns: bulk_operation_id
idx_activity_flagged
Columns: organization_id, is_flagged
idx_activity_date_type
Columns: organization_id, date, activity_type
Validation Rules
required_fields_present
error
Validation failed
date_not_in_future
error
Validation failed
duration_positive_nonzero
error
Validation failed
proxy_fields_consistency
error
Validation failed
bulk_fields_consistency
error
Validation failed
rejection_reason_required
error
Validation failed
flag_reason_required
error
Validation failed
org_id_immutable
error
Validation failed
activity_type_valid_enum
error
Validation failed
summary_length_limit
error
Validation failed
Business Rules
tenant_isolation
Every activity record must be scoped to an organization_id. All queries — reads, aggregations, exports — must include a WHERE organization_id = :orgId clause. Cross-tenant access is never permitted, even for coordinators.
proxy_requires_coordinator_role
An activity with is_proxy = true must have proxy_user_id set to a user who holds the Coordinator role within the same organization. Peer Mentors cannot register activities for other users.
proxy_scope_restriction
A coordinator can only register proxy activities for peer mentors within their own local association(s). Cross-association proxy registration is forbidden.
bulk_atomicity
All activities created within a single bulk_operation_id must be inserted atomically. If any single insert fails, the entire batch is rolled back. No partial bulk registrations are permitted.
status_transition_guard
Activity status transitions must follow the defined workflow: draft → pending_review → approved/rejected. Approved activities cannot be moved back to pending_review without creating a correction record. Only Coordinators and Org Admins can trigger status changes.
optimistic_locking
Updates to an activity record must include the current version value. If the version in the update request does not match the database version, the update is rejected with a conflict error to prevent concurrent approval race conditions.
bufdir_approved_only
Only activities with status = 'approved' are included in Bufdir report generation. Draft, pending, rejected, and flagged activities are excluded from all compliance exports.
duplicate_detection
When a new activity is created, the system checks for existing activities with the same (user_id, contact_id, date, activity_type) within a configurable deduplication window per organization. Suspected duplicates are auto-flagged with is_flagged = true.
soft_delete_only
Activities must never be hard-deleted. If deletion is required, the status is set to 'rejected' with a system rejection reason, preserving the full audit trail for compliance purposes.
assignment_threshold_trigger
For organizations using assignment-based honorarium tiers (Blindeforbundet), each activity completion event must be forwarded to the Threshold Tracking Service to evaluate whether honorarium thresholds have been crossed.
offline_queue_precedence
Activities created while offline are persisted to the local SQLite sync queue. When connectivity is restored, they are submitted to the REST API in the order they were created, preserving chronological integrity.
calendar_sync_push
When an activity is created or updated and Calendar Sync is enabled for the user, the activity is pushed to the linked device or Google Calendar. The external event ID is stored in calendar_event_id.