Annual Summary
Data Entity
Description
A pre-computed annual impact summary for a peer mentor covering the prior calendar year — total hours, contacts supported, activity count, streaks, and organizational percentile rankings. Powers the 'Peer Mentor Wrapped' feature. Generated by a batch job in January each year and supports shareable image/PDF export.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key — unique identifier for the annual summary record | PKrequiredunique |
user_id |
uuid |
Foreign key referencing the users table — the peer mentor this summary belongs to | required |
peer_mentor_id |
uuid |
Foreign key referencing the peer_mentors table — enables fast lookup without joining through users for the Wrapped feature | required |
organization_id |
uuid |
Foreign key referencing the organizations table — scopes percentile calculations to the correct organization | required |
local_association_id |
uuid |
Foreign key referencing the local_associations table — scopes the summary to the peer mentor's active local association at year end | - |
year |
integer |
The calendar year this summary covers (e.g. 2024). Always the prior calendar year relative to generation date. | required |
total_activities |
integer |
Total number of approved activity records registered by the peer mentor during the calendar year | required |
total_hours |
decimal |
Sum of activity durations in hours for the full calendar year, rounded to two decimal places | required |
contacts_supported |
integer |
Count of distinct contacts the peer mentor had at least one approved activity with during the calendar year | required |
activity_streaks |
json |
Streak metrics as a JSON object: { longest_streak_days, longest_streak_start, longest_streak_end, current_streak_days, total_active_weeks } | - |
percentile_rank |
decimal |
Peer mentor's percentile rank (0.0–100.0) among all active peer mentors in their organization for total_hours during the year. NULL if fewer than 10 peers exist for statistical significance. | - |
activity_type_breakdown |
json |
Breakdown of activity counts and hours by activity type: [{ activity_type_id, activity_type_name, count, hours }] | - |
payload_json |
json |
Full structured slide payload for the Wrapped presentation layer. Contains ordered slide definitions with metric keys, display values, animation hints, and contextual copy. Consumed directly by Annual Summary Service to build slide sequences for Annual Summary Screen. | - |
generation_status |
enum |
Tracks the status of the batch aggregation for this record | required |
generation_error |
text |
Error message if generation_status is 'failed', for diagnostics and retry logic | - |
viewed_at |
datetime |
Timestamp of the peer mentor's first view of their annual summary. NULL until first opened. Set once and never updated again. | - |
share_image_key |
string |
Object storage key for the generated shareable PNG card. NULL until share is first triggered. Used by Summary Share Asset Service to generate signed GET URLs. | - |
share_pdf_key |
string |
Object storage key for the generated shareable PDF export. NULL until PDF export is first triggered. | - |
created_at |
datetime |
Timestamp when the record was first created by the batch aggregation job | required |
updated_at |
datetime |
Timestamp of the last modification — updated on upsert reruns, viewed_at writes, and share asset key updates | required |
Database Indexes
idx_annual_summary_user_year
Columns: user_id, year
idx_annual_summary_peer_mentor_year
Columns: peer_mentor_id, year
idx_annual_summary_year_org
Columns: year, organization_id
idx_annual_summary_generation_status
Columns: generation_status
idx_annual_summary_created_at
Columns: created_at
Validation Rules
year_range_valid
error
Validation failed
metrics_non_negative
error
Validation failed
percentile_rank_bounds
error
Validation failed
user_id_peer_mentor_relationship
error
Validation failed
activity_streaks_schema
warning
Validation failed
payload_json_slide_schema
warning
Validation failed
share_asset_key_format
error
Validation failed
generation_status_transition
error
Validation failed
Business Rules
one_summary_per_user_per_year
Each peer mentor may have at most one annual summary record per calendar year. The batch job uses UPSERT semantics — rerunning aggregation for a year overwrites the existing record rather than creating a duplicate.
peer_mentor_only
Annual summaries are generated exclusively for users who have an active peer_mentors profile. Users with only Coordinator, Organization Administrator, or Global Administrator roles do not receive annual summaries.
prior_year_only
The batch aggregation job only generates summaries for the prior completed calendar year. Summaries for the current or future year are never created. The year field must be less than the current calendar year.
approved_activities_only
Only activities with approval_status = 'approved' are counted toward total_activities, total_hours, and contacts_supported. Pending or flagged activities are excluded to ensure Bufdir-compliant accuracy.
percentile_minimum_cohort
percentile_rank is only computed when the organization has at least 10 active peer mentors for the given year. Below this threshold, the field is set to NULL to avoid misleading comparisons from statistically insignificant cohorts.
viewed_at_immutable_after_set
Once viewed_at is written on the peer mentor's first view, it must never be overwritten. Subsequent views of the summary do not update the timestamp.
payload_immutable_after_complete
Once generation_status transitions to 'complete', the payload_json and all aggregated metric fields (total_activities, total_hours, contacts_supported, activity_streaks, percentile_rank) become read-only except during an explicit admin-triggered recomputation. This preserves the historical integrity of the Wrapped experience.
share_assets_privacy_masking
Generated share images and PDFs (share_image_key, share_pdf_key) must exclude all personally identifiable contact information. Only aggregate metrics (hours, activity counts, percentile) are rendered in shareable assets. The Summary Share Asset Service enforces this before uploading to object storage.
january_generation_schedule
The Annual Summary Scheduler triggers the aggregation job annually in January via cron. If the job fails, automatic retry with exponential backoff is applied up to 3 times before alerting. Manual re-trigger is supported via admin API.
multi_association_deduplication
For NHF peer mentors who belong to multiple local associations (up to 5), activities are attributed to the local_association_id recorded on each activity record. The summary aggregates across all associations but the percentile_rank is computed within the peer mentor's primary organization.
CRUD Operations
Storage Configuration
Entity Relationships
A peer mentor profile links to its annual summaries enabling quick lookup for the Wrapped feature
A user has one annual summary per calendar year computed by the batch aggregation job