Skip to content

Privacy Controls: "Go It Alone" & Private Mode -- Feature Exploration & PRD

Product: Objectuve (codename: Enkidu) Feature: Privacy Controls (Roadmap #29) Status: Exploration / Design Date: April 2026


1. Problem Statement

Objectuve markets itself as an "anti-social" goal-tracking app: sessions should last roughly 10 minutes, and social features exist strictly for accountability, not entertainment. Yet today the app makes no distinction between users who want community accountability and users who want pure solo tracking. Every user sees the same Community tab, Feed tab, ally activity, and social notifications regardless of preference.

Three problems:

  1. Unwanted social pressure. Users who came for personal streak-tracking see community recommendations, ally activity feeds, and social notifications they never asked for. For users managing sensitive goals (health, finance, mental wellness), the mere visibility of social features creates anxiety about accidental exposure.

  2. No way to reduce discoverability. A user who joins one community or accepts one ally connection becomes searchable, appears in leaderboards, and can receive ally requests. There is no mechanism to participate selectively without appearing on everyone's radar.

  3. Coach misalignment. The AI coach currently gives community-related suggestions to all users. A user with no interest in communities receives irrelevant advice.

Privacy controls are not a niche request -- they are a prerequisite for the app's own brand promise. If Objectuve is genuinely "anti-social by design," it must let users opt out of the social layer entirely, or at least control their visibility within it.


2. Goals & Success Metrics

Goals

  1. Let users remove all community/social UI so the app feels like a pure personal tracker
  2. Let users hide themselves from search, discovery, and leaderboards while retaining direct-invite participation
  3. Provide username-based user search for intentional ally connections
  4. Ensure the AI coach respects the user's privacy posture
  5. Preserve all underlying data so toggling off restores everything instantly

Success Metrics

MetricTargetMeasurement
Go It Alone adoption10-15% of MAU enable within 60 daysusers.where(go_it_alone: true).count / MAU
Private Mode adoption5-10% of MAU enableusers.where(private_mode: true).count / MAU
Community engagement preservationPrivate Mode does not reduce community DAU by >2%Compare community DAU pre/post launch
Username search ally conversion20%+ of new ally connections from searchTrack source: 'username_search' on UserAlly creation
Retention impactGo It Alone users retain at >= same rate as general populationCohort analysis at 30/60/90 days
Toggle reversal rate<30% toggle back within 7 daysTrack toggle timestamps

3. User Stories

  1. As a user who prefers solo tracking, I want to toggle "Go It Alone" in Settings so that all community UI disappears and I see only my goals, streaks, and personal progress.
  2. As a Go It Alone user, I want my existing community memberships and ally connections preserved (but hidden) so I can restore them later without re-joining.
  3. As a privacy-conscious user, I want to enable "Private Mode" so that my profile does not appear in search results, ally request discovery, or public leaderboards.
  4. As a Private Mode user, I want to still join communities and accept ally requests via direct invite so I retain selective social engagement.
  5. As a user looking for a specific person, I want to search by username so I can find and connect with people I already know.
  6. As a Private Mode user, I expect that username search does NOT return my profile, so my discoverability preferences are respected.
  7. As a Go It Alone user, I want the AI coach to stop making community-related suggestions and focus exclusively on personal goal strategies.
  8. As a Go It Alone user, I want social notifications paused so I am not reminded of features I have hidden.
  9. As a user who toggles off Go It Alone, I want a "welcome back" confirmation and all my previous data restored immediately.
  10. As a new user during onboarding, I want the option to skip community features entirely and start in Go It Alone mode.

4. Feature Design

4a. "Go It Alone" Mode

What gets hidden

Every social/community UI element disappears:

Navigation:

  • "Community" tab filtered from visibleTabs in BottomTabBar.vue
  • "Feed" tab filtered from visibleTabs

Routes:

  • /communities and /communities/:id redirect to /dashboard
  • /feed redirects to /dashboard

Dashboard:

  • allyFeedItems returns empty array
  • socialNotifications returns empty array
  • Any "Join a community" or social CTA cards hidden

Communities page: Inaccessible via route guard redirect.

Activity Feed: Inaccessible via route guard redirect.

AI Coach:

  • Community page context and suggested prompts removed from useAiCoach.ts
  • Backend CoachService receives solo_mode: true, adding "Do not suggest community engagement, ally features, or social activities" to prompts

AI Insights:

  • communities InsightPage excluded
  • Dashboard insights never reference community engagement

Notifications: Social kinds paused at delivery (see Section 8).

Goal Detail:

  • "Share to community" actions hidden
  • Encouragement counts on own events still visible

What remains visible

  • Dashboard (goals, streaks, habits, momentum bar, XP, level)
  • Goals list and individual goal detail
  • All goal tracking features (check-ins, milestones, events)
  • Achievements/badges page
  • Settings (including privacy toggles)
  • AI Coach (personal goal advice only)
  • Personal notifications (badge, general, reminder, past_due, ai_check_in)

Technical approach: Frontend hiding, NOT backend filtering

Go It Alone is a frontend presentation concern. The backend still returns all data normally. The frontend reads user.goItAlone from the GraphQL user query and conditionally hides UI elements.

Rationale:

  • Data integrity: memberships, posts, ally connections remain untouched
  • Instant restoration: toggling off restores everything with no re-fetching
  • No backend complexity: no conditional includes in social queries
  • Single source of truth: the go_it_alone boolean drives all frontend gating

Exception: AI Coach -- the backend CoachService must receive Go It Alone status to adjust prompt content.

What happens to existing data

Nothing. Community memberships, ally connections, posts, reactions, and comments all remain in the database. They are simply not rendered. Toggling off restores everything instantly.

4b. Private Mode

What "not discoverable" means

A Private Mode user is excluded from:

  1. Username search results -- searchUsers query filters out private_mode: true
  2. Recommended allies -- "People you may know" features exclude private users
  3. Public leaderboards -- Community point leaderboards exclude private users
  4. Community member lists for non-members -- Private users don't appear when browsing
  5. Non-ally activity feeds -- Private users' events don't appear for non-allies
  6. Trending/featured contributor lists -- Any list surfacing users by activity excludes private users

What Private Mode users CAN do

  • Join communities (via URL/invite or direct browsing)
  • Accept ally requests arriving via direct invite
  • Post in communities they belong to
  • Appear to existing accepted allies (pre-Private Mode connections unaffected)
  • Send ally requests to others
  • Use all goal-tracking features normally

Queries needing filters

Query/FeedFilter needed
searchUsers (new)WHERE private_mode = false
communityMembers resolverExclude private users from non-member views
Recommended communities (mutual allies count)Exclude private users
userAllies resolverNo change -- already accepted connections
allyActivityFeed resolverNo change -- scoped to accepted allies
BuildUnifiedFeedNo change -- scoped to accepted allies

Existing ally connections

Private Mode does NOT sever existing connections. If User A and User B are accepted allies and User A enables Private Mode, User B still sees User A. Principle: Private Mode controls discovery, not existing relationships.

Interaction with goal visibility tiers (v4.61)

No interaction. Private Mode governs discoverability — whether a user can be found by search, recommendations, or leaderboards. Goal visibility (public/allies/private, added in v4.61 Allies-Only Goal Visibility) governs whether an already-known accepted ally can see a specific goal. A Private Mode user's allies-only goals behave identically to a non-Private-Mode user's: any of their existing accepted allies can see, encourage, comment on, react to, and follow an allies-only goal exactly as they would if Private Mode were off. Enabling Private Mode does not hide, and does not need to hide, a goal from allies the owner has already accepted — those connections aren't "existing ally connections" being newly exposed; they were already visible to each other before Private Mode was ever considered, per the principle above. See Allies § Goal visibility tiers.

4c. User Search by Username

Where it lives

  1. Communities page -- Toggle within existing search bar area to switch between "Search communities" and "Search users"
  2. Add Ally flow -- Primary mechanism for future ally requests (Roadmap #19)

Result display

  • Profile photo, display name, @username
  • Supporter badge (if applicable)
  • Mutual ally count (if > 0)
  • Action button ("Add Ally" / "Pending" / "Already Allies")

Private Mode interaction

searchUsers scope includes WHERE private_mode = false. Private users are completely invisible. No indication that a private user exists.

Matching strategy

Prefix matching on username, case-insensitive. PostgreSQL ILIKE 'query%' using existing index_users_on_username. Minimum query: 3 characters.

Rate limiting

  • Client-side: 400ms debounce
  • Server-side: 20 requests/minute/user
  • Max results: 20 users

4d. Interaction Between Modes

Both can be enabled simultaneously. The toggles are independent and orthogonal:

  • Go It Alone = UI visibility control (hides social from the user's own view)
  • Private Mode = discoverability control (hides the user from other people's views)

A user might want:

  • Private ON, Go It Alone OFF: participates in communities but can't be searched
  • Go It Alone ON, Private OFF: hides social UI but remains discoverable
  • Both ON: maximum privacy
  • Both OFF: default social experience

When enabling Go It Alone, suggest (not auto-enable) Private Mode via secondary prompt.


5. UX Flow

Settings Page Layout

New "Privacy" tab in Settings (after Supporter, before Account):

Profile | Supporter | Privacy | Account | Feedback

Section 1: "Go It Alone" mode

  • Card with User icon, title, description: "Hide all community features and focus purely on your goals."
  • Toggle switch (right-aligned)
  • Secondary text on enable: "Your communities, allies, and posts will be hidden but not deleted."

Section 2: "Private Mode"

  • Card with EyeOff icon, title, description: "Hide your profile from search results, recommendations, and public leaderboards."
  • Toggle switch
  • Subtitle: "You can still join communities and accept ally requests via direct invite."

Section 3: informational

  • Muted text: "Your data is never deleted by these settings. Toggling off restores everything instantly."

First-Time Toggle Activation

Go It Alone: Confirmation dialog (matching existing Delete Account pattern):

  • Header: "Go It Alone?"
  • Message: "Community features will be hidden. Your memberships, allies, and posts are kept safe -- toggle off anytime to bring them back."
  • Buttons: "Cancel" | "Enable"

Private Mode: No dialog. Toast: "Private Mode enabled. You're hidden from search and discovery."

Immediate Effects on Toggle

Go It Alone ON:

  1. updateUser mutation fires with goItAlone: true
  2. Apollo cache updates optimistically
  3. BottomTabBar re-renders without Community and Feed tabs
  4. If on /communities or /feed, navigate to /dashboard
  5. Social notification badges disappear
  6. Toast: "You're now in solo mode"

Go It Alone OFF:

  1. updateUser mutation fires with goItAlone: false
  2. Community and Feed tabs reappear
  3. Apollo refetches community and feed queries
  4. Previously paused notifications appear
  5. Toast: "Welcome back! Your communities and allies are restored."

"Welcome Back" Experience

Dismissible dashboard card after toggling off: "Welcome back to the community! You have [X] unread notifications and [Y] new posts." CTA: "View Activity" (navigates to /feed). Auto-dismiss after 10 seconds.


6. Data Model Changes

New Columns on users Table

ruby
add_column :users, :go_it_alone, :boolean, default: false, null: false
add_column :users, :private_mode, :boolean, default: false, null: false
add_column :users, :go_it_alone_enabled_at, :datetime, null: true
add_column :users, :private_mode_enabled_at, :datetime, null: true

add_index :users, :go_it_alone
add_index :users, :private_mode

The *_enabled_at timestamps support analytics and "welcome back" notification counting.

Model Scopes

ruby
scope :discoverable, -> { where(private_mode: false) }
scope :solo_mode, -> { where(go_it_alone: true) }

GraphQL Changes

UserType: Add go_it_alone (Boolean) and private_mode (Boolean) fields.

UpdateUser mutation: Add go_it_alone and private_mode optional arguments.

New query: searchUsers

  • Arguments: query (String, required), limit (Integer, default: 20)
  • Returns: [UserSearchResultType]

New type: UserSearchResultType

  • public_id, username, first_name, last_name, photo, is_supporter, mutual_ally_count, ally_status

Frontend GraphQL

  • USER_QUERY: Add goItAlone and privateMode fields
  • UPDATE_USER_MUTATION: Add $goItAlone: Boolean and $privateMode: Boolean arguments
  • New SEARCH_USERS_QUERY constant

7. How Privacy Affects Every Feature

Dashboard

ElementGo It AlonePrivate Mode
Greeting, streaks, momentum barNo changeNo change
Social notifications sectionReturns emptyNo change
Ally feed itemsReturns emptyNo change
Notification bell countExcludes social kindsNo change
AI insight cardsNever reference communitiesNo change
Getting Started cardsNo "join a community" CTANo change

Goals List and Detail

ElementGo It AlonePrivate Mode
Goal list/gridNo changeNo change
Check-ins, milestonesNo changeNo change
"Share to community" buttonHiddenNo change
Encouragement display on own eventsStill visibleNo change

Communities Tab/View

ElementGo It AlonePrivate Mode
Tab in BottomTabBarHiddenNo change
Route /communitiesRedirects to /dashboardNo change
Member listsN/APrivate user excluded from non-member browse

Unified Feed / Activity Feed

ElementGo It AlonePrivate Mode
Feed tab in BottomTabBarHiddenNo change
Route /feedRedirects to /dashboardNo change
User's events in others' feedsStill appearStill appear for accepted allies

Ally Activity

ElementGo It AlonePrivate Mode
AllyActivityFeed on Communities pageN/A (page hidden)No change
Ally feed items on DashboardReturns emptyNo change

Encouragements/Reactions

ElementGo It AlonePrivate Mode
Incoming notificationsPausedNo change
Existing encouragements on goalsStored; visible on toggle-offNo change

Notifications

ElementGo It AlonePrivate Mode
Paused kindsencouragement, comment, follow, reaction, feedbackNone
Unaffected kindsbadge, general, reminder, past_due, ai_check_inAll
Push notificationsSocial pushes suppressedNo change
Notification historyStored; visible on toggle-offNo change

AI Coach

ElementGo It AlonePrivate Mode
Community suggested promptsRemovedNo change
Backend advice/insight prompts"Do not suggest community features"No change
Check-in prompt jobContext excludes community dataNo change

Achievements/Badges

ElementGo It AlonePrivate Mode
Badge list and progressNo changeNo change
Community-related badgesDisplayed but not progressableNo change

Onboarding

ElementGo It AlonePrivate Mode
Community wizard slideAdd deferred prompt (not during)No change

Accountability Partners (Roadmap #19)

ElementGo It AlonePrivate Mode
Partner UIHiddenNo change
Existing partnershipsPreserved but hiddenNo change
Partner discovery/searchHiddenPrivate users excluded

Per-goal accountability-partner sharing (v4.10)

Shipped alongside — but architecturally distinct from — the Go It Alone / Private Mode toggles above. Where the table just above describes how partner UI responds to those two modes, this describes the underlying goal visibility model a confirmed accountability partner sees, and it coexists with this PRD's explicit-consent posture rather than contradicting it:

  • Public goals (private: false) are partner-visible by default, no separate opt-in required. A per-goal opt-out (excluding one public goal from partner visibility) is planned but not yet shipped — there is no AccountabilityPartnerGoalExclusion model or table today, so every public goal is currently visible to a confirmed partner. See Accountability partners § Goal exclusions (planned, not yet shipped).
  • Private goals (private: true) stay hidden from the partner by default — the owner must explicitly opt in per goal via the shared_with_partner flag (GoalPartnerSharingCard.vue on Goal Detail). No retroactive exposure: a private goal that predates this feature does not become visible on its own. Reversible at any time, and only the goal's owner can change the setting.
  • Both rules are unified at read time by the single Goal.partner_visible scope (private = false OR shared_with_partner = true), consumed identically by the profile's partnerGoals field and the missed-day alert job — sharing a private habit also makes it eligible for a missed-day alert to the partner.
  • Why this doesn't weaken the "nothing exposed without explicit action" posture this PRD is built on: every partner-visibility rule still traces back to an explicit user action — making a goal public, or flipping shared_with_partner — never to a default-on state or an inferred consent.

Full mechanics, source files, and the user-facing sharing flow: Accountability partners § Per-goal partner sharing.


8. Notification Pause System

Paused Kinds in Go It Alone

Paused: encouragement (0), comment (3), follow (6), reaction (8), feedback (9)

Not paused: badge (1), general (2), reminder (4), past_due (5), ai_check_in (7)

Private Mode does not pause any notifications.

Implementation: Filter at Delivery, Not Generation

Notifications are still generated normally. The pause happens at push delivery and frontend display.

Rationale: Notifications generated during Go It Alone are preserved. When toggling off, the full history appears. No "replay" logic needed. The "welcome back" card can count accumulated social notifications.

Push suppression: SendPushNotification adds early return when user.go_it_alone? and notification kind is social.

WebSocket suppression: UserNotification.trigger_subscription checks Go It Alone and skips trigger for social kinds.

Frontend filtering: Notification list and bell count filter out social kinds when user.goItAlone is true.

Accumulated Notifications on Toggle-Off

They remain as acknowledged: false records. Removing the frontend filter on toggle-off surfaces them all.


9. Edge Cases & Open Questions

Edge Cases

#ScenarioResolution
EC-1User enables Go It Alone while on /communitiesRouter guard detects change, redirects to /dashboard
EC-2Direct ally invite link while in Go It AloneLink works. Prompt: "You have Go It Alone enabled. Accept anyway?" Connection hidden until mode off
EC-3Sole community admin enables Go It AloneWarning: "You're the only admin of [community]. Consider assigning another before going solo."
EC-4Private user already on a leaderboardEntry removed on next query. Other positions shift
EC-5@mention in community post while Go It AloneNotification stored, delivery paused. Visible on toggle-off
EC-6Pending ally request + Private Mode enabledRequest remains pending. Requester can't find user in search. If user accepts via notification, connection forms normally
EC-7Admin queriesAll users visible regardless of privacy settings

Open Questions

  1. Should Go It Alone hide Feed or repurpose as personal-only feed? Recommend hide for v1.
  2. Should Private Mode hide user from fellow community members? No -- membership implies consent. Exclude from public-facing counts only.
  3. Onboarding privacy prompt? Defer. After 7 days of no community engagement, show one-time prompt.
  4. Naming: "Go It Alone" matches the brand's direct tone. "Solo Mode" or "Focus Mode" are weaker (Focus Mode conflicts with existing dashboard mode).
  5. Rate limiting calibration: 20/min for search -- monitor post-launch.

10. Implementation Phases

Phase 1: Data Model & Backend Foundation (1 sprint)

  • Migration: add go_it_alone, private_mode, *_enabled_at columns with indexes
  • Model scopes (discoverable, solo_mode)
  • UpdateUser interaction: accept new fields with timestamp tracking
  • GraphQL: fields on UserType, arguments on UpdateUser mutation
  • Specs: model specs, interaction specs, factory updates

Phase 2: Go It Alone Frontend (1 sprint)

  • Privacy tab in Settings with toggle cards
  • BottomTabBar: filter visibleTabs based on user.goItAlone
  • Router guards: redirect social routes
  • Dashboard: conditional rendering for ally feed, social notifications, community CTAs
  • Confirmation dialog on first enable
  • GraphQL query/mutation updates
  • Storybook stories for privacy toggles
  • Vitest specs for conditional rendering and guards

Phase 3: Notification Pause (1 sprint)

  • SendPushNotification: early return for social kinds
  • UserNotification.trigger_subscription: skip WebSocket for paused kinds
  • Frontend notification filtering
  • "Welcome back" dashboard card
  • Specs for push suppression and filtering

Phase 4: Private Mode Backend (1 sprint)

  • searchUsers query resolver with WHERE private_mode = false
  • UserSearchResultType GraphQL type
  • Community member list filtering for non-members
  • Leaderboard exclusion
  • Resolver and search filtering specs

Phase 5: Username Search Frontend (1 sprint)

  • UserSearchInput.vue with debounced input and results
  • UserSearchResult.vue displaying profile and ally status
  • Communities page integration (community/user search toggle)
  • Ally request button (dependent on Roadmap #19 prerequisite)
  • Client-side rate limiting, loading/error states
  • Storybook stories and unit tests

Phase 6: AI Coach Privacy Awareness (0.5 sprint)

  • CoachService context injection with solo_mode flag
  • useAiCoach composable: strip community prompts when Go It Alone active
  • useAiInsights: skip community insights
  • GenerateAiCheckInPromptsJob: include solo mode in context
  • Coach service specs

Phase 7: Polish & Analytics (0.5 sprint)

  • Admin panel: privacy flags per user, aggregate metrics
  • Analytics events: toggle-on/off, time-in-mode, search usage
  • Onboarding integration: deferred Go It Alone prompt after 7 days
  • Edge case handling: sole admin warning, direct invite behavior
  • QA and regression testing

11. Design Suggestions

Privacy Tab

Calm, neutral palette. Toggles use standard primary color when enabled -- not red or warning colors. Card layout mirrors existing Settings cards.

Tab Removal Animation

When Community/Feed tabs disappear from BottomTabBar: 300ms opacity transition. Remaining tabs redistribute with transition-all duration-300.

"Welcome Back" Card

Full-width dashboard card with warm gradient border (matching existing SupporterStreakNudge pattern). Users icon, accumulated notification count, "View Activity" CTA. Auto-dismiss after 10 seconds.

Username Search Results

Compact horizontal list rows: 40px avatar, name/@username, mutual ally badge, action button. Standard UiInput with Search icon prefix. Empty state: "No users found matching '@{query}'." -- never reveals private users exist.

Privacy Toggle Cards

┌─────────────────────────────────────────┐
│  👤  Go It Alone                    [ON] │
│  Hide all community features and         │
│  focus purely on your goals.             │
│                                          │
│  Your data is preserved. Toggle off      │
│  anytime to bring everything back.       │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│  👁  Private Mode                  [OFF] │
│  Hide your profile from search,          │
│  recommendations, and leaderboards.      │
│                                          │
│  You can still join communities and      │
│  accept ally requests via direct invite. │
└─────────────────────────────────────────┘

Critical Files

FileChange
rails_api/app/models/user.rbAdd go_it_alone, private_mode fields, scopes
rails_api/app/interactions/user_identity/update_user.rbAccept and persist privacy fields
rails_api/app/graphql/types/user_type.rbExpose privacy fields
rails_api/app/graphql/mutations/update_user.rbAdd privacy arguments
rails_api/app/graphql/types/query_type.rbAdd searchUsers query
rails_api/app/interactions/social/send_push_notification.rbGo It Alone push suppression
rails_api/app/models/user_notification.rbWebSocket suppression for social kinds
rails_api/app/services/ai/coach_service.rbSolo mode prompt injection
ionic_frontend/src/components/BottomTabBar.vueFilter tabs by goItAlone
ionic_frontend/src/router/index.tsRoute guards for social routes
ionic_frontend/src/views/Settings.vueNew Privacy tab
ionic_frontend/src/views/Dashboard.vueConditional social rendering
ionic_frontend/src/composables/useAiCoach.tsStrip community prompts
ionic_frontend/src/composables/useAiInsights.tsSkip community insights
ionic_frontend/src/constants/graphql/user.jsAdd privacy fields to queries/mutations

Last updated: 2026-09-15 — added §4b "Interaction with goal visibility tiers (v4.61)": Private Mode and the v4.61 allies-only visibility tier don't interact — the former is discoverability, the latter is per-goal ally access. (Previously updated 2026-07-21 for §7, per-goal partner sharing v4.10.)

Loading…