Skip to content

Backend Architecture

The backend is a Rails 8.1 API application running on PostgreSQL with Solid Queue for background jobs.

Rails Conventions

The app follows standard Rails conventions with a few project-specific patterns:

  • API-only mode -- No views, sessions, or cookies. All responses are JSON.
  • Namespaced controllers -- All API controllers live under Api::V1:: and inherit from BaseController, which provides authenticate_user! and current_user.
  • ApplicationController vs BaseController -- ApplicationController is the Rails default. BaseController adds JWT authentication. Controllers that need unauthenticated access (like webhooks) skip the before action.

Service Objects

Complex business logic is extracted into service objects under app/services/:

ServicePurpose
Ai::TaskParserCalls Claude Haiku to parse NL into task fields
Ai::TaskEditorCalls Claude Haiku to parse NL edit instructions
Ai::SuggestionGeneratorGenerates proactive task suggestions
JwtServiceEncodes/decodes JWT tokens (access + refresh)
ExpoPushServiceSends push notifications via Expo Push API
DeepgramServiceGenerates temporary Deepgram API keys
RevenuecatServiceSyncs subscription state from RevenueCat

Background Jobs (Solid Queue)

Solid Queue is configured as the default queue adapter. Jobs are stored in the database, eliminating the need for Redis.

JobTriggerPurpose
WeeklyDigestJobCron (Sunday, via recurring.yml)Sends weekly summary push notification
SendPushNotificationJobEnqueued by other jobs/servicesDelivers a push notification via Expo API
SyncSubscriptionJobEnqueued by webhook or manual syncSyncs user tier from RevenueCat

Cron schedules are defined in config/recurring.yml.

Database Schema Overview

Key tables:

TablePurpose
usersAuth, subscription tier, points, streak data
tasksCore task data with recurrence, reminders, assignment
task_completionsOne row per completion event (for streaks/stats)
categories8 predefined categories (seeded)
householdsFamily groups with invite codes
device_tokensExpo push tokens per user/device
pomodoro_sessionsFocus timer sessions (per task)

Key relationships:

  • A Task belongs to a User (creator) and optionally to an assigned_to user and a Household
  • A User optionally belongs to a Household
  • A Household has an owner (User) and many members (Users)

Structured Logging

Lograge is configured (config/initializers/lograge.rb) to output structured JSON logs. Each request log includes:

  • HTTP method, path, status, duration
  • Controller, action
  • User ID (from JWT)
  • Request parameters (filtered)

Monitoring

New Relic APM is configured via config/newrelic.yml for production performance monitoring.

Security

  • Brakeman for static security analysis
  • Bundler Audit for dependency vulnerability scanning
  • RuboCop for code style enforcement
  • All three run in CI before merge

Internal documentation — not for public distribution