User
A person with an account, and the records that track what they do across the platform — the action log and the champion pipeline.
See also: course (answers, enrollments), cohort, theme (forum moderation), nudge (delivery logs).
Tables
USER
A person with an account — one row per signed-in human. The roles array gates capabilities; a user can hold any combination of student, teacher, admin, champion, superadmin. Almost everything else in the schema either belongs to, targets, or is performed by a USER.
id usr_42_maya
email maya.chen@example.com
name Maya Chen
origin signup-form
profile_img https://cdn.afh.example/u/42.jpg
roles ["student", "champion"]
created_at 2026-03-04T14:22:00Z
USER_ACTION
Append-only event log of things users do across the platform. action_type is one of enrolled, viewed_module, started_module, completed_module, answered_question, posted_thread, posted_reply, completed_course, unenrolled. target_type + target_id form a polymorphic pointer at what they acted on (module, content_block, question, course, cohort, forum, thread, post); metadata JSONB carries action-specific detail. Powers analytics, progress tracking, and event-triggered nudges (see nudge).
The three source-tracking columns make ingestion idempotent — so the same upstream event recorded twice (a webhook retry, a replayed Segment event) only lands once:
source_system— where the event came from:webhook,app,stripe,segment,manual,cron_worker.source_event_id— the upstream event's own identifier, when it has one.idempotency_key— a deterministic key the application computes to prevent recording the same source event twice.
Two partial unique indexes enforce this, scoped so they only apply when the relevant columns are non-null (NULLs stay unconstrained, since not every action has an upstream source):
CREATE UNIQUE INDEX user_action_source_event_unique
ON user_action (source_system, source_event_id)
WHERE source_system IS NOT NULL
AND source_event_id IS NOT NULL;
CREATE UNIQUE INDEX user_action_idempotency_key_unique
ON user_action (idempotency_key)
WHERE idempotency_key IS NOT NULL;
id act_2026_03_15_001
user_id usr_42_maya
enrollment_id enr_01_april_maya
action_type viewed_module
target_type module
target_id mod_01_day1
metadata {"duration_sec": 92, "device": "ios"}
source_system segment
source_event_id evt_seg_8f2a91
idempotency_key user_action:segment:evt_seg_8f2a91
occurred_at 2026-03-15T08:14:00Z
CHAMPION
Tracks the champion pipeline — users being considered as, or actively serving as, community champions. stage walks candidate → selected → champion → alumni; cohort_id is nullable, where NULL means an ongoing/global champion not tied to a specific cohort run.
id ch_07_maya
user_id usr_42_maya
cohort_id null
stage champion
notes Strong forum presence; volunteered to mentor.
selected_at 2026-04-01T10:00:00Z
became_champion_at 2026-04-20T10:00:00Z