Skip to content

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_categoryseasonal_eventcommunity_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):

BadgeTrigger
first_sign_inFirst login
create_first_goalFirst goal created
complete_first_goalFirst goal completed
complete_fifth_goal5th goal completed
complete_tenth_goal10th goal completed
create_second_typeGoals in 2 different types
create_second_categoryGoals in 2 different categories
join_first_communityFirst community joined
consistency_is_keySustained streak
habit_formerHabit completion milestone
dedicated, supporter, super_fanEngagement tiers
visionary, achiever, explorer, innovator, planner, executorArchetype badges
early_birdEarly 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:

LevelXP Required
10
2500
31,000
42,000
53,500
65,500
78,000
811,000
915,000
1020,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):

FieldMeaning
user_is_supporterWhether the user has an active Supporter subscription.
insurance_eligibleWhether an insurance claim is available right now.
insurance_claims_remainingClaims left in the current calendar month.
insurance_period_resets_atISO 8601 timestamp when the monthly allowance resets.
insurance_goal_public_id / insurance_goal_nameThe insurance target goal. Null when ineligible.
insurance_pre_break_habit_streakPre-break streak snapshot for the insurance target. Null when ineligible.
insurance_eligible_untilISO 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:

ActionXP
Habit check-in25
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: queuedrunningsucceeded | 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: openplannedin_progresscompleted (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

TermContextPrimary Code Location
AcknowledgeGamification / SocialAcknowledgeAction (Gamification), Social::AcknowledgeNotification / Social::AcknowledgeAllNotifications (Social)
Active Accountability PartnershipSocialUserAlly.active_partnership_between / .active_partnerships_for / .with_active_partnership
AdviceAI CoachingAi::CoachService
AllySocialUserAlly model
BadgeGamificationUserAction model
Check-inGoal TrackingCheckInHabit interaction
Check-in PromptAI CoachingGenerateAiCheckInPromptsJob
CollageGoal TrackingGoalCollage model
CommunitySocialCommunity model
Community BadgeSocialCommunity#badges
Community EventSocialCommunityEvent model
Community Feed ItemSocialCommunityFeedItem model
Community FollowSocialCommunityFollow model
Community GoalSocialCommunityGoal model
Community MemberSocialCommunityMember model
Community MediaSocialCommunityMedia model
Community PostSocialCommunityPost model
Community SuggestionSocialCommunitySuggestion model
Completion RateGoal TrackingGoal#completion_rate(days)
Content FlagContent ModerationContentFlag model
Content ReportContent ModerationContentReport model
DeviceUser IdentityUserDevice model
Discovery ReasonSocialSocial::RankCommunities#select_reason, Types::CommunityReasonType
DisclosableSocialTypes::CommunityReasonType#disclosable
EncouragementSocialGoalEventEncouragement model
Event Comment (Goal)SocialGoalEventComment model
Feed Item (User)SocialUserFeedItem model
Feed KindSocialFeedKind model
Follow (Goal)SocialUserGoalFollow model
Freeze TokenGoal TrackingGoal#streak_freezes_available
GoalGoal TrackingGoal model
Goal CategoryGoal TrackingGoalCategory model
Goal EncouragementSocialGoalEncouragement model
Goal EventGoal TrackingGoalEvent model
Goal MediaGoal TrackingGoalMedia model
Goal Type (Kind)Goal TrackingGoalType model
HabitGoal TrackingGoal#habit?
Habit CompletionGoal TrackingHabitCompletion model
Health ScoreSocialCommunity#health_score
InsightAI CoachingAi::CoachService
LevelGamificationGamificationService.calculate_threshold
MilestoneGoal TrackingMilestone model
Milestone GenerationAI CoachingAi::CoachService
Moderation StatusContent Moderationenum on content models
Mood LogUser IdentityMoodLog model
NotificationSocialUserNotification model
Post CommentSocialPostComment model
Post ReactionSocialPostReaction model
Progress DataGoal TrackingCalculateGoalProgress interaction
Public IDInfrastructurePublicRecord base class
Rank (Streak)Gamificationionic_frontend/src/composables/streakRanks.ts (frontend only)
Rank (XP)GamificationAchievements::ComputeUserRankService (backend + frontend)
ReactionSocialGoalEventReaction model
Recurrence ScheduleGoal TrackingGoal.recurrence_type
Referral CodeSocialShareEvent#code, Social::AttributeShare
Refine DescriptionAI CoachingAi::CoachService
Screen (verb)Content ModerationContentModerationService.screen
Seasonal EventSocialSeasonalEvent model, Social::FinalizeSeasonalEvent
Share AttributionSocialShareAttribution model
Share EventSocialShareEvent model
ShowcaseGamificationUpdateShowcasedAchievements
Sign-inUser IdentityUserSignIn model
Soft DeletionInfrastructureacts_as_paranoid
Streak (Habit)Goal TrackingGoal#habit_streak
Streak (User)User IdentityUser#current_streak
Streak InsuranceGamificationGamification::StreakRepairOfferResolver#insurance_result
Sync (User)User IdentityClerkUserSync interaction
Unified FeedSocialBuildUnifiedFeed interaction
UserUser IdentityUser model
User DetailUser IdentityUserDetail model
User PhotoUser IdentityUserPhoto model
Word CloudInfrastructureWordCloud model
XPGamificationGamificationService.award_xp
AiEmployeeAI WorkforceAiEmployee model
CrewAI WorkforceAiEmployee.crew
AiRunAI WorkforceAiRun model
AiArtifactAI WorkforceAiArtifact model
AiEmployeeMemoryAI WorkforceAiEmployeeMemory model
AiUsageEventAI Workforce / AI CoachingAiUsageEvent model
Autonomy LevelAI WorkforceAiEmployee::AUTONOMY_LEVELS
Monthly BudgetAI WorkforceAiEmployee#budget_remaining_cents
Post-FilterAI Workforceagent_runner/src/agent/postFilter.ts
Schedule (Cron)AI WorkforceAiWorkforce::ScheduleRunsJob
Agent RunnerAI WorkforceAi::AgentRunnerClient
PaymentRecordBillingPaymentRecord model
PlanBillingPlan model
Checkout SessionBillingBilling::CreateCheckout
Billing WebhookBillingWebhooks::StripeController
Supporter ExpirationBillingBilling::ExpireSupportersJob
FeedbackPostFeedbackFeedbackPost model
FeedbackCommentFeedbackFeedbackComment model
FeedbackVoteFeedbackFeedbackVote model
Feedback StatusFeedbackFeedbackPost.status enum
AdminActionAdminAdminAction model
AdminRoleAdminAdminRole model
Integration ConnectionIntegrations & Connected AppsIntegrationConnection model
Integration ActivityIntegrations & Connected AppsIntegrationActivity model
Integration ProviderIntegrations & Connected AppsIntegrationProvider model
Habit Integration MappingIntegrations & Connected AppsHabitIntegrationMapping model
Confidence ScoreIntegrations & Connected AppsIntegrations::MapIncomingActivity
Auto Check-InIntegrations & Connected AppsIntegrations::AutoCheckIn
Month in ReviewPersonal AnalyticsPersonalAnalytics::CalculateMonthInReview
Completion by CategoryPersonal AnalyticsPersonalAnalytics::CalculateCompletionByCategory
Activity HeatmapPersonal AnalyticsPersonalAnalytics::CalculateActivityHeatmap
Badge-XP ProxyPersonal AnalyticsPersonalAnalytics::BadgeXpProxy
DataImportImport/ExportDataImport model
ImportExportImport/ExportImportExport::CsvSchema, ImportExport::ParseCsv
Staged ImportImport/ExportDataImport#status (staged)
Collision RowImport/ExportImportExport::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)

Loading…