Scouttlo
All ideas/devtools/Plataforma SaaS que facilite la transformación de aplicaciones self-hosted en soluciones multi-tenant con integración automática de dispositivos, gestión de sincronización escalable y facturación integrada.
GitHubB2Bdevtools

Plataforma SaaS que facilite la transformación de aplicaciones self-hosted en soluciones multi-tenant con integración automática de dispositivos, gestión de sincronización escalable y facturación integrada.

Scouted 8 hours ago

7.0/ 10
Overall score

Turn this signal into an edge

We help you build it, validate it, and get there first.

Go from idea to plan: who buys, what MVP to launch, how to validate it, and what to measure before spending months.

Extra context

Learn more about this idea

Get a clearer explanation of what the opportunity means, the current problem behind it, how this idea solves it, and the key concepts involved.

Share your email to view this expanded analysis.

Score breakdown

Urgency8.0
Market size7.0
Feasibility8.0
Competition5.0
Pain point

La falta de soporte multiusuario completo y la ausencia de una interfaz de integración y facturación automatizada limitan la escalabilidad y monetización de herramientas SaaS basadas en dispositivos personales.

Who'd pay for this

Desarrolladores y startups que tienen aplicaciones basadas en datos de dispositivos personales y quieren escalar a SaaS multiusuario sin complejidad operativa.

Source signal

"This issue documents the full architectural and product analysis for turning Mr. Bridge from a single-user self-hosted tool into a multi-tenant SaaS application"

Original post

feat: architecture and product plan for multi-tenant SaaS launch

Published: 8 hours ago

Repository: Theioz/mr-bridge-assistant Author: Theioz ## Summary This issue documents the full architectural and product analysis for turning Mr. Bridge from a single-user self-hosted tool into a multi-tenant SaaS application — where users sign up, connect their own devices, and interact with their data through Mr. Bridge without ever touching a terminal, environment variable, or Supabase dashboard. This is a planning and decision issue. Each section below frames the decision space, analyzes options, and lands on a recommendation. Concrete implementation issues will be filed for each pillar once decisions are ratified. --- ## Current architecture snapshot (honest assessment) | Layer | What we have | Multi-tenant ready? | |---|---|---| | Database | Supabase Postgres, RLS on all tables, `user_id` on every row | ✅ Already multi-tenant | | Auth | Supabase Auth (email + Google OAuth) | ✅ Works for N users | | Web app | Next.js App Router on Vercel | ✅ Stateless, scales automatically | | Per-user fitness tokens | `fitbit_refresh_token`, `oura_token` stored in `profile` table per user | ✅ Already per-user | | App-level OAuth credentials | `FITBIT_CLIENT_ID/SECRET`, `GOOGLE_CLIENT_ID/SECRET` as env vars | ✅ These are app-level — same for all users, correct pattern | | Sync cron job | `OWNER_USER_ID` hardcoded — runs sync for one user only | ❌ Single-user assumption | | Python scripts | `scripts/` — machine-local, reference `OWNER_USER_ID` | ❌ Not deployable, not multi-user | | AI usage | No limits, no tracking, no per-user quotas | ❌ Would be bankrupt at scale | | Integration setup | Manual: CLI scripts, env vars, Supabase dashboard | ❌ No user can self-serve this | | Apple Health | Not implemented | ❌ Missing the dominant iOS platform | | Billing | None | ❌ No monetization | **The good news**: Supabase RLS is already the correct foundation — every query is already isolated by `user_id`. The codebase is about 60% of the way to multi-tenant. The remaining 40% is cron multi-user support, integration onboarding UI, cost controls, and Apple Health. --- ## Decision 1 — Infrastructure: keep current stack vs. containerize vs. rewrite ### Option A — Keep Vercel + Supabase, move Python sync to a TypeScript background worker (recommended) Rewrite the Python sync scripts in TypeScript. Deploy them as a separate Node.js worker service on Railway or Render. The worker polls a `sync_queue` table in Supabase for pending sync jobs and processes them. The Vercel cron triggers enqueueing for all users; the worker does the actual API calls. **Pros:** - Vercel + Supabase already works — no migration risk - TypeScript unifies the entire codebase (no Python maintenance tax going forward) - Railway/Render worker costs ~$5–7/month for a persistent Node.js process - Supabase scales to thousands of concurrent users on Pro plan ($25/month) - Vercel scales automatically — no ops work - The existing sync TypeScript modules (`web/src/lib/sync/fitbit.ts`, `oura.ts`, `googlefit.ts`) are already written and working — the worker just calls them outside of Vercel's 15-second function timeout **Cons:** - Railway/Render adds one more service to manage - Long sync jobs (backfill years of Fitbit data) need timeout handling - Cold starts on the worker if using serverless-style deployment ### Option B — Full containerization (Docker + Kubernetes / AWS ECS) Package the entire application in Docker containers, run on ECS, GKE, or self-managed Kubernetes. **Pros:** - Full control over scaling, resource allocation, and deployment - Can run long-running processes without timeout constraints **Cons:** - Massively premature — adds months of DevOps work before shipping a single user - Requires maintaining infrastructure that Vercel and Supabase already handle for free - Kubernetes operational complexity is a full-time job at this stage - No meaningful benefit over Vercel + Railway until the app has hundreds of thousands of users ### Option C — Rewrite backend in Go Replace Python scripts and potentially the Next.js API routes with a Go backend. **Pros:** - Go is fast, easy to deploy as a single binary, excellent for background workers - Lower memory footprint than Node.js **Cons:** - Complete rewrite — months of work, zero new features shipped - The current TypeScript codebase is clean and performant enough for this scale - Anthropic SDK, Supabase SDK, and health API clients all have first-class TypeScript support; Go equivalents are community-maintained **Recommendation: Option A.** The stack is correct. The only infrastructure gap is the Python sync scripts — rewrite them in TypeScript and run on Railway. Everything else scales as-is. --- ## Decision 2 — Authentication and data isolation ### Current state Supabase Auth handles login. RLS policies enforce that every Supabase query only returns rows where `auth.uid() = user_id`. The `createServiceClient()` bypasses RLS and is correctly limited to system operations (sync, cron, admin). This is already correct multi-tenant architecture. ### What needs to change 1. **Apple Sign In** — required for App Store apps; strongly preferred by iOS users 2. **Email verification** — currently optional in Supabase; must be enforced for production 3. **Data deletion** — users must be able to delete their account and all associated data (GDPR Article 17, CCPA) 4. **Session security** — Supabase handles JWTs already; review token expiry settings 5. **Admin access controls** — an admin panel to manage users, disable accounts, view aggregate (non-PII) usage stats ### Option A — Supabase Auth only, add Apple + social providers (recommended) Stay on Supabase Auth. Add Apple Sign In and extend Google OAuth. Implement a `/api/account/delete` route that cascades delete all user data. Use Supabase's built-in email verification. **Pros:** - Zero migration — add providers via Supabase dashboard - Apple Sign In is a native Supabase Auth provider - Data deletion is a single `DELETE FROM auth.users WHERE id = $uid` which cascades via `ON DELETE CASCADE` on all tables (already configured) - Supabase handles token rotation, session storage, PKCE **Cons:** - Supabase Auth has limits on the free plan (50k MAU); Pro plan is needed at scale (unlimited MAU, $25/mo) ### Option B — Replace Supabase Auth with Clerk or Auth0 Migrate authentication to a dedicated auth provider. **Pros:** - Clerk has excellent UI components, organization support, audit logs - Auth0 has enterprise SSO features **Cons:** - Migration of existing sessions is complex - Adds another vendor and monthly cost (~$25+/month) - Supabase Auth already covers all required features for this use case **Recommendation: Option A.** Supabase Auth is sufficient. Add Apple Sign In, enforce email verification, implement data deletion. No migration needed. ### Data isolation audit (required before launch) - Audit every use of `createServiceClient()` — must only be used for system operations, never for returning user-specific data to the frontend - Remove all `OWNER_USER_ID` references from query logic; every query must use `auth.uid()` from the authenticated request - Add a `deleted_at` soft-delete to `auth.users` via a database function — gives a 30-day grace period before hard deletion --- ## Decision 3 — Integration onboarding UX (replacing env vars) ### Current state Connecting Fitbit requires: registering a Fitbit developer app, setting 4 env vars, running a Python OAuth setup script, then running sync manually. No normal user can do this. ### What the onboarding flow needs to be A **Connections** page in Settings (or a dedicated `/connect` route) with integration cards — similar to how Notion, Zapier, or Strava handle third-party connections. ``` ┌─────────────────────────────────────────┐ │ Connected Devices │ ├─────────────────────────────────────────┤ │ 🟢 Fitbit Connected [Sync] [Disconnect] │ │ 🔴 Apple Health Not connected [Connect] │ │ 🔴 Oura Ring Not connected [Connect] │ │ 🟡 Google Fit Connected [Sync] [Disconnect] │ │ 🔴 Garmin Not connected [Connect] │ ├─────────────────────────────────────────┤ │ 📧 Gmail Connected │ │ 📅 Google Calendar Connected │ └─────────────────────────────────────────┘ ``` ### Option A — Build per-provider OAuth flows ourselves (recommended for initial launch) For each provider (Fitbit, Oura, Google Fit), implement a standard OAuth 2.0 authorization code flow: 1. User clicks "Connect Fitbit" 2. Redirected to Fitbit's auth page with our app's `client_id` 3. Fitbit redirects back to `/api/connect/fitbit/callback` with `?code=...` 4. Exchange code for tokens, encrypt and store in `user_integrations` table per user 5. Show "Connected ✓" The app registers ONE Fitbit developer app, ONE Google app — all users authenticate through it. This is standard SaaS OAuth. New `user_integrations` table: ```sql create table user_integrations ( id uuid primary key default gen_random_uuid(), user_id uuid not null references auth.users(id) on delete cascade, provider text not null, -- 'fitbit', 'oura', 'google_fit', 'google_calendar', 'gmail' access_token text, -- encrypted at rest (Supabase Vault or pgcrypto) refresh_token text, -- encrypted at rest expires_at timestamptz, scope text, connected_at timestamptz default now(), unique (user_id, provider) ); ``` **Pros:** - Full control over the OAuth flow and token storage - No additional vendor cost or dependency - Fitbit, Oura, Google APIs are well-documented with standard OAuth 2.0 - The TypeScript sync modules already handle token refresh correctly **Cons:** - Each provider requires a separate developer app registration - Must maintain OAuth apps with each provider (review policies, scope changes) - Apple Health requires a native app — cannot be done via web OAuth (see Decision 4) ### Option B — Use a health data aggregator (Terra API, Vital, Sahha) Register with Terra or Vital — they provide a single SDK/API that aggregates Fitbit, Oura, Apple Health, Garmin, Whoop, and more via their own OAuth infrastructure. **Pros:** - Single integration handles 10+ providers including Apple Health (via Terra's iOS SDK) - Webhook-based: Terra pushes data to our endpoint when it's available — eliminates cron/sync entirely - Handles token refresh, provider API changes, and data normalization **Cons:** - Terra costs: ~$0.10–0.25 per connected user per month (adds up at scale) - Data passes through a third party — privacy/compliance consideration for health data - Less control over data granularity and sync timing - Vendor lock-in: if Terra raises prices or shuts down, migration is expensive **Recommendation: Option A for launch (Fitbit, Oura, Google Fit), Option B as a future accelerator for Apple Health and Garmin.** Build the OAuth flows ourselves for the three providers we already support — the code is already written. Add Terra specifically for Apple Health and Garmin where web OAuth is impossible. --- ## Decision 4 — Apple Health Apple Health is the dominant fitness platform for US iPhone users. It captures data from Apple Watch, third-party apps (Strava, MyFitnessPal, etc.), and manual entries. It is the single biggest missing integration. ### The constraint Apple Health (HealthKit) is only accessible via native iOS code. There is no web API. A pure web app cannot read HealthKit data. ### Option A — Manual XML export (no native app, available at launch) Apple Health allows users to export all their data as an XML file (`export.xml`). We build an import page that accepts this file, parses it, and loads historical data. **Pros:** - Available immediately, no native app needed - Captures complete historical data - Zero ongoing infrastructure cost **Cons:** - Not automatic — user must manually re-export and re-import to refresh data - Export file can be hundreds of MB for long-time Apple Watch users — needs streaming parser - Not real-time — can't get today's steps without another manual export ### Option B — PWA + background sync via Shortcuts Build a Progressive Web App. Use Apple Shortcuts automation to read HealthKit data and POST it to our `/api/sync/apple-health` endpoint on a schedule (e.g., every hour). **Pros:** - No App Store review needed - Can automate sync without a native app - Shortcuts can read steps, heart rate, sleep, workouts from HealthKit **Cons:** - Requires users to set up an Automations shortcut — not zero-friction - Limited to what Shortcuts can export (no raw HRV, no detailed sleep stages) - Runs only when the shortcut triggers (not truly real-time) ### Option C — Native iOS companion app (React Native / Expo) Build a lightweight React Native app whose sole job is reading HealthKit and syncing to Supabase. The main UI stays on the web. **Pros:** - Full HealthKit access: steps, heart rate, HRV, sleep stages, workouts, body weight, blood oxygen - Background sync — can post data every 15–60 minutes automatically - Apple Watch complications possible - Unlocks Apple Sign In (required for App Store apps) **Cons:** - App Store review process (1–2 weeks for initial review, faster for updates) - React Native / Expo adds a second codebase to maintain - Apple Developer Program: $99/year - HealthKit entitlement requires App Store submission (no TestFlight distribution without review for HealthKit) ### Option D — Terra API iOS SDK Integrate Terra's iOS SDK in a native companion app. Terra handles HealthKit permissions, normalization, and webhook delivery to our backend. **Pros:** - Fastest path to comprehensive HealthKit data (Terra's SDK handles the complexity) - Same backend integration as Decision 3 Option B — one webhook endpoint for all providers **Cons:** - Still requires a native app for the HealthKit entitlement - Terra cost per connected user (see Decision 3) **Recommendation:** - **Launch**: Option A (XML import) — ships immediately, captures historical data, no App Store dependency - **Phase 2**: Option B (Shortcuts automation) — bridges the gap for daily sync without an app - **Phase 3**: Option C (React Native companion) — full HealthKit access, required for serious fitness tracking users. This is the right long-term answer; build it once the web product is validated. --- ## Decision 5 — AI cost management and usage limits ### Current state No limits. Every user can make unlimited requests. At ~$2/day for one user, 100 users = $200/day = $6,000/month in Anthropic bills alone. ### Cost drivers (ranked, from current analysis) 1. `maxSteps: 12` — up to 12 tool call round-trips per message 2. System prompt size — loads full profile, recent meals, habits on every request 3. No `maxTokens` cap on responses 4. Context window: last 20 messages sent on every request 5. Model routing: Haiku handles simple queries but complex ones always hit Sonnet ### Option A — Token budget per user per month with subscription tiers (recommended) Track token usage in a `token_usage` table (input tokens, output tokens, model, timestamp per request). Enforce monthly limits by tier. Use Stripe for subscription management. ``` Free tier: 50,000 tokens/month (~$0.75 at Sonnet pricing) — enough for ~25 conversations Pro tier: 500,000 tokens/month (~$7.50) — $9.99/month subscription Unlimited: No cap — $24.99/month ``` **Pros:** - Direct relationship between cost and revenue - Stripe is standard, well-documented, has Next.js examples - Free tier drives signups; Pro converts power users - Token counting is exact — Anthropic returns usage in every API response **Cons:** - Users hate token limits — need clear UI showing remaining budget - Must handle gracefully: show warning at 80%, soft limit at 100% (no hard cutoff mid-conversation) - Stripe integration is a week of work (checkout, webhooks, subscription management) ### Option B — Request-based limits (X messages per day) Simpler than token counting — limit total messages sent per day/month. **Pros:** - Easy to understand for users ("10 messages/day free") - Simple to implement (count rows in `chat_messages`) **Cons:** - "Message" is a bad unit — a 3-word question costs the same as a detailed analysis request - Power users will game it by cramming everything into one long message - Doesn't map to actual costs ### Option C — Flat monthly subscription, no per-request limits Charge a flat fee ($9.99–19.99/month), don't meter usage. Absorb cost variance. **Pros:** - Simplest UX — no budget anxiety - No infrastructure for metering **Cons:** - High-usage users could cost $50+/month to serve while paying $10 - Financially risky without usage data to model cost distribution **Recommendation: Option A (token budget + Stripe tiers).** Token metering is the honest unit of cost. The implementation is: (1) read `usage` from every Anthropic API response and insert into `token_usage`, (2) check budget at the start of each chat request and return 402 if exhausted, (3) show a usage indicator in the Chat UI. Stripe for billing. Also implement the cost-optimization changes from issue #189 (maxSteps, maxTokens, context window) before launch — these reduce per-user costs by ~60%, widening the margin on every tier. --- ## Decision 6 — QoS, rate limiting, and abuse prevention ### What's needed - **Per-user rate limiting**: max N requests per minute to prevent runaway loops or abuse - **Global circuit breaker**: if Anthropic API is down, return a clear error rather than hanging - **Sync throttling**: don't run all users' fitness syncs simultaneously — stagger across the hour - **Webhook verification**: all incoming webhooks (Fitbit, Terra, Stripe) must verify HMAC signatures ### Option A — Upstash Redis for rate limiting (recommended) Use Upstash (serverless Redis) for sliding-window rate limiting at the Next.js middleware layer. Free tier: 10,000 requests/day. Pro: $0.2 per 100K requests. **Pros:** - Vercel-native: Upstash has a first-class `@upstash/ratelimit` library designed for Vercel Edge - Sliding window prevents burst abuse - Sub-millisecond latency — doesn't add perceptible delay - Can also use for caching expensive queries (profile, briefing data) **Cons:** - Another service dependency - Free tier may not cover high-volume users ### Option B — Supabase-based rate limiting (count recent requests in DB) Count recent `chat_messages` rows per user as a proxy for rate limiting. **Pros:** - No new service **Cons:** - DB query on every request adds latency - Supabase connection pool pressure **Recommendation: Option A (Upstash).** The `@upstash/ratelimit` + Vercel Edge combination is the standard pattern. Add it to the chat route: 20 requests/minute per user on Free, 60/minute on Pro. --- ## Decision 7 — Compliance and privacy Health data carries higher sensitivity than typical SaaS data. Key considerations: ### HIPAA Mr. Bridge is **not** a covered entity under HIPAA (it's not a healthcare provider, insurer, or clearinghouse). The fitness tracking use case (steps, sleep, weight) is personal wellness, not medical records. **HIPAA does not apply.** However, marketing language should be careful not to position Mr. Bridge as a medical device or health management tool. ### GDPR / CCPA Applies if users are in the EU or California. Required: - Privacy policy and terms of service - Cookie consent banner (minimal — only Supabase auth cookies) - **Right to deletion**: `/api/account/delete` that removes all user data - **Data export**: `/api/account/export` that returns a JSON dump of all the user's data - Data processing agreement with Supabase and Anthropic (both have DPAs available) ### Token/health data encryption - OAuth tokens (Fitbit refresh tokens, Oura tokens) are currently stored in plaintext in the `profile` table. Before launch: encrypt these at rest using Supabase Vault or `pgcrypto`. - Anthropic does not train on API data by default — no action needed, but document this in the privacy policy. --- ## Phased launch roadmap ### Phase 1 — Foundation (pre-launch, ~4–6 weeks) Issues to file and implement: 1. **Multi-user cron sync**: Update `/api/cron/sync` to loop over all users with connected integrations, not just `OWNER_USER_ID` 2. **OAuth connections UI**: `user_integrations` table + `/connect` page with Fitbit, Oura, Google Fit OAuth flows 3. **Remove OWNER_USER_ID**: Replace all single-user assumptions with authenticated user context 4. **Token usage tracking + limits**: Insert to `token_usage` on every chat request; enforce monthly budget 5. **Stripe integration**: Subscription tiers, checkout flow, webhook handler 6. **Data deletion + export**: `/api/account/delete` and `/api/account/export` 7. **Token encryption**: Encrypt OAuth tokens at rest in `user_integrations` table ### Phase 2 — Apple Health + mobile (post-launch, ~6–8 weeks) 8. **Apple Health XML import**: Upload and parse `export.xml`, load into `fitness_log` and `recovery_metrics` 9. **Apple Health Shortcuts bridge**: `/api/sync/apple-health` endpoint + Shortcuts template for users 10. **PWA manifest**: installable web app, home screen icon, splash screen ### Phase 3 — Native app + growth (~3 months post-launch) 11. **React Native companion app**: HealthKit sync, push notifications, App Store submission 12. **Garmin / Whoop via Terra**: Expand device support via Terra webhooks 13. **Team/family plans**: Shared household data, multiple profiles under one subscription --- ## Acceptance criteria (for this planning issue) - [ ] All 7 decisions above are reviewed and ratified (or amended) by the user - [ ] Phase 1 issues are filed with full implementation prompts - [ ] `user_integrations` table schema is finalized and approved - [ ] Stripe pricing tiers are decided (Free / Pro / Unlimited amounts) - [ ] Apple Health launch strategy is decided (XML import only vs. Shortcuts bridge at launch) - [ ] Privacy policy scope is defined (GDPR compliance level, data residency) ## Related - #189 (API cost optimization) — must ship before launch to reduce per-user cost basis - #188 (voice mode) — Phase 1 feature - #192 (workout program) — Phase 1 feature