# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. Flaredown is a chronic-illness symptom tracker. It is a monorepo with three deployable apps: - `backend/` — Rails 7.1 API (Ruby 3.2.3), the only backend for all clients. - `frontend/` — Ember.js 2.18 web app (the production web client at app.flaredown.com), proxies API calls to the backend. - `native/` — Expo / React Native + TypeScript app (newer, in-progress replacement for the Ember client). The root `app/` directory is a stray remnant (single `g-recaptcha.js`), not a fourth app. ## Commands Everything is Dockerized; `make` wraps `docker compose`. Prefer these over running services natively. - `make start` / `make stop` — run the full dev stack (backend + workers + Ember frontend) via the `dev` profile. - `make startNative` / `make stopNative` — run backend + React Native (`native` profile). - `make build` — rebuild the backend image. Do this before running specs if backend code/deps changed. - `make seed` — seed databases (`rails app:setup`). - `make console` — Rails console. - Web app: http://localhost:4300 (Ember). Native: http://localhost:19006. Backend API: http://localhost:3000. ### Tests - All backend specs: `make specs` (equivalently `script/backend rspec spec spec`). - A single spec: `script/backend rspec spec/services/weather_retriever_spec.rb`. The `script/backend` wrapper runs any command inside the backend container (`docker compose --profile dev run --rm backend $@`). - Add `debugger` to Ruby code to break into an interactive shell under rspec. - Frontend (Ember): `cd frontend && npm test` (`ember test`). - Native: `cd native && npm test` (jest), `npm run tsc` (typecheck). ### Lint (all enforced in CI; run before pushing) - Ruby: `script/backend standardrb` (StandardRB, not RuboCop). - ERB: `script/backend erb_lint --lint-all`. - Native: `cd native && npm run lint` (eslint + prettier), `npm run lint:fix` to autofix. CI (`.github/workflows/{backend,frontend,native}.yml`) uses path filters — backend jobs only run when `backend/**` changes, etc. StandardRB, ERB lint, rspec, and frontend build are required for merge. ## Architecture ### Dual database — the most important thing to understand The backend uses **both PostgreSQL and MongoDB simultaneously**, split by data type: - **PostgreSQL (ActiveRecord)** — relational/reference data: `User` (Devise auth), `Condition`, `Symptom`, `Treatment`, `Food`, `Tag`, `Profile`, `Weather`, and the `user_*` join tables. These models subclass `ActiveRecord::Base` and carry a `# == Schema Information` header. Schema lives in `db/schema.rb` + `db/structure.sql`; migrations in `db/migrate/`. - **MongoDB (Mongoid 8)** — high-volume, user-generated, schemaless data: `Checkin` (the core daily symptom/treatment/tag log), `Comment`, `Reaction`, `Pattern`, `Notification`, `HarveyBradshawIndex`, `Feedback`, `PromotionRate`, `OracleRequest`. These `include Mongoid::Document`. Config in `config/mongoid.yml`. The two stores are linked by an **encrypted foreign key**: Mongo documents store `encrypted_user_id` (symmetric-encryption gem, see `config/symmetric-encryption.yml`) rather than a plain `user_id`, and dereference it back to the Postgres `User`. When querying check-in data by user, filter on `encrypted_user_id`, not `user_id`. `Checkin` embeds condition/symptom/treatment sub-documents inline. ### API layer Versioned JSON API under `app/controllers/api/v1/`, routed via `namespace :api { scope module: :v1 }` in `config/routes.rb`. Serialization uses `active_model_serializers` 0.9 (`app/serializers/`). Auth is Devise + `devise_invitable` + Facebook OmniAuth; authorization is CanCanCan with a Mongoid adapter (`app/models/ability.rb`). Business logic lives in `app/services/` (e.g. `weather_retriever`, `pattern_creator`, `chart_list_service`) — controllers should stay thin. ### Background work Sidekiq (`config/sidekiq.yml`, `worker` process in `Procfile`) backed by Redis, with jobs in `app/jobs/` (check-in reminders, data exports, notification dispatch, top-posts mailers). Recurring schedules are defined in `config/cronotab.rb` (Crono) and rake tasks under `lib/tasks/` invoked by Heroku Scheduler. ### External integrations Tomorrow.io (weather, via `tomorrowio_rb`), Pusher (realtime), Geocoder + `nearest_time_zone` (location → timezone for reminders), AWS SES (inbound/bounce handling in `aws_ses_controller`). ## Deployment Heroku, via `rake` tasks in the root `Rakefile`. Frontend and backend are separate Heroku apps deployed with `git subtree split` (`rake production:deploy` / `rake staging:deploy`). Commits to `master` auto-deploy to staging. Postgres/Redis are Heroku addons; MongoDB is hosted at mongodb.com. ## Gotchas - Node is pinned to **12.22.6** for the Ember frontend (`.tool-versions`); the native app uses a modern toolchain independently. Don't assume one Node version across the repo. - Env files: `cp backend/env-example backend/.env` and `cp backend/env-example frontend/.env`. A `FACEBOOK_APP_ID` is needed in `frontend/.env` or the app renders a blank beige screen on first load (see README "Common Problems" for the workaround).