Continuum is a self-hosted, privacy-first dashboard that replaces a pile of single-purpose tracking apps — budget spreadsheet, Letterboxd, Goodreads, subscription reminders — with one place to manage expenses, investment portfolios, media watchlists, book libraries, and recurring subscriptions.
It started as a personal API I fed into a Custom GPT so I could log expenses over chat instead of paying for another app. A friend wanted it too, so instead of handing over my personal API collection I built an actual dashboard around it. It's designed to natively integrate with AI assistants through a standardized OpenAPI schema.
Framework: Next.js 16 (App Router, Turbopack) + React 19 + TypeScript
Styling: Tailwind CSS
Database & Auth: Firebase (Google Sign-In + Firestore REST API)
- Expense ledger with categorized transactions, location-specific currencies, and custom financial-period filtering.
- Investment portfolio tracking across equities, crypto, mutual funds/SIPs, gold, cash, and fixed deposits — manual entry or live valuation.
- Unified media watchlist with bidirectional AniList and Trakt sync, Letterboxd CSV imports, and metadata enrichment via OMDb and TVMaze.
- Book library backed by the OpenLibrary API with reading-progress tracking.
- Subscription tracker that normalizes monthly and annual costs into a true effective monthly spend.
- Auto-saving scratchpad for quick, persistent notes.
- Built-in OpenAPI 3.1 schema for Custom GPT Actions, Gemini Gems, or Claude Projects — add expenses, log media, or update your portfolio in plain English.
- AES-256-GCM encryption on sensitive fields, with no admin service account — every request is authenticated with the caller's own Firebase ID token.
git clone https://github.com/fal3n-4ngel/Continuum-Home.git
cd Continuum-Homenpm install- Create a project in the Firebase Console.
- Enable Google Sign-in under Authentication → Sign-in method.
- Provision a Firestore Database.
- Project Settings → General → Add Web App to generate the config snippet.
- Deploy the security rules that isolate each user's data:
npm install -g firebase-tools
firebase login
firebase use --add
firebase deploy --only firestore:rulescp .env.example .env.localSet FIREBASE_CONFIG as a minified JSON string and pick an encryption key in .env.local:
FIREBASE_CONFIG={"apiKey":"...","authDomain":"...","projectId":"..."}
ENCRYPTION_KEY="your-custom-super-secret-key-phrase"Optional keys for Trakt, AniList, and TMDb can also go here — see .env.example.
Tip
Bring-your-own-config mode: server-wide env vars for third-party APIs are optional. Users can instead supply their own credentials per-request via HTTP headers (X-Firebase-Config, X-Trakt-Client-Id, etc.) — see lib/credentials.ts.
npm run devnpm run build
npm run startOpen your browser and navigate to
http://{ip}:3000- No admin service account. The backend never holds elevated database credentials — every write is routed through the Firestore REST API, authenticated with the caller's own Firebase ID token.
- AES-256-GCM encryption on sensitive fields (titles, categories, amounts, notes) before they hit Firestore.
- Per-user isolation enforced by ownership checks in
firestore.rules. - Hardened API routes — payloads are validated at the boundary, and upstream proxy routes are strictly allowlisted against SSRF.
Continuum exposes an OpenAPI schema (/api/openapi.json) so you can add expenses, log media, or check your portfolio from a chat window instead of the UI.
Open the Continuum Assistant. Authorization runs through standard OAuth 2.0 on your first prompt.
Configure a Custom GPT for your own self-hosted instance
- In ChatGPT: Explore GPTs → Create → Configure → Actions.
- Import Schema: point it at
https://your-domain.com/api/openapi.json. - Configure Authentication → OAuth:
- Client ID & Secret: any dummy strings (e.g.
client/secret). - Authorization URL:
https://your-domain.com/api/oauth/authorize - Token URL:
https://your-domain.com/api/oauth/token - Token Exchange Method:
Default (POST request).
- Client ID & Secret: any dummy strings (e.g.
- Instructions: paste the contents of CUSTOM_GPT_INSTRUCTIONS.md.
- Save and publish.
- Symptoms
- Fields render as blank or as raw ciphertext
- Data written before now still won't read back correctly
- Troubleshooting Steps
# ENCRYPTION_KEY must stay identical for the lifetime of your data — # changing it makes everything encrypted under the old key unreadable. # Confirm .env.local matches what was used when the data was written.
- Symptoms
- Login redirects back to the login screen
- API routes return 401/403
- Troubleshooting Steps
# Confirm Google Sign-in is enabled in Firebase Console → Authentication # Confirm `firebase deploy --only firestore:rules` was run against the right project # Confirm FIREBASE_CONFIG in .env.local matches the same Firebase project
- Symptoms
- No daily portfolio/expense/subscription emails
- Custom GPT Action calls fail silently
- Troubleshooting Steps
# Confirm CRON_SECRET and RESEND_API_KEY are set in your deployment env # Confirm the GitHub Actions cron workflows have APP_URL and CRON_SECRET as repo secrets # Check /api/cron/health for a live status check
|
Adithya Krishnan |
This project is open-source and available under the MIT License.
Interested in improving Continuum? I welcome contributions! See CONTRIBUTING.md for issue/branch conventions and CI requirements, or just open an issue, submit a PR, or share ideas on GitHub. Together, we can make this project even better.
Well, it's been a while since I worked on any public projects—mostly coz I rarely get time after work, and even when I do, it's usually personal APIs or portfolio updates.
I already had a system to track my expenses and movies via my personal API, which I enhanced when ChatGPT released Custom GPTs so I could add stuff directly via chat (use AI without paying for an API). Instead of putting AI inside my API, I put my API inside AI (sounded cool in my head).
Anyway, a friend saw it and wanted it too, so rather than handing over my personal API collection, I decided to build a proper dashboard instead. And here we are!
Anyways, hosting a custom gpt is kinda costly so not sure how long I might keep that up, feel free to host your own one or sponsor me via the button below :)
