derived PK: id 15 required 1 unique

Description

Derived entity storing pre-computed yearly impact summaries for peer mentors, powering the Spotify Wrapped-style year-in-review experience. Each record aggregates a user's activities, contacts supported, events attended, hours contributed, and milestones achieved over a calendar year into a structured dataset optimized for animated slide-based presentation and social sharing.

26
Attributes
4
Indexes
7
Validation Rules
13
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Unique identifier for the annual summary record
PKrequiredunique
user_id uuid Foreign key referencing the peer mentor or coordinator whose year is summarized
required
year integer Calendar year this summary covers (e.g. 2025)
required
organization_id uuid Organization context for tenant-scoped queries and org-specific multipliers
required
total_activities integer Total number of logged activities during the year
required
total_hours decimal Cumulative hours spent on peer mentor activities
required
total_contacts_supported integer Distinct contacts the peer mentor interacted with during the year
required
total_events_attended integer Number of events the user registered for and attended
required
total_travel_km decimal Total kilometres travelled for peer mentor activities
-
activity_breakdown json Activity counts grouped by type (e.g. home_visit, phone_call, group_session) for chart rendering
required
monthly_distribution json Array of 12 monthly activity/hour totals for trend line visualization
required
top_contacts json Array of most-frequently supported contact IDs with interaction counts (anonymized names for sharing)
-
achievements_earned json Array of achievement/badge IDs earned during the year with award dates
-
milestones json Key milestones reached during the year (e.g. first_activity, 100th_hour, first_event_organized)
-
impact_metrics json Calculated impact values using org-specific multipliers: monetary equivalent, social hours value, cost savings
-
busiest_month integer Month number (1-12) with highest activity count for highlight slide
-
longest_streak_days integer Longest consecutive-day streak of logged activities
-
slide_data json Pre-rendered slide configuration array for the Wrapped animation sequence, including titles, stats, and animation keys
-
share_image_url text URL to a pre-rendered shareable summary image stored in cloud storage, with contact-identifiable info stripped
-
status enum Generation lifecycle status of the summary
required
data_sufficiency boolean Whether the user had enough activity data to generate a meaningful summary (minimum threshold met)
required
generated_at datetime Timestamp when the summary aggregation was last computed
-
viewed_at datetime Timestamp when the user first viewed their Wrapped summary
-
shared_count integer Number of times the user shared this summary externally
required
created_at datetime Record creation timestamp
required
updated_at datetime Last modification timestamp
required

Database Indexes

idx_annual_summaries_user_year
btree unique

Columns: user_id, year

idx_annual_summaries_organization_year
btree

Columns: organization_id, year

idx_annual_summaries_status
btree

Columns: status

idx_annual_summaries_year
btree

Columns: year

Validation Rules

valid_year_range error

Validation failed

valid_user_reference error

Validation failed

non_negative_metrics error

Validation failed

valid_monthly_distribution_format error

Validation failed

valid_status_transitions error

Validation failed

busiest_month_within_range error

Validation failed

generated_at_required_when_ready error

Validation failed

Business Rules

one_summary_per_user_per_year
on_create

Each user may have at most one annual summary per calendar year, enforced by the unique index on (user_id, year)

data_sufficiency_threshold
on_create

A summary is only marked as ready if the user logged at least 5 activities and 3 hours during the year; otherwise data_sufficiency is false and the Wrapped experience shows a encouragement message instead

year_end_generation_window
on_create

Summaries are generated in a batch job during December 15 – January 15 window for the preceding year; on-demand regeneration is allowed after that window

strip_pii_from_shareable_content
on_update

Shared summary images and exported data must not contain contact names, addresses, or other personally identifiable information; only aggregate counts and anonymized statistics are permitted

tenant_isolation
always

Users may only view their own annual summaries; coordinators may view summaries of peer mentors within their local association scope for team-level reporting

immutable_after_share
on_update

Once a summary has been shared externally (shared_count > 0), the core metrics (totals, breakdown) should not be recalculated to maintain consistency with what was shared

Enforced by: Annual Summary Service
organization_scoped_impact_multipliers
on_create

Impact metrics must be computed using the organization-specific hourly rate and multiplier values from organization_settings, falling back to platform defaults if none are configured

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
by_date
Retention
Permanent Storage