Objectuve Architecture
The Objectuve repository is structured as a monorepo, consisting of three main applications (rails_api, ionic_frontend, admin_dashboard) and a marketing site (marketing_landing).
System Design Diagram
graph TB
subgraph Clients["Client Layer"]
WEB["🌐 Web Browser<br/><i>app.objectuve.com</i>"]
IOS["📱 iOS App<br/><i>Capacitor</i>"]
ANDROID["📱 Android App<br/><i>Capacitor</i>"]
ADMINUI["🌐 Admin Dashboard<br/><i>admin.objectuve.com</i>"]
end
subgraph Frontend["ionic_frontend — Vue 3 / Ionic 8 / Vite"]
direction TB
ROUTER["Vue Router<br/><i>@ionic/vue-router</i>"]
subgraph Views["Views"]
DASH["Dashboard"]
GOALS["Goals / Goal Detail"]
FEED["Activity Feed"]
COMMUNITIES["Communities"]
ACHIEVEMENTS["Achievements"]
SETTINGS["Settings"]
end
subgraph Composables["Composables"]
USE_AI["useAiInsights<br/>useAiCoach"]
USE_GOAL["useGoalForm<br/>useProgressData"]
USE_FEED["useUnifiedFeed"]
USE_NOTIF["useNotifications"]
USE_CLERK["useClerkSync"]
end
subgraph Components["Component Library (56 stories)"]
HABIT_UI["TodaysHabits<br/>HabitCalendar<br/>HabitCompletionRing"]
CHART_UI["ProgressChart<br/>PaceIndicator<br/>StreakVisualization"]
FEED_UI["FeedItemCard<br/>CheckInPromptCard"]
CORE_UI["GoalGridCard<br/>DashboardHero<br/>ActionHub"]
end
PINIA["Pinia Stores"]
GQL_CONST["graphql/*<br/><i>Context-split queries & mutations</i>"]
APOLLO["Apollo Client<br/><i>BatchHttpLink + ActionCableLink</i>"]
end
subgraph Auth["Authentication"]
CLERK["Clerk<br/><i>RS256 JWT via JWKS</i>"]
end
subgraph Backend["rails_api — Rails 8.1.2 / Ruby 4.0"]
direction TB
GQL_CTRL["GraphqlController<br/><i>POST /graphql</i>"]
CABLE["ActionCable<br/><i>WS /cable</i>"]
subgraph GQL_Layer["GraphQL Layer"]
QUERY_TYPE["QueryType<br/><i>20+ queries</i>"]
MUT_TYPE["MutationType<br/><i>25+ mutations</i>"]
GQL_TYPES["Types<br/><i>GoalType, UserType,<br/>UnifiedFeedType, etc.</i>"]
end
subgraph Interactions["Interactions (Business Logic)"]
GOAL_INT["AddGoal · UpdateGoal<br/>CheckInHabit · UseStreakFreeze"]
PROGRESS_INT["CalculateGoalProgress<br/>BuildUnifiedFeed"]
USER_INT["SignUp · UpdateUser<br/>AddMoodLog"]
NOTIF_INT["SendPushNotification"]
end
subgraph Models["Models"]
USER_M["User<br/><i>PublicRecord</i>"]
GOAL_M["Goal<br/><i>PublicRecord</i>"]
HABIT_M["HabitCompletion"]
EVENT_M["GoalEvent<br/><i>PublicRecord</i>"]
COMM_M["Community<br/><i>PublicRecord</i>"]
MOOD_M["MoodLog<br/><i>PublicRecord</i>"]
end
subgraph Services["Services"]
AI_COACH["Ai::CoachService<br/><i>Langchain gem</i>"]
GAMIFICATION["GamificationService"]
end
subgraph Jobs["Background Jobs (Crono)"]
JOB_STREAK["ProcessHabitStreaksJob<br/><i>daily 08:00</i>"]
JOB_REMIND["GenerateReminderNotificationsJob<br/><i>daily 09:30</i>"]
JOB_AI["GenerateAiCheckInPromptsJob<br/><i>daily 10:00</i>"]
JOB_ACTIVITY["GenerateActivityReminderJob<br/><i>daily 12:00</i>"]
end
JWT_VERIFY["ClerkJwtVerifier<br/><i>RS256 JWKS validation</i>"]
end
subgraph Infrastructure["GCP Infrastructure (us-central1)"]
direction TB
CLOUD_RUN["Cloud Run<br/><i>enkidu-api-production</i>"]
CLOUD_SQL["Cloud SQL<br/><i>PostgreSQL 15</i>"]
FIREBASE["Firebase Hosting<br/><i>enkidu-app</i>"]
ARTIFACT["Artifact Registry<br/><i>enkidu-registry</i>"]
REDIS["Redis<br/><i>Sidekiq + ActionCable</i>"]
end
subgraph External["External Services"]
LLM["LLM Provider<br/><i>OpenAI / Anthropic /<br/>Gemini / Ollama</i>"]
PUSH["FCM / APNs<br/><i>Push Notifications</i>"]
GCS["Google Cloud Storage<br/><i>File Storage</i>"]
SENTRY["Sentry<br/><i>Error Tracking</i>"]
MAILTRAP["Mailtrap<br/><i>Email</i>"]
end
%% Client connections
WEB --> FIREBASE
IOS --> CLOUD_RUN
ANDROID --> CLOUD_RUN
FIREBASE --> APOLLO
%% Frontend internal flow
ROUTER --> Views
Views --> Composables
Views --> Components
Composables --> GQL_CONST
GQL_CONST --> APOLLO
PINIA --> Views
%% Auth flow
CLERK --> USE_CLERK
CLERK --> JWT_VERIFY
APOLLO -- "SessionToken header" --> GQL_CTRL
%% Backend internal flow
GQL_CTRL --> GQL_Layer
CABLE --> GQL_Layer
GQL_Layer --> Interactions
Interactions --> Models
Interactions --> Services
Models --> CLOUD_SQL
Services --> LLM
Jobs --> Interactions
Jobs --> NOTIF_INT
NOTIF_INT --> PUSH
%% Infrastructure connections
CLOUD_RUN --> CLOUD_SQL
CLOUD_RUN --> REDIS
REDIS --> CABLE
REDIS --> Jobs
%% External connections
Backend --> GCS
Backend --> SENTRY
Backend --> MAILTRAP
%% Styling
classDef clientStyle fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
classDef frontendStyle fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20
classDef backendStyle fill:#fff3e0,stroke:#e65100,color:#bf360c
classDef infraStyle fill:#f3e5f5,stroke:#6a1b9a,color:#4a148c
classDef externalStyle fill:#fce4ec,stroke:#c62828,color:#b71c1c
classDef authStyle fill:#fffde7,stroke:#f9a825,color:#f57f17
class WEB,IOS,ANDROID clientStyle
class ROUTER,DASH,GOALS,FEED,COMMUNITIES,ACHIEVEMENTS,SETTINGS,USE_AI,USE_GOAL,USE_FEED,USE_NOTIF,USE_CLERK,HABIT_UI,CHART_UI,FEED_UI,CORE_UI,PINIA,GQL_CONST,APOLLO frontendStyle
class GQL_CTRL,CABLE,QUERY_TYPE,MUT_TYPE,GQL_TYPES,GOAL_INT,PROGRESS_INT,USER_INT,NOTIF_INT,USER_M,GOAL_M,HABIT_M,EVENT_M,COMM_M,MOOD_M,AI_COACH,GAMIFICATION,JOB_STREAK,JOB_REMIND,JOB_AI,JOB_ACTIVITY,JWT_VERIFY backendStyle
class CLOUD_RUN,CLOUD_SQL,FIREBASE,ARTIFACT,REDIS infraStyle
class LLM,PUSH,GCS,SENTRY,MAILTRAP externalStyle
class CLERK authStyle
Reading the Diagram
| Color | Layer | Description |
|---|---|---|
| 🔵 Blue | Client | Browsers and native mobile apps connecting to the platform |
| 🟢 Green | Frontend | Vue 3 / Ionic SPA — views, composables, components, Apollo Client |
| 🟡 Yellow | Auth | Clerk handles all authentication — issues RS256 JWTs verified server-side |
| 🟠 Orange | Backend | Rails API — GraphQL endpoint, interactions, models, background jobs |
| 🟣 Purple | Infrastructure | GCP Cloud Run, Cloud SQL, Firebase Hosting, Redis |
| 🔴 Red | External | Third-party services (LLM providers, push notifications, storage, email) |
Request Flow
User action → Vue Router → View → Composable → graphql.js → Apollo Client
→ POST /graphql (SessionToken header)
→ GraphqlController → QueryType/MutationType → Interaction → Model → PostgreSQL
→ Response → Apollo Cache → Reactive UI updateReal-time Flow
Server event (notification, badge, level-up)
→ UserNotification.generate → ActionCable subscription trigger
→ WS /cable → Apollo subscription → useNotifications composable → Toast/Card UIBackground Job Flow
Crono scheduler (daily at configured times)
→ Job.perform → Interaction (business logic) → Model (database)
→ SendPushNotification → FCM/APNs → Device push notification
→ UserNotification.generate → ActionCable → Live in-app notification├── ionic_frontend/ // Main Mobile/Web Application (Ionic, Vue 3, Vite)
├── admin_dashboard/ // Dedicated Admin Portal (Vue 3, Vite, Tailwind, HeadlessUI)
├── rails_api/ // Backend API (Rails 8, GraphQL)
├── marketing_landing/ // Static Marketing Website
├── docker-compose.yml // Docker orchestration
├── .semaphore/ // CI/CD Configuration
└── ... // Other configuration files1. ionic_frontend — Main Mobile/Web Application
- Framework: Ionic 8 (Vue 3)
- Build Tool: Vite
- Purpose: The primary user-facing application for mobile (iOS/Android) and web. Handles user interaction, data presentation, and state management.
Key Directories
src/views/: Application pages (e.g.,Dashboard.vue,Goals.vue,ActivityFeed.vue,Settings.vue).src/components/: Reusable UI components ensuring consistent design.src/composables/: Vue composables for shared logic (e.g.,useAiInsights.ts,useAiCoach.ts,useProgressData.ts,useUnifiedFeed.ts,useGoalForm.ts).src/stores/: Pinia stores for local state management.src/constants/graphql/: All GraphQL query and mutation definitions (18 modules + barrelindex.js).src/router/: Vue Router configuration.src/theme/: Global styling and theme variables.src/apollo-client.ts: Apollo Client configuration inc. Auth & Subscriptions..storybook/: Storybook configuration, decorators, and mocks.
Key Functionalities
- User Interface: Comprehensive UI for Goals, Communities, Dashboard, and Settings.
- Authentication: JWT-based auth via Apollo Middleware (
SessionTokenheader). - Real-time Updates: Integration with ActionCable for live data (e.g., goal updates).
- Mobile Navigation:
BottomTabBarcomponent handles tab navigation on mobile (≤767px); sidebar handles desktop. - Coach Insights:
useAiInsightscomposable provides context-aware insight cards on every major page with 15-minute caching and 24-hour dismissal persistence. - Mood Tracking:
MoodCheckInmodal lets users log emotional state (6 moods) optionally linked to a goal. - Habit Tracking: Recurring habit goals with one-tap check-in via
TodaysHabitsdashboard widget.HabitCalendarheatmap andHabitCompletionRingprogress indicator on goal detail. - Progress Visualization:
ProgressChartbar chart on goal detail with day/week/month grouping,PaceIndicator(ahead/on track/behind), andStreakVisualizationfor habit goals. - Unified Activity Feed:
/feedview (ActivityFeed.vue) merging ally check-ins, community posts, and own goal events with filter tabs and pagination viaFeedItemCardcomponent. - Check-In Prompts:
CheckInPromptCardon dashboard showing personalized Coach-generated nudges referencing specific goals, streaks, and milestones. - Offline Capability: (Potential via Capacitor/PWA standards).
- Native Integration: Capacitor for accessing native device features (Camera, Haptics).
2. rails_api — Backend API
- Framework: Ruby on Rails 8.1.2 (API Only)
- Language: Ruby 4.0
- Purpose: The central source of truth for data, business logic, and authentication.
Key Directories
app/graphql/: GraphQL schema definitions (types,mutations,resolvers).app/interactions/: Business logic encapsulated in interaction objects (e.g.,AddGoal,SignUp,AddMoodLog,CheckInHabit,CalculateGoalProgress,BuildUnifiedFeed).app/models/: ActiveRecord models for database interaction.app/channels/: ActionCable channels for websocket connections.app/jobs/: Sidekiq jobs for background processing.
Key Functionalities
- GraphQL API: Exposes a rich API for the frontend to consume.
- Authentication: Handles User Sign Up/In and JWT generation.
- Business Logic: "Interaction" pattern ensures clean separation of concerns.
- Background Jobs: Uses Sidekiq/Crono for scheduled tasks (habit streak processing, AI check-in prompts, reminder notifications, past due alerts).
3. admin_dashboard — Admin UI
- Framework: Vue 3 (Vite)
- Library: HeadlessUI, TailwindCSS
- Purpose: A standalone administrative frontend exposing operations securely disjointed from the public app bundle. Provides audit tracking, moderation queues, and user role overrides.
4. marketing_landing — Marketing Site
- Structure: Static HTML/CSS/JS site.
- Purpose: Public-facing landing page for the product.
- Key Files:
index.html,blog.html,css/,js/.
4. Database Layer (PostgreSQL)
- Purpose: Relational database for persistent storage.
- Schema: Managed via Rails Active Record Migrations (
rails_api/db/migrate). - Key Models:
User,Goal,Community,GoalEvent,MoodLog,HabitCompletion.
5. Docker Configuration
- Purpose: Containerization for development and potentially production.
- Key Files:
docker-compose.yml: Orchestratesdb(Postgres),api(Rails), andfrontend.rails_api/Dockerfile.ruby: Dockerfile for the Rails API.
Observability
The application uses a GCP-native + Sentry observability stack:
- Structured Logging: Lograge emits JSON request logs (method, path, status, duration, user_id, graphql_operation) auto-parsed by GCP Cloud Logging
- Error Tracking: Sentry on both backend (Rails) and frontend (Vue) with user context and performance tracing
- Health Check:
GET /healthprobes database, Redis, and Sidekiq — returns component-level status - Performance Metrics: Sentry APM with
GraphQL::Tracing::SentryTracefor query-level traces and frontend web vitals - Alerting: GCP Cloud Monitoring (uptime, latency, error rate, DB metrics) + Sentry (error spikes, new issues)
- Dashboards: GCP Cloud Monitoring (infrastructure) + Sentry (application errors and performance)
For full details, see Observability, Alerting, and Dashboards.
API Endpoints
The application primarily exposes a single GraphQL endpoint, but technically serves:
- POST
/graphql: The main entry point for all queries and mutations. - WS
/cable: WebSocket endpoint for ActionCable subscriptions. - GET
/health: Detailed health check (database, Redis, Sidekiq status). - GET
/up: Simple health check for load balancers.
Key GraphQL Queries
user(id: ID)/users: Fetch specific user or list of users.goal(id: ID)/goals: Fetch goal details or list of goals for a user.publicGoal(id: ID): Fetch limited public details of a goal.community(id: ID)/communities: Fetch community details or browse available communities.goalEvent(id: ID): Fetch details about a specific update/event on a goal.goalKinds/goalCategories: Fetch metadata about available goal types and categories.communitySuggestions: Get recommended communities for the current user.isFollowingGoal(id: ID): Check if the current user follows a specific goal.goalProgressData(id: ID, period?, lookbackDays?): Progress visualization data for a goal (event frequency, pace, streak data).unifiedFeed(limit?, offset?): Paginated unified activity feed merging ally activity, community posts, and own goal events.
Key GraphQL Mutations
signIn/oAuthSignIn: Authenticate user and return session token.signUp: Register a new user.addGoal/updateGoal: Create or modify a goal.addGoalEvent/updateGoalEvent: Post an update to a goal.joinCommunity/addGoalToCommunity: Interaction with communities.updateUser/updateUserPhoto: Modify user profile information.toggleFollowGoal: Follow/unfollow a specific goal.toggleGoalEventEncouragement: "Like" or encourage a goal update.addGoalEventComment: Add a comment to a goal update.addMoodLog(mood, note?, goalId?): Record a mood check-in for the current user, optionally linked to a goal.checkInHabit(goalId): One-tap habit check-in for the current day.useStreakFreeze(goalId): Use a streak freeze to preserve a habit streak.
Key Data Flows
Goal Creation
- Frontend: User submits goal form in
ionic_frontend. - GraphQL: Mutation
addGoalis sent to/graphql. - Rails:
GraphqlControllerreceives request. - Resolver: Delegates to
AddGoalinteraction. - Interaction: Validates input, creates
Goalrecord, potentially triggers background jobs. - Response: JSON payload returned to frontend; cache updated.
Authentication
- Frontend: User signs in via Clerk (email, Google OAuth, or other configured providers).
- Clerk: Issues an RS256 JWT after successful authentication.
- Frontend: Retrieves the JWT via
Clerk.session.getToken()and attaches it as theSessionTokenheader (PascalCase) on every GraphQL request. - Rails:
ClerkJwtVerifierdecodes the token via JWKS.ClerkUserSyncfinds or creates the localUserrecord from the Clerk profile.
Mood Check-In
- Frontend: User opens
MoodCheckInmodal, selects mood and optional goal/note. - GraphQL:
addMoodLogmutation sent withmood, optionalgoalId, optionalnote. - Rails:
AddMoodLoginteraction creates aMoodLogrecord linked to the current user. - Response:
MoodLogpayload returned; modal closes.
Environment Variables
Rails API
DATABASE_HOST,DATABASE_USERNAME,DATABASE_PASSWORD: Database connection.REDIS_URL: Redis connection for Sidekiq/ActionCable.GCP_PROJECT_ID: Google Cloud project ID.GCS_BUCKET_NAME: Google Cloud Storage bucket for media uploads — per-environment, pinned in eachdeploy/*.yamlmanifest (enkidu-storageproduction,enkidu-storage-stagingstaging; see Deployment § Staging wrote live uploads into production's GCS bucket). Uploaded objects carry aCache-Control: public, max-age=300header — see Deployment § Public media Cache-Control for how long a deleted photo stays fetchable and why.MAILTRAP_API_TOKEN: Transactional email delivery.SENTRY_DSN: Error tracking.
Ionic Frontend
VITE_API_URL: URL of the backend API (e.g.,localhost:3000or production URL).- Capacitor configurations for Android/iOS builds.
Features
Organization via Interactions
The backend allows for strict organization by encapsulating every "action" a user can take into an Interaction class (in app/interactions). This keeps controllers and GraphQL resolvers thin and creates a clear directory of all available business capabilities.
Mobile-First Design
The ionic_frontend is built to be deployed as a native app using Capacitor, utilizing native plugins while sharing a single codebase for the web. The BottomTabBar component provides native-feeling tab navigation on mobile and is hidden on desktop where the sidebar takes over.
Real-Time Interactions
ActionCable flows real-time updates to the client, allowing features like "New Goal Feed" or "Live Comments" to update without page refreshes.
Coach Insights System
The useAiInsights composable provides page-scoped contextual insights. Each page (dashboard, goals, goal-detail, achievements, communities, admin) generates an insight based on the user's current data. Insights are cached for 15 minutes at the module level and dismissals persist for 24 hours via localStorage.
Last updated: 2026-08-30 — component-library diagram node renamed MomentumBar → DashboardHero, which superseded it (OBJ-3016).