Ubiquitous Language
A comprehensive domain dictionary for Objectuve. Every term maps to something concrete in the codebase. When discussing features, writing code, or designing APIs, use these terms consistently.
How to use this document: Terms are grouped by bounded context for scanning. Each entry includes a definition, the context it belongs to, and the code locations where it lives. The Quick Reference table at the bottom provides a flat index.
Goal Tracking (Core Domain)
Check-in
A single daily completion record for a habit. Creates a HabitCompletion record dated to the completion day. Idempotent — checking in twice on the same date returns the existing record. Awards 25 XP.
Code: CheckInHabit interaction, HabitCompletion model, Goal#checked_in_today?
Collage
A visual progress collage generated from media attached to a goal's events. One per goal.
Code: GoalCollage model, Goal#collage
Completion Rate
The percentage of expected habit check-ins that were actually completed over a period. Formula: (actual_completions / expected_completions) * 100, capped at 100%.
Code: Goal#completion_rate(days), HabitCompletion.actual_completions scope
Freeze Token
A consumable item that prevents streak loss for one missed day. Earned automatically at every 7-day streak milestone. Tracked per goal as streak_freezes_available and streak_freezes_used.
Code: UseStreakFreeze interaction, Goal#streak_freezes_available, Goal#update_habit_streak!
Goal
A user's objective. Can be a one-time target (with target_date) or a recurring habit (with recurrence_type). Supports nesting via milestones. Progress is tracked through immutable goal events. Can be private or public, and optionally shared into communities. Aggregate root.
Code: Goal model (< PublicRecord), AddGoal interaction, UpdateGoal interaction
Goal Category
A broad classification for goals. Examples: fitness, learning, personal development. Used to group goals and associate communities. Reference data — rarely changes.
Code: GoalCategory model, Goal.goal_category_id, Community.goal_category_id
Goal Event
An immutable progress log entry on a goal. Created automatically on goal creation and completion, and manually when users log updates or check in on habits. Can have encouragements, reactions, comments, and media attached. Aggregate root.
Code: GoalEvent model, Goal#events, AddGoalEvent interaction, UpdateGoalEvent interaction
Goal Media
An image attached to a goal event. Uses ActiveStorage for file handling. Supports soft deletion.
Code: GoalMedia model, GoalEvent#media
Goal Type (Kind)
A classification for the approach to achieving a goal. Examples: habit, milestone, quantity-based. Aliased as kind in code. Reference data with display_number for ordering.
Code: GoalType model, Goal#kind (alias for goal_type), GoalType#display_number
Habit
A goal with a recurrence schedule. Not a separate model — it's a Goal where recurrence_type is set. Recurrence types: daily, weekly, custom_days, interval. Tracked via HabitCompletion records.
Code: Goal#habit?, Goal.habits scope, recurrence_type field
Habit Completion
A dated record of a habit check-in. One per goal per date (unique constraint). Tracks whether a streak freeze was used. Scoped queries: for_period(start, end), recent(days), actual_completions (excludes freeze-covered days).
Code: HabitCompletion model, Goal#habit_completions
Milestone
A sub-goal nested under a parent goal. Implemented as a Goal subclass (Milestone < Goal) linked via parent_goal_id (references the parent's public_id). Inherits visibility from parent. Has its own events and completion tracking.
Code: Milestone model, Goal#milestones association
Progress Data
Grouped goal events by period (daily, weekly, monthly) with computed pace, averages, and streak data. Read-only projection for analytics charts.
Code: CalculateGoalProgress interaction (query service), GOAL_PROGRESS_DATA_QUERY
Recurrence Schedule
The configuration determining when a habit is "due." Combines recurrence_type (daily/weekly/custom_days/interval), recurrence_days (array of day abbreviations), and recurrence_interval (days between check-ins). Currently stored as raw fields on Goal — candidate for extraction as a value object.
Code: Goal.recurrence_type, Goal.recurrence_days, Goal.recurrence_interval, Goal#due_today?
Streak (Habit)
Consecutive completed check-ins for a specific habit. Calculated backward from today/yesterday through HabitCompletion dates. Stored on the goal as habit_streak (current) and longest_habit_streak (all-time best). Recalculated on every check-in and daily via ProcessHabitStreaksJob.
Code: Goal#habit_streak, Goal#update_habit_streak!, Goal#calculate_streak_from_dates
Social & Community (Accountability)
Active Accountability Partnership
The rule for "are these two users active accountability partners?" — an Ally relationship where status: 'accepted' and accountability_partner: true. Previously reimplemented independently at 9 call sites across 3 predicate shapes (pair-scoped, self-scoped, and batch/unscoped); now has exactly one owning home on UserAlly. This is the only sanctioned way to express the check — do not re-spell accepted.where(accountability_partner: true) (or the reversed-direction OR) at a new call site; call one of the three scopes below instead.
Code: UserAlly.active_partnership_between(a, b) — pair-scoped, "are A and B active partners?" (.exists?/.first at the call site, e.g. goal_queries.rb#partner_can_view?). UserAlly.active_partnerships_for(u) — self-scoped, "all of U's active partnerships" (e.g. social/accept_partner_request.rb). UserAlly.with_active_partnership — batch/unscoped, "all active partnerships, no pair or user filter" (e.g. Social::GeneratePartnerMissedDayAlertsJob, which iterates every active partnership to dispatch missed-day alerts). The pair- and self-scoped forms are both defined in terms of this batch form.
Ally
A bidirectional peer relationship between two users for mutual accountability. Allyships have a status lifecycle: pending -> accepted (or blocked). Accepted allies see each other's public goal activity in their unified feed.
Statuses: pending, accepted, blocked
Code: UserAlly model, User#allies, User#initiated_allyships, User#received_allyships
Community
An interest-based group where users share goals and hold each other accountable. Bound to a GoalCategory. Has members with roles, posts, events, and a computed health score. Aggregate root.
Code: Community model, CreateCommunity interaction
Community Badge
A platform-awarded distinction for a community (not a user badge). Computed from community metrics.
Badges: verified, featured, topActive (health >= 80), club1k (1000+ members), wins500 (500+ completed goals), earlySupporter
Code: Community#badges method
Community Event
A scheduled event within a community. Has a title, date, and attendees.
Code: CommunityEvent model, EventAttendee model, CommunityEvent#attendee_count
Community Feed Item
An activity stream entry within a community. Records member joins, goal additions, completions, and updates. Has pre-defined text templates.
Item types (via templates): join, completed_goal, goal_update, add_goal_to_community
Code: CommunityFeedItem model, class methods: add_join_feed_item, add_completed_goal_feed_item, add_goal_update_feed_item, add_goal_to_community_feed_item
Community Follow
A notification subscription to a community without joining as a member. Distinct from membership — followers receive updates but are not listed as members and cannot post.
Code: CommunityFollow model, FollowCommunity interaction, UnfollowCommunity interaction
Community Goal
A join record sharing a user's goal into a community. Only public goals can be shared. Creates a community feed item when added.
Code: CommunityGoal model, AddGoalToCommunity interaction
Community Member
A user's membership in a community with a role. Tracks join date and contribution points.
Roles: admin, moderator, member
Code: CommunityMember model, JoinCommunity interaction, LeaveCommunity interaction
Community Media
An image attached to a community feed item. Uses ActiveStorage.
Code: CommunityMedia model, CommunityFeedItem#media
Community Post
A discussion thread within a community. Has a type, moderation status, and can receive comments and reactions. Aggregate root.
Post types: discussion, achievement, milestone
Moderation statuses: approved (0), pending_review (1), rejected (2)
Code: CommunityPost model, CreateCommunityPost interaction
Community Suggestion
A user-submitted recommendation for a new community. Optionally linked to a goal type and category.
Code: CommunitySuggestion model, AddCommunitySuggestion interaction
Encouragement
A lightweight social gesture on a goal event — essentially a "like." Implemented via soft deletion: toggling an encouragement creates or restores/deletes a GoalEventEncouragement record. Triggers a notification and feed item for the goal owner.
Code: GoalEventEncouragement model, ToggleGoalEventEncouragement interaction
Goal Encouragement
A goal-level encouragement (distinct from event-level GoalEventEncouragement). Has an optional comment text. Belongs to a goal and optionally a user.
Code: GoalEncouragement model
Event Comment (Goal)
A text reply on a goal event. Triggers a notification to the goal owner. Subject to content moderation.
Code: GoalEventComment model, AddGoalEventComment interaction
Feed Item (User)
An entry in a user's personal activity stream. Created by the system when noteworthy things happen. Has a kind enum and details JSONB for flexible context.
Kinds: encouragement (0), badge (1), general (2), comment (3), follow_update (4), reaction (5)
Code: UserFeedItem model, class methods: add_encouragement_feed_item, add_reaction_feed_item, add_comment_feed_item, add_badge_feed_item, add_goal_event_feed_item, add_follow_feed_item
Feed Kind
A reference/enum model categorizing feed item types by name. Used by CommunityFeedItem.
Code: FeedKind model
Follow (Goal)
Subscribing to updates on another user's public goal. Creates a UserGoalFollow record. The follower receives feed items when the goal owner logs progress. Soft-deleted for toggle behavior.
Code: UserGoalFollow model, ToggleFollowGoal interaction
Health Score
A computed metric (0-100) measuring community engagement quality. Weighted formula: active member ratio (40%) + post frequency (30%) + response time (20%) + admin presence (10%).
Code: Community#health_score
Discovery Reason
The single signal a discovery surface (recommendedCommunities, trendingCommunities, communityInsights.suggestedCommunities) is allowed to show a user for why a community was ranked. Chosen by fixed precedence — goal_category → seasonal_event → community_health — never by the ranking score itself. nil when no disclosable signal applies: no chip is better than a laundered chip.
Kinds: goal_category, seasonal_event, community_health, ally_overlap (declared on the type but never actually returned by any resolver — see Disclosable, below)
Code: Social::RankCommunities#select_reason, Types::CommunityReasonType (fields kind, label, disclosable)
Disclosable
A boolean on a Discovery Reason marking whether a ranking signal is safe to show the user as the reason a community was recommended. goal_category, seasonal_event, and community_health are all disclosable. Ally overlap is the one ranking input that is never disclosable — it feeds Social::RankCommunities' score, but the resolver never returns kind: 'ally_overlap', because "you were shown this because your ally X is a member" would out that ally's own membership to the viewer. Types::SuggestedCommunityType#mutual_allies stays pinned at 0 for the same reason, independent of this field.
Code: Types::CommunityReasonType#disclosable, Social::RankCommunities#select_reason, Types::SuggestedCommunityType#mutual_allies
Notification
An in-app notification delivered to a user. Has a kind, templated message, and JSONB details. Triggers GraphQL subscriptions and push notifications on creation.
Kinds: encouragement (0), badge (1), general (2), comment (3), reminder (4), past_due (5), follow (6), ai_check_in (7), reaction (8)
Code: UserNotification model, UserNotification.generate (factory method), Social::AcknowledgeNotification, Social::AcknowledgeAllNotifications, Social::DeleteNotification, Social::BuildNotificationHistory interactions
Post Comment
A text reply on a community post. Subject to content moderation (has moderation_status). Can be reported and flagged.
Moderation statuses: approved (0), pending_review (1), rejected (2)
Code: PostComment model, AddPostComment interaction
Post Reaction
An emoji/like reaction on a community post. One per user per post per type (unique constraint).
Code: PostReaction model
Reaction
An emoji-based response to a goal event. Distinct from Encouragement (which is a simple "like"): reactions carry a specific emoji from a curated set of 16 allowed emojis. Toggle behavior: creating a reaction when one already exists with the same emoji removes it; with a different emoji, it swaps in place. Soft-deleted via paranoia. Triggers a notification and feed item for the goal owner.
Allowed emojis: ALLOWED_EMOJIS constant
Code: GoalEventReaction model, ToggleGoalEventReaction interaction
Referral Code
The code embedded in a celebration share link (?ref={code}) that attributes a resulting signup back to the sharer. Minted fresh on every shareableMoment preview query but only persisted onto a ShareEvent when the share actually completes — more codes are minted than ShareEvents exist, by design. Captured client-side under last-touch semantics (a later share-link visit overwrites an earlier one) and consumed exactly once, on first sign-in.
Code: ShareEvent#code, Social::RecordShare, Social::AttributeShare, ionic_frontend/src/lib/sourceAttribution.ts (persistShareCode/readPersistedShareCode)
Seasonal Event
A platform-wide, time-boxed challenge — the counterpart to a Community Challenge but deliberately not scoped to a community_id, so it's open to every user rather than one community's members. Users join, accrue progress on a SeasonalEventParticipant (progress_count), and qualify by reaching target_goal_count before end_date. Finalizing awards a badge to each qualifier, guarded by the same completion_processed_at reprocessing lock and durable notified_at at-most-once push marker as challenge finalization — but does not create a CommunityFeedItem the way FinalizeCommunityChallenge does, since a platform-wide event has no community to post the feed item into.
Code: SeasonalEvent model, SeasonalEventParticipant model, Social::JoinSeasonalEvent, Social::LeaveSeasonalEvent, Social::IncrementSeasonalEventProgress, Social::FinalizeSeasonalEvent interactions
Share Attribution
The record that a new signup was caused by a specific ShareEvent's referral link. Created once per user (unique index on user_id, the real idempotency guarantee — not the calling mutation's own first_sign_in flag) and never for a sharer following their own link. Excluded from data export and hard-deleted (not exported) on account erasure.
Code: ShareAttribution model, Social::AttributeShare interaction
Share Event
A record of a completed celebration share — a badge, goal completion, milestone, or streak the user shared off-platform. Carries the referral code, channel (native/link), and which kind/subject was shared. Distinct from a preview: opening the share sheet mints a code via shareableMoment but creates no ShareEvent until the share actually completes. Excluded from data export and hard-deleted (not exported) on account erasure.
Code: ShareEvent model, Social::RecordShare interaction, Types::ShareableMomentType
Unified Feed
An aggregated activity stream combining four sources: ally goal events, community posts, user feed items (notifications/badges), and the user's own goal events. All items within a 14-day lookback window, sorted by timestamp, with limit/offset pagination. A CQRS-style read projection.
Code: BuildUnifiedFeed interaction (query service)
User Identity & Profile
Device
A registered push notification token for a user's mobile device. Tracks platform (iOS/Android). Soft-deleted when unregistered.
Code: UserDevice model, StoreDeviceToken interaction
Mood Log
A mood check-in record. Optionally linked to a specific goal. Six mood values.
Moods: amazing, happy, calm, meh, tired, low
Code: MoodLog model (< PublicRecord), AddMoodLog interaction
Public ID
A URL-safe base64 token generated for every PublicRecord model on creation. The only identifier exposed to clients — internal integer IDs are never sent over the API. Used for lookups via Model.public_find(id).
Code: PublicRecord base class, GeneratePublicId interaction
Sign-in
A tracked user session. UserSignIn aggregates sign-in data (most recent, total count). UserSignInHistory logs individual dated sign-ins. Creating a sign-in triggers streak calculation and XP award.
Code: UserSignIn model, UserSignInHistory model, RecordSignIn interaction
Streak (User)
Consecutive days the user has signed into the app. Calculated from UserSignInHistory dates. Stored on User as current_streak and longest_streak. Awards 50 XP per streak day when the streak grows.
Code: User#update_streak!, User#streak, UserSignIn, UserSignInHistory
Sync (User)
The process of finding or creating a local User record from a Clerk authentication profile on first sign-in. Runs once per session. Also detects first-time sign-ins for onboarding flow.
Code: ClerkUserSync interaction, SyncUser GraphQL mutation
User
The central entity referenced by every context. Owns goals, community memberships, ally relationships, devices, and gamification state. Authenticated via Clerk OAuth. Aggregate root (shared kernel).
Code: User model, UpdateUser interaction, UpdateUserPhoto interaction
User Detail
Extended profile metadata stored as JSONB. Includes app version and feedback data. Soft-deleted.
Code: UserDetail model, StoreUserDetails interaction
User Photo
A profile image for a user. Uses ActiveStorage.
Code: UserPhoto model, UpdateUserPhoto interaction
Gamification & Progression
Acknowledge
Marking a badge unlock or notification as "seen" by the user. Sets the acknowledged boolean on UserAction or UserNotification. Does not delete the record — acknowledged items remain for history. The verb is shared, but the two owners differ: AcknowledgeAction manages UserAction (badges), which Gamification owns; Social::AcknowledgeNotification / Social::AcknowledgeAllNotifications manage UserNotification, which Social & Community owns. See 05 — Application Services § Namespace Placement Rule.
Code: AcknowledgeAction interaction (Gamification), Social::AcknowledgeNotification / Social::AcknowledgeAllNotifications interactions (Social)
Badge
A milestone achievement unlocked by user behavior. Badges are represented as UserAction records with an action enum. Each badge can only be earned once.
Badge types (20):
| Badge | Trigger |
|---|---|
first_sign_in | First login |
create_first_goal | First goal created |
complete_first_goal | First goal completed |
complete_fifth_goal | 5th goal completed |
complete_tenth_goal | 10th goal completed |
create_second_type | Goals in 2 different types |
create_second_category | Goals in 2 different categories |
join_first_community | First community joined |
consistency_is_key | Sustained streak |
habit_former | Habit completion milestone |
dedicated, supporter, super_fan | Engagement tiers |
visionary, achiever, explorer, innovator, planner, executor | Archetype badges |
early_bird | Early adopter |
Rarity tiers (frontend): Common, Rare, Epic, Legendary
Code: UserAction model, UserAction.generate, badge detection jobs
Level
A user's progression rank, computed from cumulative XP. Starts at 1.
XP thresholds:
| Level | XP Required |
|---|---|
| 1 | 0 |
| 2 | 500 |
| 3 | 1,000 |
| 4 | 2,000 |
| 5 | 3,500 |
| 6 | 5,500 |
| 7 | 8,000 |
| 8 | 11,000 |
| 9 | 15,000 |
| 10 | 20,000 |
| 11+ | +5,000 per level |
Code: User.level, GamificationService.calculate_threshold(level)
Rank (Streak)
A named title corresponding to a user's current streak-day count. Uses a masonry/stone-building metaphor — small efforts accumulating into something lasting. Not stored in the database — derived from streak day at render time.
Rank names: First Stone, Steady Hand, Foundation, Cornerstone, Momentum, Architect, Pillar, Keystone, Monument, Legacy
Code: Frontend only — ionic_frontend/src/composables/streakRanks.ts
Rank (XP)
A named title corresponding to a user's level (level is XP-derived — see Level). Uses a distance/journey metaphor, deliberately distinct from the streak rank's masonry vocabulary. Not stored in the database — derived from level at render time.
Until OBJ-3024, this ladder shared nine of its ten titles with Rank (Streak) above (only rung 3 differed: "Foundation" vs. "Path Maker") — the two are unrelated ladders (one tracks streak days, the other tracks XP) that happened to use almost the same words. The XP ladder was renamed to a non-overlapping vocabulary to remove the collision.
Rank names: Open Road, Bearings, Full Stride, Second Wind, Long Haul, Ridgeline, Frontier, Wayfinder, Far Country, Horizon
Code: Backend and frontend — Achievements::ComputeUserRankService (rails_api/app/services/achievements/compute_user_rank_service.rb) is the server-authoritative source, exposed via user.achievementStats.currentRankName over GraphQL; ionic_frontend/src/constants/gamification.ts's RANK_LADDER mirrors it client-side (a test asserts the two lists match, in order). Also read by the AI coach prompt (rails_api/app/interactions/ai/build_coach_context.rb).
Showcase
A user's curated selection of badges displayed on their profile. Users choose which earned badges to highlight.
Code: UpdateShowcasedAchievements interaction
Streak Insurance
A Supporter-only paid recovery lane for a broken habit streak (v4.67 Phase 1, OBJ-4022) — a third lane alongside the free Freeze Token (proactive) and RepairStreak (reactive, free, once per goal lifetime, XP-charged; see 05 — Application Services). Gated by the streak_insurance_enabled feature flag and grants up to INSURANCE_MONTHLY_ALLOWANCE (1) claim per calendar month, tracked one row per (user, period_key) via StreakInsuranceClaim. ClaimStreakInsurance never touches streak_repaired_count — that column is RepairStreak's own once-per-goal-lifetime guard, and a paid claim must never remove the free XP-repair lane it sits alongside (ROADMAP decision D5).
Resolved independently from the free XP-lane repair target: insurance_target/insurance_candidate_scope mirror the repair-window filter but skip the streak_repaired_count: 0 guard, so a goal that already spent its free repair can still surface an insurance offer (ROADMAP decision D8).
insurance_* field vocabulary (Types::StreakRepairOfferType, sibling fields to the free-repair eligible/goal_public_id/goal_name/pre_break_habit_streak/repair_xp_cost/repair_eligible_until):
| Field | Meaning |
|---|---|
user_is_supporter | Whether the user has an active Supporter subscription. |
insurance_eligible | Whether an insurance claim is available right now. |
insurance_claims_remaining | Claims left in the current calendar month. |
insurance_period_resets_at | ISO 8601 timestamp when the monthly allowance resets. |
insurance_goal_public_id / insurance_goal_name | The insurance target goal. Null when ineligible. |
insurance_pre_break_habit_streak | Pre-break streak snapshot for the insurance target. Null when ineligible. |
insurance_eligible_until | ISO 8601 timestamp when the insurance window closes. Null when ineligible. |
Code: Gamification::StreakRepairOfferResolver#insurance_result (rails_api/app/services/gamification/streak_repair_offer_resolver.rb), Gamification::ClaimStreakInsurance interaction, Types::StreakRepairOfferType, StreakInsuranceClaim model — exposed via User#streak_repair_offer GraphQL field.
XP (Experience Points)
Cumulative points earned through platform engagement. Never decreases. Drives the leveling system.
XP awards:
| Action | XP |
|---|---|
| Habit check-in | 25 |
| Daily streak (sign-in) | 50 |
Code: User.xp, GamificationService.award_xp(user, amount, reason)
AI Coaching (Supporting)
Advice
Contextual coaching response generated by AI based on the user's goal, progress, and history.
Code: Ai::CoachService, GetAdvice GraphQL mutation
Insight
A page-scoped AI-generated observation. Contextual to the current view (dashboard, goals, achievements, communities). Cached and dismissible.
Code: Ai::CoachService, GetInsight GraphQL mutation, useAiInsights composable
Milestone Generation
AI-suggested sub-goals for a given goal. Returns structured milestones the user can accept or modify.
Code: Ai::CoachService, GenerateMilestones GraphQL mutation
Refine Description
AI-powered improvement of a goal's description text. Returns a polished version the user can accept.
Code: Ai::CoachService, RefineDescription GraphQL mutation
Check-in Prompt
A personalized daily coaching nudge generated by AI, delivered as a notification. Runs on a daily schedule.
Code: GenerateAiCheckInPromptsJob (Crono, daily 10:00), UserNotification kind: ai_check_in
Citation
A corpus page (slug, title, path) the guide assistant cited to support part of its answer. Extracted from [source: <slug>] markers in the model's raw output and validated against the corpus — a cited slug that doesn't resolve to a real page is dropped, never returned to the caller. Always empty when the assistant refuses or is disabled.
Code: Ai::DocsAssistant::AnswerGuideQuestion#extract_valid_citations, Types::GuideAssistantCitationType
Guide Assistant
The "Ask the guide" Q&A surface — a stateless assistant that answers questions about the Objectuve guide (help.objectuve.com) using only the committed guide corpus, never outside knowledge. Sub-context of AI Coaching (v4.55 Phase 3) — see 01 — Bounded Contexts.
Code: Ai::DocsAssistant::AnswerGuideQuestion, askGuideQuestion GraphQL query, Types::GuideAssistantAnswerType
Guide Corpus
The committed JSON snapshot (rails_api/config/ai/guide_corpus.json) of the guide's real source-of-truth markdown (guide_site/*.md), one entry per page (slug, title, path, body). Committed rather than read live because rails_api/'s Docker build context can't see guide_site/. Regenerated by scripts/build-guide-corpus.mjs; .github/workflows/guide-corpus-drift.yml regenerates-and-diffs in CI to catch drift between the guide and what the assistant can cite.
Code: scripts/build-guide-corpus.mjs, rails_api/config/ai/guide_corpus.json
Refusal
The guide assistant's response when a question can't be answered from the guide corpus — the exact string "Not covered in this guide." (REFUSAL_PHRASE), never a guess. Surfaces as GraphQL state REFUSED, with citations always empty.
Code: Ai::DocsAssistant::AnswerGuideQuestion::REFUSAL_PHRASE, GuideAssistantStateEnum::REFUSED
Content Moderation (Cross-Cutting)
Content Flag
A system-generated moderation marker attached to user-created content via polymorphic association. Created automatically by the profanity filter, AI screening, or as a side effect of a user report.
Sources: profanity_filter (0), ai_screen (1), user_report (2)
Severities: low (0), medium (1), high (2), critical (3)
Review statuses: pending (0), approved (1), rejected (2)
Flaggable types: CommunityPost, PostComment, GoalEventComment
Code: ContentFlag model (< PublicRecord), ReviewContentFlag interaction
Content Report
A user-submitted report against a piece of content. Each user can report a given content item only once (unique constraint). Creating a report also generates a ContentFlag with source: :user_report.
Reasons: spam (0), harassment (1), profanity (2), discouraging (3), other (4)
Review statuses: pending (0), reviewed (1), dismissed (2)
Reportable types: CommunityPost, PostComment, GoalEventComment
Code: ContentReport model (< PublicRecord), ReportContent interaction, ReviewContentReport interaction
Moderation Status
An enum on content models (CommunityPost, PostComment, GoalEventComment) indicating moderation state.
Values: approved (0), pending_review (1), rejected (2)
Screen (verb)
Automated content review by the profanity filter or AI screening service. Called from interactions that create user-generated content. Produces a ContentFlag if issues are detected. The profanity filter runs synchronously; AI screening runs asynchronously via ScreenContentJob.
Code: ContentModerationService.screen, ContentModeration::ProfanityFilter, ScreenContentJob
AI Workforce (Platform Infrastructure)
AiEmployee
A configured, persistent AI employee that runs on a schedule, consumes skills as system-prompt fragments, and produces reviewable artifacts. Owns runs, artifacts (via runs), memory, and usage events. Enforces autonomy-level transitions and monthly budget limits. Aggregate root.
Code: AiEmployee model, AiWorkforce::UpdateEmployee interaction
Crew
A free-text label grouping an AiEmployee for Ops Board filtering (AiEmployee.crew, nullable, no enum validation). One value is special: 'marketing' is the only crew a marketing-role (non-admin) user can access — require_ai_workforce_crew_access! grants admins every crew but scopes marketing-role callers to employee.crew == 'marketing' on every AI Workforce query and mutation that resolves a specific employee, run, or artifact. See docs/development/gotchas.md ("AI Workforce access is admin-or-marketing, then crew-scoped for marketing").
Code: AiEmployee.crew, Authorization#require_ai_workforce_crew_access! (rails_api/app/graphql/concerns/authorization.rb)
AiRun
The execution record of a single agent invocation. Status lifecycle: queued → running → succeeded | failed | cancelled. Belongs to an AiEmployee; owns artifacts. Aggregate root.
Code: AiRun model, AiWorkforce::TriggerRun, AiWorkforce::ProcessWebhookResult, AiWorkforce::ExecuteRunJob
AiArtifact
A durable output produced by an AiRun, awaiting operator review. Kinds: draft_post, code_patch, email_template, report, recommendation. Approval statuses: pending, approved, rejected, auto_rejected (auto-rejected by the brand-voice post-filter).
Code: AiArtifact model, AiWorkforce::ApproveArtifact, AiWorkforce::RejectArtifact
AiEmployeeMemory
Structured JSONB memory for an AI employee, injected into the agent system prompt at run time. One record per memory_key per employee. Capped at ~2,000 tokens when assembled into the prompt.
Code: AiEmployeeMemory model
AiUsageEvent
An append-only per-call cost and token record. Shared with AI Coaching — tracks the full AiUsageEvent::FEATURES feature set: coaching, milestones, insights, check_ins, description, moderation, daily_insight_pack, coach_synopsis, coach_at_risk_nudge, compassionate_break, goal_draft, goal_suggestions, feedback_summary, welcome_back, weekly_digest, goal_quality_check, quick_updates, docs_assistant. Inherits ApplicationRecord (not PublicRecord) and has no public_id — admin-only, never exposed via API.
Code: AiUsageEvent model, AiMetrics::RecordAiUsageEventJob, AiMetrics::AiBudgetAlertJob
Autonomy Level
The degree to which an AiEmployee runs unsupervised. Values: shadow (every artifact requires operator approval), semi_autonomous (some kinds auto-publish, others require approval), autonomous (all kinds auto-publish). Promotion is enforced at the model layer via validate :promotion_requirements_met. Customer-support employees are permanently blocked from promotion above shadow.
Code: AiEmployee::AUTONOMY_LEVELS, AiEmployee#promotion_requirements_met
Monthly Budget
A per-employee cents-denominated cap on LLM spend for the current calendar month. Enforced both inside Rails (AiEmployee#budget_remaining_cents) and inside LiteLLM (monthly cap by model alias). Breaches trigger AiWorkforce::BudgetAlertJob (Slack alert).
Code: AiEmployee.monthly_budget_cents, AiEmployee#current_month_cost_cents
Post-Filter (Brand Voice)
A mandatory second query() call on every user-facing artifact, using the tightening-brand-voice skill with maxTurns: 1 and no tools. Runs in the Agent Runner (not Rails), conservatively passes on error to prevent false auto-rejection. Not a loaded skill on the main run — kept separate to avoid context dilution.
Code: agent_runner/src/agent/postFilter.ts
Schedule (Cron)
A cron-like expression on AiEmployee.schedule_cron. AiWorkforce::ScheduleRunsJob (Crono, every minute) enqueues runs for any employee whose next_run_at has passed.
Code: AiEmployee#scheduled scope, AiWorkforce::ScheduleRunsJob
Agent Runner
A separate TypeScript Cloud Run service with no DB access that executes Claude Agent SDK query() loops. Communicates with Rails via authenticated HTTP (OIDC in production, shared secret in dev) and returns results via HMAC-signed webhook. External seam for the AI Workforce context.
Code: Ai::AgentRunnerClient (Rails), Ai::OidcAuth, Webhooks::AiWorkforceController, agent_runner/ repo
Billing (Supporter & Teams)
PaymentRecord
A record of a Stripe checkout session, subscription, or payment intent. Belongs to User, optionally to Plan. Tracks status and amount. Aggregate root.
Code: PaymentRecord model
Plan
Reference data for a paid tier (Supporter monthly/annual, Teams). Has a unique slug and an optional Stripe price ID. Aggregate root (reference data).
Code: Plan model
Checkout Session
A Stripe-managed payment flow initiated by Billing::CreateCheckout. Returns a redirect URL; completion is asynchronous via the Stripe webhook.
Code: Billing::CreateCheckout interaction, StripeService
Billing Webhook
Inbound Stripe event (checkout completion, subscription lifecycle, payment intents). Handled by Webhooks::StripeController, which today performs webhook logic directly (candidate for extraction behind a Billing::StripeAdapter ACL).
Code: Webhooks::StripeController
Supporter Expiration
The daily job that revokes supporter entitlements for users whose Stripe subscriptions have lapsed.
Code: Billing::ExpireSupportersJob (Crono, daily)
Feedback (User Voice)
FeedbackPost
A user-submitted product request, improvement, or bug report. Categorized (feature, improvement, bug, other) and given a lifecycle status (open, planned, in_progress, completed, declined). Uses counter caches on vote_count and comment_count for ordering. Aggregate root.
Code: FeedbackPost model, Feedback::CreateFeedbackPost
FeedbackComment
A reply on a FeedbackPost. Supports is_official for staff responses. Soft-deleted.
Code: FeedbackComment model, Feedback::CreateFeedbackComment
FeedbackVote
A unique per-user upvote on a FeedbackPost. Drives the by_votes ordering and enables the voted_by_user scope.
Code: FeedbackVote model, Feedback::ToggleFeedbackVote
Feedback Status
The lifecycle state of a FeedbackPost. Admin-driven transitions: open → planned → in_progress → completed (with shipped_at timestamp) or declined. Status changes trigger voter notifications.
Code: FeedbackPost.status enum, Feedback::UpdateFeedbackPostStatus, Feedback::NotifyVotersJob
FeedbackTag
An admin-managed tag (v4.62) applied to FeedbackPosts for finer-grained organization, alongside the fixed category enum. Has a unique name/slug, a position for display order, and can be archived (archived_at) without detaching it from posts that already carry it. Merged behind feedback_tags_enabled, currently 0% rollout.
Code: FeedbackTag model, Feedback::CreateFeedbackTag/UpdateFeedbackTag/ArchiveFeedbackTag
FeedbackPostTag
Join model between FeedbackPost and FeedbackTag (v4.62). No public_id — not independently API-exposed. A post may carry at most FeedbackPost::MAX_TAGS_PER_POST (3) tags, enforced by a model validation on FeedbackPost.
Code: FeedbackPostTag model, Feedback::UpdateFeedbackPostTags
Integrations & Connected Apps
Integration Connection
A user's link to a third-party activity provider — an OAuth token pair for Strava, or a Chess.com username for auth_type: 'none' providers. Owns habit mappings and fetched activities. Status lifecycle: active, paused, error. Aggregate root.
Code: IntegrationConnection model, AuthorizeConnection / ConnectChess interactions
Integration Activity
A single fetched activity from a connected provider — a Strava run, a Chess.com game. Optionally checked in against a habit. Deduplicated via a unique idempotency_key (connection_id:provider_activity_id:date).
Code: IntegrationActivity model
Integration Provider
Catalog entry for a connectable third-party service. Reference data.
Auth types: oauth (Strava), api_key, none (Chess.com)
Code: IntegrationProvider model, IntegrationProvider::Adapter base contract, IntegrationProvider::Strava, IntegrationProvider::Chess
Habit Integration Mapping
A confidence-scored link between a provider's activity type (e.g. Strava's run) and an Objectuve habit (Goal). Proposed automatically by MapIncomingActivity or created manually; user-acceptable, editable, and dismissible.
Code: HabitIntegrationMapping model, AcceptMapping / EditMapping / DismissMapping interactions
Confidence Score
A 0–1 score MapIncomingActivity assigns an IntegrationActivity against a candidate goal, from a rule table of category-match plus timing bonuses. Classified into a decision band: auto (≥ 0.85), propose (≥ 0.50), or ignore.
Code: Integrations::MapIncomingActivity, AUTO_CHECK_THRESHOLD, PROPOSAL_THRESHOLD
Auto Check-In (verb)
Turning a confidence-scored IntegrationActivity into a real habit check-in without user action, when its score clears the auto-check threshold. The only place an integration activity becomes an actual HabitCompletion + GoalEvent — anything below threshold is surfaced as a proposal instead, never checked in silently.
Code: Integrations::AutoCheckIn, Integrations::ProcessIncomingActivity
Personal Analytics
Month in Review
The dashboard's month-to-date hero summary: days active, best streak, badge-XP earned, goals completed, and the leading category. Computed on demand, not persisted.
Code: PersonalAnalytics::CalculateMonthInReview
Completion by Category
Per-category percentage of goals completed month-to-date, using the shared GoalProgressCalculator precedence (habit > roadmap > target amount > not tracked). Categories beyond the top 5 fold into "Other."
Code: PersonalAnalytics::CalculateCompletionByCategory
Activity Heatmap
Daily activity counts (habit check-ins, goal events, mood logs) over the trailing 90 days, keyed to the user's own timezone.
Code: PersonalAnalytics::CalculateActivityHeatmap
Badge-XP Proxy
A stand-in for XP earned, since no per-event XP ledger exists in the database. Counts badge unlocks over a period at a fixed 100 XP each, matching the frontend's "1 badge = 100 XP" model. Shared by the Month in Review and XP Over Time series.
Code: PersonalAnalytics::BadgeXpProxy, XP_PER_BADGE
Import/Export
DataImport
A user's staged CSV import — one goals/habit_completions upload pair parsed in-request and held entirely in-database (staged_rows, row_errors, row_warnings jsonb) pending user confirmation. Never backed by ActiveStorage or a GCS object; the uploaded Tempfile is validated and discarded. Deliberately named outside the ImportExport module to avoid a Ruby class/module namespace collision. Aggregate root.
Code: DataImport model, ImportExport::ParseCsv interaction
ImportExport
The module namespacing this context's domain service and interaction (ImportExport::CsvSchema, ImportExport::ParseCsv) — distinct from the DataImport model itself, which sits outside the module (see above).
Code: ImportExport::CsvSchema, ImportExport::ParseCsv
Staged Import
A DataImport in status: staged — parsed, validated, and held for user review, but not yet committed into real Goal/HabitCompletion rows. Committing a staged import is Phase 3+ and not yet implemented; only the staged status is reachable today.
Code: DataImport#status (staged enum value, prefix: :status)
Collision Row
A staged goal row whose name case-insensitively matches an existing non-deleted goal already owned by the importing user. Flagged for the user to resolve, never rejected outright — the row still stages.
Code: ImportExport::ParseCsv#collides_with_existing_goal?, Types::DataImportCollisionType
Admin (Cross-Cutting)
AdminAction
A polymorphic audit log entry recording every administrative or moderator action. Belongs to an actor (User) and optionally a target (any model). Requires action_type and metadata JSONB. Internal-only (inherits ApplicationRecord).
Code: AdminAction model, Admin::Logged interaction helper
AdminRole
A granular admin-role grant for a user. Roles: super_admin, admin, support, moderator. Unique per (user_id, role). Legacy User#admin boolean is auto-synced to true on super_admin grant.
Code: AdminRole model, Admin::UpdateUserRoles interaction
Infrastructure & Cross-Cutting
Anti-Corruption Layer (ACL)
The boundary services that isolate Clerk (external auth provider) from the rest of the system. Clerk internals never leak past these services.
Code: ClerkJwtVerifier (JWT verification via JWKS), ClerkUserSync (profile mapping), Gdpr::ClerkIdentityDeleter (Clerk identity deletion on account erasure — OBJ-3121)
Published Language
The GraphQL schema serving as the API contract between frontend and backend. Queries and mutations are organized by domain concern. The frontend's graphql/ constants are a 1:1 mapping of this contract.
Code: app/graphql/types/query_type.rb, app/graphql/types/mutation_type.rb, ionic_frontend/src/constants/graphql/
Soft Deletion
Core models use acts_as_paranoid. Records get a deleted_at timestamp rather than being hard-deleted. Preserves domain history and enables toggle patterns (encouragements, reactions, follows).
Soft-deleted models (34, verified via grep -l acts_as_paranoid rails_api/app/models/*.rb): AiArtifact, AiEmployee, AiEmployeeMemory, AiRun, AllyInvite, ChallengeParticipant, CoachConversation, CoachMessage, CollectiveGoal, Community, CommunityChallenge, CommunityPost, CriticalPathPlay, DesignAsset, EnneagramAssessment, FeedbackComment, FeedbackPost, GdprRequest, Goal, GoalEvent, GoalEventEncouragement, GoalEventReaction, GoalMedia, GoalTemplate, PaymentRecord, Plan, StimXpLedger, Team, TeamInvite, TeamMembership, User, UserDetail, UserDevice, UserGoalFollow
Note: GoalEventComment was previously (incorrectly) listed here — it does not call acts_as_paranoid and is hard-deleted.
Word Cloud
A read-only value object representing word frequency data from goal names. Used for admin analytics.
Code: WordCloud model (includes ActiveModel::Model), GenerateWordCloud interaction
Quick Reference
| Term | Context | Primary Code Location |
|---|---|---|
| Acknowledge | Gamification / Social | AcknowledgeAction (Gamification), Social::AcknowledgeNotification / Social::AcknowledgeAllNotifications (Social) |
| Active Accountability Partnership | Social | UserAlly.active_partnership_between / .active_partnerships_for / .with_active_partnership |
| Advice | AI Coaching | Ai::CoachService |
| Ally | Social | UserAlly model |
| Badge | Gamification | UserAction model |
| Check-in | Goal Tracking | CheckInHabit interaction |
| Check-in Prompt | AI Coaching | GenerateAiCheckInPromptsJob |
| Collage | Goal Tracking | GoalCollage model |
| Community | Social | Community model |
| Community Badge | Social | Community#badges |
| Community Event | Social | CommunityEvent model |
| Community Feed Item | Social | CommunityFeedItem model |
| Community Follow | Social | CommunityFollow model |
| Community Goal | Social | CommunityGoal model |
| Community Member | Social | CommunityMember model |
| Community Media | Social | CommunityMedia model |
| Community Post | Social | CommunityPost model |
| Community Suggestion | Social | CommunitySuggestion model |
| Completion Rate | Goal Tracking | Goal#completion_rate(days) |
| Content Flag | Content Moderation | ContentFlag model |
| Content Report | Content Moderation | ContentReport model |
| Device | User Identity | UserDevice model |
| Discovery Reason | Social | Social::RankCommunities#select_reason, Types::CommunityReasonType |
| Disclosable | Social | Types::CommunityReasonType#disclosable |
| Encouragement | Social | GoalEventEncouragement model |
| Event Comment (Goal) | Social | GoalEventComment model |
| Feed Item (User) | Social | UserFeedItem model |
| Feed Kind | Social | FeedKind model |
| Follow (Goal) | Social | UserGoalFollow model |
| Freeze Token | Goal Tracking | Goal#streak_freezes_available |
| Goal | Goal Tracking | Goal model |
| Goal Category | Goal Tracking | GoalCategory model |
| Goal Encouragement | Social | GoalEncouragement model |
| Goal Event | Goal Tracking | GoalEvent model |
| Goal Media | Goal Tracking | GoalMedia model |
| Goal Type (Kind) | Goal Tracking | GoalType model |
| Habit | Goal Tracking | Goal#habit? |
| Habit Completion | Goal Tracking | HabitCompletion model |
| Health Score | Social | Community#health_score |
| Insight | AI Coaching | Ai::CoachService |
| Level | Gamification | GamificationService.calculate_threshold |
| Milestone | Goal Tracking | Milestone model |
| Milestone Generation | AI Coaching | Ai::CoachService |
| Moderation Status | Content Moderation | enum on content models |
| Mood Log | User Identity | MoodLog model |
| Notification | Social | UserNotification model |
| Post Comment | Social | PostComment model |
| Post Reaction | Social | PostReaction model |
| Progress Data | Goal Tracking | CalculateGoalProgress interaction |
| Public ID | Infrastructure | PublicRecord base class |
| Rank (Streak) | Gamification | ionic_frontend/src/composables/streakRanks.ts (frontend only) |
| Rank (XP) | Gamification | Achievements::ComputeUserRankService (backend + frontend) |
| Reaction | Social | GoalEventReaction model |
| Recurrence Schedule | Goal Tracking | Goal.recurrence_type |
| Referral Code | Social | ShareEvent#code, Social::AttributeShare |
| Refine Description | AI Coaching | Ai::CoachService |
| Screen (verb) | Content Moderation | ContentModerationService.screen |
| Seasonal Event | Social | SeasonalEvent model, Social::FinalizeSeasonalEvent |
| Share Attribution | Social | ShareAttribution model |
| Share Event | Social | ShareEvent model |
| Showcase | Gamification | UpdateShowcasedAchievements |
| Sign-in | User Identity | UserSignIn model |
| Soft Deletion | Infrastructure | acts_as_paranoid |
| Streak (Habit) | Goal Tracking | Goal#habit_streak |
| Streak (User) | User Identity | User#current_streak |
| Streak Insurance | Gamification | Gamification::StreakRepairOfferResolver#insurance_result |
| Sync (User) | User Identity | ClerkUserSync interaction |
| Unified Feed | Social | BuildUnifiedFeed interaction |
| User | User Identity | User model |
| User Detail | User Identity | UserDetail model |
| User Photo | User Identity | UserPhoto model |
| Word Cloud | Infrastructure | WordCloud model |
| XP | Gamification | GamificationService.award_xp |
| AiEmployee | AI Workforce | AiEmployee model |
| Crew | AI Workforce | AiEmployee.crew |
| AiRun | AI Workforce | AiRun model |
| AiArtifact | AI Workforce | AiArtifact model |
| AiEmployeeMemory | AI Workforce | AiEmployeeMemory model |
| AiUsageEvent | AI Workforce / AI Coaching | AiUsageEvent model |
| Autonomy Level | AI Workforce | AiEmployee::AUTONOMY_LEVELS |
| Monthly Budget | AI Workforce | AiEmployee#budget_remaining_cents |
| Post-Filter | AI Workforce | agent_runner/src/agent/postFilter.ts |
| Schedule (Cron) | AI Workforce | AiWorkforce::ScheduleRunsJob |
| Agent Runner | AI Workforce | Ai::AgentRunnerClient |
| PaymentRecord | Billing | PaymentRecord model |
| Plan | Billing | Plan model |
| Checkout Session | Billing | Billing::CreateCheckout |
| Billing Webhook | Billing | Webhooks::StripeController |
| Supporter Expiration | Billing | Billing::ExpireSupportersJob |
| FeedbackPost | Feedback | FeedbackPost model |
| FeedbackComment | Feedback | FeedbackComment model |
| FeedbackVote | Feedback | FeedbackVote model |
| Feedback Status | Feedback | FeedbackPost.status enum |
| AdminAction | Admin | AdminAction model |
| AdminRole | Admin | AdminRole model |
| Integration Connection | Integrations & Connected Apps | IntegrationConnection model |
| Integration Activity | Integrations & Connected Apps | IntegrationActivity model |
| Integration Provider | Integrations & Connected Apps | IntegrationProvider model |
| Habit Integration Mapping | Integrations & Connected Apps | HabitIntegrationMapping model |
| Confidence Score | Integrations & Connected Apps | Integrations::MapIncomingActivity |
| Auto Check-In | Integrations & Connected Apps | Integrations::AutoCheckIn |
| Month in Review | Personal Analytics | PersonalAnalytics::CalculateMonthInReview |
| Completion by Category | Personal Analytics | PersonalAnalytics::CalculateCompletionByCategory |
| Activity Heatmap | Personal Analytics | PersonalAnalytics::CalculateActivityHeatmap |
| Badge-XP Proxy | Personal Analytics | PersonalAnalytics::BadgeXpProxy |
| DataImport | Import/Export | DataImport model |
| ImportExport | Import/Export | ImportExport::CsvSchema, ImportExport::ParseCsv |
| Staged Import | Import/Export | DataImport#status (staged) |
| Collision Row | Import/Export | ImportExport::ParseCsv#collides_with_existing_goal? |
Last updated: 2026-09-19 (OBJ-4032: added Streak Insurance term under Gamification & Progression, covering the insurance_* field vocabulary added to Types::StreakRepairOfferType in v4.67 Phase 3b)
Previously: 2026-09-18 (OBJ-3816: added Discovery Reason and Disclosable terms under Social & Community, backfilling a v4.63 Phase 3 discovery-vocabulary gap flagged in Roy's Phase 3 review)
Even earlier: 2026-09-18 (OBJ-3949: added Seasonal Event term under Social & Community, backfilling a gap from v4.63 Phase 6/7)
Prior update: 2026-09-15 (OBJ-3822: added DataImport, ImportExport, Staged Import, and Collision Row terms under a new Import/Export section, v4.64 Phase 2)