Skip to content

Activity Nexus — PRD (Penny-proposed, Josh-greenlit)

Product: Objectuve (codename: Enkidu) Feature bundle: Connected Apps integration hub (Strava + Chess.com) with auto-mapping and idempotent check-ins Status: Shipped — built and merged to master 2026-08-03 (v4.14, narrative); not yet live to users — connected_apps_enabled flag at 0% pending Strava provisioning (B1–B3) Date: 2026-04-30 Proposer: Penny (Product Lead, feasibility study OBJ-44) PRD file: docs/product/completed/activity-nexus-prd.mdConfidence: Medium (concept strong, API landscape narrower than original ask)


1. Problem Statement

Users who already track fitness on Strava or hold streaks on Chess.com must re-enter the same data as Objectuve habit check-ins. Every redundant log-in is friction that breaks streaks and removes the people most likely to thrive — those already building activity habits elsewhere — from Objectuve's daily loop.

Specific gaps:

  • Strava users log a 10-mile run but must also check a "Morning Run" habit in Objectuve to count toward their goal. Two systems, two taps, one source of truth.
  • Chess.com players rack up games but don't link that activity to their "Play Chess" streak in Objectuve.
  • Duolingo streaks (the original ask) have no official API and present ToS risk — not feasible via public channels.
  • Fitbit is deprecated September 2026; the direct replacement is Google Health API, which Objectuve doesn't yet support.

The core opportunity: eliminate the double-entry by importing activity data and auto-checking the matching habits. This surfaces as a first-class "Connected Apps" surface, not a one-off integration.


2. Goals & Success Metrics

Primary Goals

  1. Reduce friction for multi-tracker users — users who already log elsewhere should not have to re-enter data in Objectuve to maintain streaks.
  2. Increase goal completion rate (north star) among users with active integrations by automating check-ins they would manually enter anyway.
  3. Build integration framework for future providers — first with Strava + Chess.com (MVP), but designed reusable for Apple Health, Google Health, Garmin (post-partnership) without rewrites.
  4. Demonstrate integration value for roadmap prioritization — if adoption is strong, integrations move from Year 3 to Phase 6 (concurrent with Teams monetization).

Success Metrics

MetricTargetMeasurement
% of users who connect at least one provider8–15% (typical onboarding feature adoption)Connected apps / active users
% of connected-app activities auto-checked85%+Auto-checked / total eligible activities (Strava runs, Chess.com games)
Avg goal completion rate (connected users vs. control)+8–12ppCohort comparison post-launch
% of users who disconnect within 30 days<20% (low churn = trust in mapping)Disconnections / connections at 30d mark
Activity feed impression ("via Strava" marker)50%+ of daily active users see itAnalytics on activity_feed events tagged source: integration
Strava OAuth completion rate75%+ (Capacitor browser handoff)OAuth grants / OAuth start attempts

Guardrails

  • Free tier feature — no paywall. Activity integration is free for all users. (See MISSION.md value #3, #5.)
  • Auto-check-in is confident, not silent — first connect surfaces explicit mapping review; subsequent new habits in matching categories are proposed (toast + link to settings), never silently checked in.
  • Credential security — encrypted token storage (Rails 7+ ActiveRecord::Encryption); tokens never logged or exposed in error messages.
  • ToS compliance — Strava GPS data requires Privacy Policy + ToS updates before any public launch. Internal/QA use allowed pre-update.
  • Idempotent check-ins — same activity can't double-check a habit. Check-in keyed on (goal_id, completed_date, integration_provider_id) uniqueness.
  • Graceful degradation — if a provider API is down, no check-ins are queued; users see a "Connection paused" message in settings, not an error on Dashboard.

3. User Stories

  1. As a user with active Strava, I want to authorize Objectuve to read my activities, so that my fitness runs automatically check my habits without me manually re-entering.
  2. As someone new to Connected Apps, I want to review a confidence-scored mapping of my Strava activities to my habits before confirming, so I trust the auto-check-ins and don't worry about mismatches.
  3. As a user who built a Chess.com streak, I want my daily games to auto-check my "Play Chess" habit, so I maintain my Objectuve streak without extra work.
  4. As a user concerned about privacy, I want to see exactly what data Objectuve imports and disconnect any time, so I control my integration footprint.
  5. As a user whose integration breaks, I want a clear "Connection paused" message in settings, not a silent failure, so I can troubleshoot and reconnect.

4. Feasibility & API Landscape (Penny's Research)

Feasibility Score: 7 / 10

DimensionScoreNotes
Technical complexity6/10OAuth flows + data normalization are real work; no integration framework exists yet in the Rails API
API availability7/10Strava and Chess.com are easy wins; Fitbit is deprecated Sept 2026; Duolingo has no official API
Market value9/10Integration hubs are proven retention drivers — reduces double-logging friction
North-star alignment9/10Auto check-ins → habits completed → goals completed. Direct.
Enkidu fit7/10Habits + recurrence are already there; need: integration framework, OAuth UI, auto-check-in logic
Roadmap timing5/10Integrations are Year 3; pulling forward is a deliberate choice

Supported Providers (MVP)

ProviderStatusVerdictMVP Priority
Strava✅ OAuth 2.0, free tier, well-documentedWebhook-driven, real-time activity ingestionMVP
Chess.com✅ Public REST API, no auth requiredDaily polling, zero auth frictionMVP
Google Health API✅ Active — correct Fitbit replacementPost-MVP (framework supports it)Phase 2
Apple HealthKit✅ iOS native via CapacitorPost-MVPPhase 2
Fitbit⚠️ Deprecated Sept 2026Skip; use Google HealthNot supported
Garmin Connect⚠️ Business partnership requiredPost-MVPPhase 3
Duolingo❌ No official API, ToS riskDo not build (use Chess.com instead)Not supported

Critical finding (Penny): Duolingo has no official public API. Reverse-engineered community packages exist but violate Duolingo's ToS and are unsupported/fragile. Decision (Josh): Accept Chess.com as the streak-app substitute — fully public, zero auth, zero ToS risk.


5. MVP Scope (Josh's Direction)

What Ships in MVP

5.1 Strava Integration

  • OAuth 2.0 authorization (Capacitor in-app browser, callback via deep link)
  • Webhook subscription (real-time activity ingestion from Strava)
  • Activity normalization (Activity domain model with type, duration, distance, timestamp)
  • Mapping: Strava activity_type (run, cycle, swim, etc.) → Objectuve goal_category (fitness)

5.2 Chess.com Integration

  • Public REST API adapter (no auth)
  • Daily poller (Crono job at 02:00 UTC, fetches previous day's games)
  • Activity normalization (game count, timestamp)
  • Mapping: "player has games on date X" → Objectuve goal_category (games)

5.3 Smart Auto-Mapping Engine

  • Confidence-scored proposals on first connect (≥0.85 auto-check, 0.50–0.85 propose, <0.50 ignore)
  • Mapping review modal — user accepts, edits, or dismisses proposed matches
  • One-tap mapping management — Settings → Connected Apps → [Provider] → Manage Mappings
  • Toast notification on auto-map — "New habit detected: [habit name]. Linked via Strava. [Edit]"

5.4 Connected Apps Settings Surface

  • List of connected providers with status (connected, paused, error)
  • OAuth handoff for each provider
  • Disconnect (with confirmation)
  • View mapping details per provider
  • Re-run mapping review

5.5 Activity Feed Integration

  • Imported activities visibly attributed — "Checked in via Strava" pill on GoalEventCard
  • GoalEvent#source enum (manual | integration) to distinguish user-entered from imported
  • Analytics: track impression + tap-through rate on provider attribution

5.6 Documentation & ToS

  • User-facing docs: docs/features/connected-apps.md (how to connect, what data we access, how to disconnect)
  • Privacy Policy update (Termly): section on activity data import from Strava
  • ToS update (Termly): clause on third-party data ingest and retention
  • Release notes highlighting integration as free feature

What's Out of Scope (MVP)

  • Apple Health, Google Health, Garmin — Phase 2+ (framework designed for them, not built)
  • Bidirectional sync — Objectuve → Strava (sync check-ins back to Strava). One-way import only.
  • Goal progress updates — Only habits auto-check-in; goal progress (% toward monthly target) stays manual for now
  • Custom activity types — Only Strava's built-in types + Chess.com games mapped; no user-defined "other activity" type
  • Retroactive sync — Sync starts from connection date; historical data before connection date is not imported

6. Feature Design (High-level — UI-SPEC After Greenlight)

6.1 OAuth Flow (Strava)

  1. Settings → Connected Apps → "Connect Strava"
  2. Tap → Capacitor.Browser.open(strava_oauth_authorize_url) (in-app browser)
  3. User logs into Strava, grants permission
  4. Redirect to objectuve://strava/callback?code=...&state=...
  5. Capacitor browser closes
  6. Deep-link handler exchanges code for access token (backend POST /integrations/strava/authorize)
  7. Mapping review modal surfaces (unless user opts to skip)
  8. Token stored encrypted in IntegrationConnection record

6.2 Mapping Review Modal (First Connect)

  • Header: "Link your Strava activities to habits"
  • Proposed mappings table: (confidence score, activity type, → Objectuve habit, [Accept] [Edit] [Dismiss])
  • Help text: "High confidence (85%+) means we're confident; medium confidence means double-check this. You can change mappings anytime in settings."
  • Buttons: [Accept All] [Custom] (deep dive per mapping)
  • Confirmation state: "✓ 3 mappings linked. Your fitness activities will auto-check habits."

6.3 Connected Apps Settings Surface

List view:

  • Provider card per connected provider
  • Status badge (Connected / Paused / Error / Authorizing)
  • "Last sync: 2 hours ago" timestamp
  • [Disconnect] button (confirmation modal)
  • [Manage Mappings] link

Manage Mappings view:

  • Table: Strava activity type | Auto-check habit | [Edit] [Remove]
  • [+ Add Mapping] button
  • [Re-run Auto-Mapping] button (surfaces new mapping suggestions)

6.4 Activity Feed Attribution

  • Event card shows: "You checked in: Morning Run (via Strava) — 10 miles, 58 min"
  • Strava pill color: Strava orange (#fc5200), subtle background
  • Chess.com pill: Chess.com gradient, subtle background
  • Tap pill → attribution details (activity timestamp, synced data)

6.5 Disconnection & Error States

  • Disconnect: Confirm modal — "Remove Strava connection? Past check-ins stay, but future activities won't sync."
  • Paused state: "Your Strava connection paused. [Reconnect]" (user reconnects via OAuth, not manual token re-entry)
  • API error: "Strava sync failed. Check your connection and try [Retry]. Or [Disconnect]."

7. Technical Overview (Orion's Epic Plan)

7.1 Data Model

IntegrationProvider
  - provider_slug (Strava, Chess.com, GoogleHealth, etc.)
  - name, logo_url, description
  - auth_type (oauth, api_key, none)

IntegrationConnection
  - user_id, provider_id
  - access_token, refresh_token, token_expires_at (encrypted)
  - status (active, paused, error)
  - synced_at (last successful activity fetch)

HabitIntegrationMapping
  - user_id, integration_connection_id, goal_id (habit)
  - provider_activity_type (Strava.run, Chess.com.game, etc.)
  - confidence_score (0–1, used during proposal)
  - auto_check_enabled (boolean, user can disable per mapping)

IntegrationActivity
  - integration_connection_id, provider_activity_id, goal_id
  - activity_type, duration_minutes, distance_km, timestamp
  - checked_at (when auto-check-in happened, if any)
  - idempotency_key (provider_id, provider_activity_id, date) → prevents double-checks

7.2 Adapter Pattern

ruby
# lib/integration_provider/adapter.rb (abstract base)
class IntegrationProvider::Adapter
  def authorize_url(state:) # OAuth start → raises NotImplementedError
  def exchange_code(code:) # OAuth callback, returns tokens
  def fetch_recent_activity(connection:) # Returns array of normalized activities
  def verify_signature(request) # Webhook security (Strava specific)
end

# lib/integration_provider/strava.rb
class IntegrationProvider::Strava < IntegrationProvider::Adapter
  # Implementation of above methods
end

7.3 Interaction Layers

Integrations::AuthorizeConnection
  - Takes: provider_slug, oauth_code, user_id
  - Returns: IntegrationConnection record

Integrations::FetchAndMapActivities
  - Polls provider API or receives webhook
  - Calls Integrations::MapIncomingActivity for each activity
  - Calls Integrations::AutoCheckIn if confidence ≥ threshold

Integrations::MapIncomingActivity
  - AI-powered: analyzes activity description + user's habits
  - Returns: confidence score + proposed habit match

Integrations::AutoCheckIn
  - Wrapper around GoalTracking::CheckInHabit
  - Idempotent on (goal_id, completed_date, integration_provider_id)
  - Publishes domain event: integrations.activity_checked_in

7.4 Strava Webhook Receiver

POST /webhooks/strava
  - Signature verification (Strava HMAC-SHA256)
  - Parse activity subscription event
  - Enqueue `IngestionJob` (async)
  - Return 200 OK immediately

7.5 Chess.com Polling Job

ruby
# Crono schedule: 02:00 UTC daily
class IntegrationProvider::Chess::PollActivityJob
  - For each connected Chess.com user:
    - Fetch user's public games from "yesterday" (user's local timezone)
    - Dedupe vs. IntegrationActivity records
    - Call Integrations::FetchAndMapActivities

7.6 Confidence Scoring Algorithm

First-pass scoring (heuristic-based):

  • Rule 1: activity_type matches goal_category — graded by match quality, not binary:
    • Exact match (activity_type maps 1:1 to the goal's category, e.g. Strava run/ride/swim/walk, or any Chess.com chess_<time_class> game) → 0.80 confidence
    • Partial/family match (activity_type only loosely implies the category, e.g. a generic Strava workout) → 0.55 confidence
    • No relationship → 0.0
  • Rule 2: Activity timestamp matches user's typical check-in time → +0.05
  • Rule 3: Goal has existing check-ins from same day → +0.05 (but capped at 0.95, avoids double-entry)
  • Rule 4: User has historically checked this habit on this day of week → +0.05

A bare exact category match with no other corroborating signal (e.g. a user's first-ever synced activity, before any check-in history exists) lands at 0.80 — surfaced for one-tap review, not silently auto-checked. This is intentional: "confident, not silent" (see A2 below) means the flagship first-connect review experience only fires once corroboration, not just a category match, earns auto-check.

Thresholds (tunable post-launch):

  • ≥ 0.85 → Auto-check without user review
  • 0.50–0.85 → Propose via toast notification + modal
  • < 0.50 → Ignore (don't surface or check)

Tuning: Post-launch, track false-positive rate (user edits / deletes auto-checks) and adjust thresholds in IntegrationConfiguration table.


8. Assumptions (Call Out If Wrong)

  • A1. Activity Nexus is a first-class product surface, not a bolt-on. The Phase 1 framework is reusable for future providers without architectural rewrites.

  • A2. Smart auto-mapping = confidence-scored proposal with accept/edit/dismiss, NOT silent zero-touch auto-mapping. First connect surfaces explicit review; new habits are proposed (toast), never silently checked.

  • A3. Strava uses webhooks for real-time activity ingestion. Chess.com uses daily poller. No new infra component needed; existing Sidekiq + Crono sufficient.

  • A4. Encrypted credential storage uses Rails 7+ ActiveRecord::Encryption (no third-party gem). Keys via Rails credentials / GCP Secret Manager.

  • A5. goal_category table will get a new games row (or similar) via seed migration to host Chess.com mappings. Fitness category already exists.

  • A6. Auto-check-ins reuse GoalTracking::CheckInHabit interaction (idempotent on (goal_id, completed_date)). We tag the resulting GoalEvent with source: integration so the feed can show "via Strava."

  • A7. User's time_zone is reliably populated (set in onboarding wizard or migrated from legacy system). If unset, Chess.com polling falls back to UTC with a TODO comment (precedent: GeneratePartnerMissedDayAlertsJob).


9. Open Questions (Resolve Before Phase 1 Dispatch)

QuestionResolution pathBlocker?
Strava rate limits (200 req/15min, 2000 req/day on free tier) — becomes constraint at ~5K connected users.Apply for "increased rate limits" before public launch (tracked in Phase 6 release task).No — document as A3 in release notes
Chess.com timezone handling — API returns UTC months; we compute "yesterday" in user's local TZ. Is User#time_zone always set?Verify onboarding sets it; if not, add fallback (UTC + TODO). Phase 3 task includes guard.No — has fallback
Confidence threshold tuning (currently 0.85/0.50/<0.50) — should these numbers be different?Post-launch, monitor false-positive rate (user-deleted auto-checks) and adjust. Phase 4 task makes them constants.No — has post-launch adjustment plan
iOS deep-link callback (Capacitor in-app browser closes on custom URL scheme).Confirm @capacitor/browser handles objectuve://strava/callback. Risk: low (well-trodden pattern).No — Phase 2 task includes verification
Strava redirect_uri for OAuth (sandbox vs. prod).Use ENV['STRAVA_REDIRECT_URI'] (different per environment). Phase 1 task includes configuration.No — standard OAuth practice

10. Risks & Mitigations

RiskSeverityMitigation
Mis-mapped auto-check-ins erode trustHighConfidence threshold + mandatory user confirmation on first connect. Never silent.
Webhook spoofing (Strava)HighStrava signs webhooks; Phase 1 task includes signature verification. Reject unsigned events with 401.
Token leak via logsHighUse Rails encrypted attributes AND filter :access_token, :refresh_token in logging config. Phase 1 includes this.
API credentials in GitHighAll secrets via config/credentials.yml.enc and GCP Secret Manager. Never commit plaintext.
Strava ToS breach (GPS data)MediumPhase 6 release task gates feature behind Privacy Policy + ToS update (Termly required).
Integration breaks post-launch, user confusionMediumClear "Connection paused" status + [Reconnect] button. No silent failures.
Rate limit exceeded, integrations queue silentlyMediumGraceful degradation: failed fetches log warning + emit alert (Sentry), do not queue check-ins.
User deletes habit after mapping, integration tries to check non-existent goalLowAutoCheckIn validates goal exists; fails gracefully with warning log, does not fatal.
Timezone ambiguity (Chess.com)LowFallback to UTC if User#time_zone unset. Documented in code comment.

11. Feature Design (PBC & Brand Check)

Free Tier Impact

Extends free tier. Activity integration is fully free. No paywall, no gating to Supporter tier.

Engagement vs. Goals (North Star)

Targets goals-completed (the north star) by automating check-ins users would manually enter anyway. Does NOT increase session length or notification volume. One-tap activity discovery, then users leave.

Dark-Pattern Check

Confirmed clean. Auto-check-ins only happen for activities the user already created in another app (Strava run, Chess.com game). Not a phantom engagement hook. Attribution ("via Strava") is transparent.

Anti-Addictive Philosophy

Aligns. Reduces the need to open Objectuve. Users with active integrations open less because progress happens automatically — the goal is fewer sessions, same or better outcomes.


12. Phase Breakdown (6 Phases, 6–10 Weeks AI Execution)

PhaseTitleOwner MixOutcomeEstimated size
53Integration Framework FoundationCodi (be) + DoriIntegrationProvider, IntegrationConnection, HabitIntegrationMapping, IntegrationActivity models + adapter pattern + GraphQL surface + architecture docLarge
54Strava Integration (backend)Codi (be)OAuth flow, webhook receiver, Strava::Adapter, ingestion pipeline, 80% spec coverageLarge
55Chess.com Integration (backend)Codi (be)Public REST adapter, Crono poller, daily aggregation, 80% spec coverageMedium
56Smart Auto-Mapping EngineCodi (be)Integrations::MapIncomingActivity interaction with confidence scoring, Integrations::AutoCheckIn (idempotent wrapper), GoalEvent#source enum + feed-marker glueLarge
57Connected Apps Settings UIDesi → Codi (fe)UI-SPEC + Vue surface for connect/manage/map; activity feed marker; Storybook stories; Cypress smokeLarge
58ToS, Privacy & ReleaseDori + Codi (release)Termly Privacy Policy + ToS updates; user-facing Connected Apps docs; CHANGELOG; feature-flag staged rampMedium

Total estimated AI execution time: 6–10 weeks (matching Penny's estimate for the epic once greenlit).


13. Test Strategy

Backend (RSpec + SimpleCov ≥80%)

  • Model validations/associations + uniqueness constraints
  • Interaction success + failure paths + side effects (job enqueuing)
  • GraphQL request specs for new queries + mutations
  • Webhook signature verification
  • Encrypted-attribute round-trip test
  • OAuth code → token exchange
  • Idempotency (same activity can't double-check)

Integration Tests (VCR cassettes)

  • Strava OAuth flow (with sandbox credentials)
  • Chess.com player profile + games-archive fetch
  • Webhook payload parsing + verification

Frontend (Vitest ≥80%)

  • Connected Apps list component (status badges, disconnect button)
  • Mapping review modal (confidence scores, accept/edit/dismiss)
  • Activity feed marker rendering (pill styling, attribution)
  • OAuth flow initiation (Capacitor browser open)

E2E / Smoke (Cypress)

  • Connect mock Strava provider, verify Connected Apps surface lists it
  • Disconnect, verify removal
  • (Real OAuth handoff stubbed via cy.intercept())

Manual QA (Pre-release)

  • Phase 57 mobile build with sandboxed Strava app
  • Known Chess.com username test account
  • Activity feed impression on mobile (pill rendering)

14. Dependencies & Ordering

  • Phase 53 must complete before 54, 55, 56 (foundation models + adapter pattern)
  • Phase 54 & 55 are parallelizable once 53 lands (independent adapters)
  • Phase 56 depends on 54 & 55 (MapIncomingActivity needs both adapters implemented)
  • Phase 57 depends on 53, 54, 55, 56 (UI surfaces framework outputs)
  • Phase 58 depends on 57 (needs working UI to document)

Suggested dispatch order: 53 (foundation) → 54 + 55 (parallel) → 56 → 57 → 58


15. Implementation Notes (For Codi During Phases 53–58)

Idempotency Strategy

Every imported activity must be idempotent to prevent double-checks. Use a composite key:

ruby
IntegrationActivity.find_or_create_by!(
  integration_connection_id: connection.id,
  provider_activity_id: strava_activity[:id],  # Strava's internal activity ID
  completed_date: activity_date
)

If the same Strava activity arrives twice (webhook retry, re-poll), the second find_or_create_by! returns the existing record — no second check-in.

Token Refresh

Strava tokens expire. On 401 response, refresh via Strava's refresh_token:

ruby
def refresh_access_token(connection)
  response = Strava::Client.post('/oauth/token', body: {
    client_id: ENV['STRAVA_CLIENT_ID'],
    client_secret: ENV['STRAVA_CLIENT_SECRET'],
    grant_type: 'refresh_token',
    refresh_token: connection.refresh_token
  })
  connection.update!(
    access_token: response[:access_token],
    refresh_token: response[:refresh_token],
    token_expires_at: response[:expires_at]
  )
end

Error Handling & Graceful Degradation

If a Strava webhook fails or a Chess.com poll times out, never queue a check-in. Instead:

  1. Log the error to Sentry
  2. Set connection.status = 'error'
  3. Emit a Sentry alert
  4. User sees "Connection paused. [Reconnect]" in settings

They must manually reconnect (re-do OAuth) to resume.

Staging & Production Credential Separation

yaml
# config/credentials/staging.yml.enc
strava:
  client_id: "staging-app-id"
  redirect_uri: "https://staging.objectuve.app/oauth/strava/callback"

# config/credentials/production.yml.enc
strava:
  client_id: "prod-app-id"
  redirect_uri: "https://objectuve.app/oauth/strava/callback"

Access in code: ENV['STRAVA_CLIENT_ID'] or Rails.application.credentials.strava.client_id


16. Rollback Strategy

All phases land behind a activity_nexus_enabled feature flag (reuses Feature Switches infra from item #37, already on roadmap). If needed:

  1. Disable flag → No Connected Apps UI rendered, no webhooks processed (early-exit guard), no polling jobs run.
  2. Existing manual check-ins unaffected (they use the standard GoalTracking::CheckInHabit interaction).
  3. Rollback time: <5 minutes (flag flip via admin dashboard).

17. Suggested Routing (Post-Greenlight)

Orion to plan as Phase 53–58 milestone on the roadmap (epic, 6 phases).

Josh to confirm version number (originally proposed v1.12; align with current in-flight versions before committing).

Maggie to dispatch Phase 53 task package to Codi (foundation models first, specs/docs parallelizable).

Riley to bundle all 6 phases into one PR per phase on the milestone branch (gsd/v1.12-activity-nexus or equivalent) — phases merge sequentially as Vicki ships.


18. References & Evidence


Appendix: FAQ

Q: Why not use Duolingo? A: No official public API. Community reverse-engineered packages violate ToS and are fragile. Chess.com is the safe substitute — fully public, no auth, strong market fit (chess learners overlap with habit-builders).

Q: Why is Fitbit not supported? A: Fitbit is deprecated September 2026. Google Health is the official replacement. It's on the roadmap for Phase 2, after MVP validates the integration framework.

Q: What if a user breaks an Objectuve habit and the integration tries to check it? A: AutoCheckIn validates goal exists. If goal is deleted, it fails gracefully (warning log, Sentry alert) and does NOT create a dangling event. This is tested in Phase 54 (Strava) and Phase 55 (Chess.com) spec suites.

Q: Can I export my data (Strava runs) from Objectuve later? A: This PRD does not include data export. One-way import only. Export is a separate feature proposal if needed post-launch.

Q: What about Apple Watch or Garmin devices? A: Apple Health is planned for Phase 2 (leverages Capacitor's existing HealthKit plugin). Garmin requires a business partnership; we'll apply if integration adoption is strong. See Phase 2+ roadmap.

Q: How long are activity records kept? A: IntegrationActivity records follow the same retention as GoalEvent records. Soft-delete (paranoia) applies. See docs/operations/data-retention.md for specifics (outside this PRD's scope).


Status: Ready for Epic Scoping

This PRD captures Penny's research, Orion's epic plan, and Josh's decisions. When Josh decides to begin Activity Nexus work, Maggie routes this PRD + OBJ-44 to Orion to invoke /gsd-new-milestone and start Phase 53 dispatch.

Last updated: 2026-08-02

Loading…