Quantified Self is an open-source platform for collecting, analyzing, and visualizing fitness and health data. It combines activity imports and connected fitness services with dashboards, training insights, route tools, sleep trends, and detailed workout analysis.
Try the hosted app at quantified-self.io.
- Import activity files in FIT, GPX, TCX, JSON, and SML formats.
- Connect Garmin, Suunto, COROS, and Wahoo for supported activity, route, sleep, and history workflows.
- Explore configurable dashboards, training readiness, load trends, power curves, intensity zones, laps, and durability metrics.
- View activities and saved routes with Mapbox-powered maps and route tools.
- Compare recordings from multiple devices, share selected activities, and export your data.
- Generate optional AI-assisted activity insights.
| Area | Technology |
|---|---|
| Frontend | Angular 20, Angular Material, RxJS |
| Backend | Firebase Auth, Firestore, Functions, Storage, Hosting, App Check, and Remote Config |
| Visualization | ECharts and Mapbox GL JS |
| Activity parsing | @sports-alliance/sports-lib |
| Testing | Vitest and Firebase Rules Unit Testing |
The main repository areas are:
| Path | Purpose |
|---|---|
src/app/ |
Angular application, routes, components, and browser services |
functions/src/ |
Firebase Functions, queues, integrations, and scheduled jobs |
shared/ |
Contracts and helpers shared by the browser and Functions runtimes |
extensions/ |
Firebase Extension configuration |
docs/ |
Architecture, product rules, and operational documentation |
| Repository root | Firebase rules, indexes, Hosting configuration, and build tooling |
For the frontend and the repository's CI-compatible workflow, install:
- Git.
- Node.js 20.19 or later in the Node 20 line. The committed
.nvmrcselects Node 20, sonvm useis the easiest way to match CI. - npm, which is included with Node.js.
- A Mapbox public access token for maps and geocoding.
For Firebase emulators and Rules tests, also install:
- Firebase CLI.
- Java 21, matching the CI environment.
Note
functions/package.json declares Node.js 22 as the Cloud Functions runtime. Installing Functions dependencies under Node 20 may show an engine warning. Use Node 22 when developing or deploying Functions runtime behavior; the root .nvmrc remains the frontend and CI default.
git clone https://github.com/jimmykane/quantified-self.git
cd quantified-self
nvm use
npm ci
npm --prefix functions ciThe root application and Functions use separate lockfiles, so both installs are required for the full development workflow.
The local Angular build expects a file that is intentionally excluded from Git. Create src/environments/mapbox-token.local.ts with your own public token:
export const mapboxAccessToken = 'YOUR_PUBLIC_MAPBOX_TOKEN';Do not copy a maintainer token or commit this file. A valid token is required for map and geocoding features.
Warning
The current development configuration is hybrid, not fully isolated. Callable Functions are routed to the Functions emulator, but browser Auth, Firestore, Storage, Analytics, App Check, and Remote Config still use the configured hosted Firebase project. Starting additional emulators does not connect those browser SDKs automatically.
Use a dedicated development Firebase project and test account for authenticated work. Do not perform writes until you have confirmed which project the browser is using. Credentials placed in functions/.env can also call real provider APIs, and Cloud Tasks uses its configured external API unless a task emulator host is supplied.
In the first terminal:
npm --prefix functions run build
firebase emulators:start --only auth,functions,firestore,storageThe Functions emulator loads compiled output from functions/lib, so the build must finish before the emulators start.
In a second terminal:
npm run start:functions:emu -- --ssl=falseOpen:
- Application: http://localhost:4200
- Firebase Emulator UI: http://localhost:4000
The --ssl=false override provides a predictable fresh-clone path without relying on a local trusted certificate. If you need HTTPS for an integration flow, generate and trust your own localhost certificate rather than reusing or sharing private key material.
Public pages such as /, /help, /integrations, and /tools/compare are useful first smoke tests. Authenticated flows additionally require correctly configured Firebase Auth providers, authorized domains, and App Check settings.
npm start and npm run start:functions:emu start Angular only; neither command starts Firebase emulators. Avoid npm run start:functions:prod during normal contributor work because it routes callable requests to the configured hosted Functions.
functions/.env is ignored and is not required to install dependencies, build the code, or run unit tests. Add only the credentials needed for the integration you are developing.
| Feature | Configuration names |
|---|---|
| Garmin | GARMINAPI_CLIENT_ID, GARMINAPI_CLIENT_SECRET, GARMINHEALTHAPI_CONSUMER_KEY, GARMINHEALTHAPI_CONSUMER_SECRET |
| Suunto | SUUNTOAPP_CLIENT_ID, SUUNTOAPP_CLIENT_SECRET, SUUNTOAPP_SUBSCRIPTION_KEY, SUUNTOAPP_NOTIFICATION_SECRET |
| COROS | COROSAPI_CLIENT_ID, COROSAPI_CLIENT_SECRET |
| Wahoo | WAHOOAPI_CLIENT_ID, WAHOOAPI_CLIENT_SECRET, WAHOOAPI_WEBHOOK_TOKEN, optional WAHOOAPI_ALLOWED_FILE_HOSTS |
| Stripe | STRIPE_SECRET_KEY or STRIPE_API_KEY |
| AI Insights | GEMINI_API_KEY |
| Backend Mapbox access | MAPBOX_ACCESS_TOKEN |
| Optional task emulator | CLOUD_TASKS_EMULATOR_HOST |
| Release source maps | SENTRY_AUTH_TOKEN |
Never commit environment files, service-account JSON, API tokens, private keys, decrypted credentials, personal data, or production exports. Emulator code can still reach external services when real credentials are configured.
| Purpose | Command | Notes |
|---|---|---|
| Frontend tests once | npm test -- --run |
Deterministic command used by CI |
| Frontend tests in watch mode | npm test |
Keeps Vitest running |
| Frontend coverage | npm run test-coverage |
Writes the coverage report locally |
| Frontend lint | npm run lint |
Angular ESLint |
| Firestore and Storage Rules tests | npm run test:rules |
Uses the isolated demo-test emulator project |
| Frontend build | npm run build |
Development build |
| Production build | npm run build-production |
Builds locally; does not deploy |
| Functions tests | npm --prefix functions test |
One-shot Vitest suite |
| Functions coverage | npm --prefix functions run test:coverage |
Writes the Functions coverage report |
| Functions build | npm --prefix functions run build |
Compiles TypeScript to functions/lib |
| Functions lint | npm --prefix functions run lint |
Runs ESLint with --fix and may edit files |
| Install Git hooks | npm run hooks:install |
Reinstalls the repository Lefthook hooks; npm ci normally installs them automatically |
| MCP pre-push checks | npm run hooks:mcp:pre-push |
Runs the registered-contract gate and focused MCP output/server tests |
| Local plugin tooling | npm run plugin:tools |
Installs the isolated pinned Codex CLI dependency |
| Local plugin setup | npm run plugin:setup |
Explicitly builds, validates, registers, and installs the configured plugin |
| Local plugin validation | npm run plugin:validate |
Uses an isolated temporary Codex profile |
| Local plugin refresh | npm run plugin:sync |
Explicitly rebuilds and reinstalls; normal app builds never do this |
The repository-local Quantified Self plugin bundles the registered read-only MCP app with six discoverable workflows
for cross-domain analysis, training, sleep, body measurements, activities, and saved routes. Configure its
account-specific ChatGPT technical app ID once by setting QS_CHATGPT_APP_ID and running
npm run plugin:configure, then run npm run plugin:setup. Generated app mappings and cache-busted manifests are
ignored. Restart the ChatGPT desktop app after setup or sync, then test in a new conversation. See the
MCP server documentation for the complete lifecycle and update matrix.
The deployment scripts and Firebase aliases in this repository target maintainer-managed environments. Do not run deployment commands against them as part of ordinary contributor setup.
Self-hosting is an advanced workflow rather than a turnkey installation. A fork must provide and review its own:
- Firebase project, client configuration, CLI aliases, Hosting and Storage targets, and indexes.
- Auth providers, authorized domains, redirect URIs, App Check, and Remote Config.
- Function regions, Cloud Tasks queues, buckets, allowed origins, and email URLs.
- Firebase Extension instances and Secret Manager bindings.
- Garmin, Suunto, COROS, Wahoo, Stripe, Gemini, Mapbox, email, and observability credentials used by enabled features.
Audit all project-specific identifiers and domains before deploying a fork. Deployment, publishing, and cloud configuration changes should always be deliberate, separate operations.
The hosted project uses Firestore TTL policies for short-lived operational data:
| Collection | Retention | TTL field | Purpose |
|---|---|---|---|
mail |
About 90 days | expireAt |
Transactional email records |
aiInsightsPromptRepairs |
About 90 days | expireAt |
AI prompt-repair backlog |
failed_jobs |
7 days | expireAt |
Failed background-job records |
*Queue |
7 days | expireAt |
Temporary queue items |
adminStats |
About 1 hour | expireAt |
Admin aggregate cache |
userDeletionTombstones |
Account-deletion retention window | expireAt |
Deletion guards with TTL fallback cleanup |
mcpOAuthAuthorizationRequests / mcpOAuthAuthorizationCodes |
10 / 5 minutes | expireAt |
MCP OAuth consent and single-use codes |
mcpOAuthAccessTokens / mcpOAuthRefreshTokens |
1 hour / 30 days | expireAt |
Hashed MCP bearer and refresh credentials |
mcpOAuthRateLimits |
About 5 minutes | expireAt |
Distributed MCP request counters |
users/*/mcpConnections |
5 minutes while pending | expireAt |
Abandoned MCP approvals; successful exchanges remove the TTL field |
users/*/eventMergeOperations |
7 days after the latest state transition | expireAt |
Event-merge idempotency and reconciliation ledger |
These policies are infrastructure configuration; starting local emulators does not create or deploy production TTL policies.
- Provider integration implementation guide
- Wahoo integration architecture and release checklist
- Training workspace architecture and maintenance
- Read-only MCP server
- Queue processing architecture
- Sleep sync operations
- Email lifecycle
- Firebase Auth link-domain routing
- Connected-provider attribution audit
- Event merge idempotency and recovery
- Pricing and usage limits
- User deletion workflow
Contributions are welcome. Before opening a pull request:
- Keep changes focused and add or update the narrowest relevant tests.
- Run the applicable checks from the table above.
- Use a prefixed commit subject:
feat:,fix:,chore:,refactor:,test:, ordocs:. - Follow the Code of Conduct.
Security-related guidance is available in SECURITY.md.
Quantified Self is licensed under the GNU Affero General Public License v3.0.
Icons by Alessandro.