docs/roadmap-pro.md
The /pro landing page promises features across 4 tiers (Free, Pro, API, Enterprise) but almost nothing beyond the marketing page exists. Current state:
registrations + counters tables onlyWORLDMONITOR_API_KEY in keychainapi/_api-key.js validates against static WORLDMONITOR_VALID_KEYS env varKey architectural constraint: main app is vanilla TS + Vite (NOT React). Only pro-test/ landing page is React. Clerk must use @clerk/clerk-js headless SDK.
Recommended MVP scope: Phases 0–4 + tasks 5.1, 5.2 = monetization MVP. Defer Phase 6 XL features until revenue validates demand.
Phase 0 (Decisions)
├──→ Phase 1 (Auth) ────┐
└──→ Phase 2 (Schema) ──┤
├──→ Phase 3 (Payments) ──→ Phase 4 (Gating)
│ │
│ ┌──────┼──────┐
│ ▼ ▼ ▼
└──────────────────→ Phase 5 Phase 6 Phase 7
(Dashboard) (Pro) (API)
│
▼
Phase 8 (Enterprise)
Critical path: Decisions → Auth + Schema (parallel) → Payments → Gating → everything else
| Phase | P0 | P1 | P2 | P3 | Total |
|---|---|---|---|---|---|
| 0: Decisions | 3 | — | — | — | 3 |
| 1: Auth | 2 | 2 | — | — | 4 |
| 2: Schema | 2 | 1 | 1 | — | 4 |
| 3: Payments | 3 | 2 | 1 | — | 6 |
| 4: Gating | 2 | 2 | — | — | 4 |
| 5: Dashboard | — | 2 | 3 | — | 5 |
| 6: Pro Features | — | 5 | 3 | — | 8 |
| 7: API Tier | — | 2 | 2 | — | 4 |
| 8: Enterprise | — | — | — | 10 | 10 |
| Total | 12 | 16 | 10 | 10 | 48 |
Title: decision: auth provider — Clerk (@clerk/clerk-js headless) vs Convex Auth
Labels: decision, auth, P0
Priority: P0 | Size: S | Dependencies: None
Description: Evaluate and select an authentication provider for World Monitor Pro.
Options:
@clerk/clerk-js headless SDK for vanilla TS app, @clerk/clerk-react for /pro React page.Key constraint: Main app is vanilla TS + Vite (NOT React). Auth SDK must support headless DOM mounting (mountSignIn() / mountSignUp()).
Acceptance criteria:
Title: decision: payment provider — Stripe Checkout (hosted) vs embedded
Labels: decision, payments, P0
Priority: P0 | Size: S | Dependencies: None
Description: Select payment processing approach.
Recommendation: Stripe Checkout (hosted). Simpler than embedded, handles SCA/3DS automatically, less frontend code. Stripe Customer Portal for billing management.
Acceptance criteria:
Title: decision: API tier architecture — separate Stripe products, independent of Pro plan
Labels: decision, api-tier, P0
Priority: P0 | Size: S | Dependencies: None
Description: The marketing page states API is "separate from Pro — use both or either." Define the entitlement model.
Decision points:
entitlements projection table derives access from all active subscriptionsrateLimitTier, not per productAcceptance criteria:
entitlements projection table designedTitle: feat(auth): Clerk + Convex integration — users table, webhook sync
Labels: auth, backend, infra, P0
Priority: P0 | Size: M | Dependencies: #0.1
Description: Set up Clerk as the authentication provider and wire it into Convex via webhook.
Implementation:
@clerk/clerk-js (vanilla TS main app) + @clerk/clerk-react (pro-test React page)users table to convex/schema.ts (see schema in Phase 2)user.created → create user in Convex with clerkId, email, name, plan: "free"user.updated → sync email/name changesuser.deleted → anonymize/tombstone user records (NOT hard delete audit/billing)VITE_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEY, CLERK_WEBHOOK_SECRETKey files:
convex/schema.ts — add users tableconvex/clerk-webhook.ts — new HTTP action.env.example — add Clerk env varsAcceptance criteria:
users tableTitle: feat(auth): sign-in/sign-up UI in vanilla TS dashboard (clerk-js headless)
Labels: auth, frontend, P0
Priority: P0 | Size: M | Dependencies: #1.1
Description:
Add authentication UI to the main vanilla TS dashboard using Clerk's headless @clerk/clerk-js SDK.
Implementation:
Clerk instance in app entry pointclerk.mountSignIn(element) / clerk.mountSignUp(element) for auth modalscurrentUser and user entitlements via a service module (src/services/auth.ts)Key files:
src/main.ts — Clerk initializationsrc/services/auth.ts — new auth servicesrc/components/Panel.ts — update locked panel CTA (line ~300)src/locales/en.json — update premium.joinWaitlist to "Sign In to Unlock"Risk: @clerk/clerk-js headless is less documented than React SDK. Prototype mountSignIn() early to validate the approach.
Acceptance criteria:
Title: feat(auth): Tauri desktop auth flow — PKCE + deep link callback
Labels: auth, desktop, P1
Priority: P1 | Size: L | Dependencies: #1.1
Description: Implement Clerk auth flow for the Tauri desktop app with proper session persistence.
Implementation:
worldmonitor://auth/callback deep link URI scheme in Tauri configsetSecret() patternclerk.signOut() + invalidate cached entitlementsKey files:
src-tauri/tauri.conf.json — register deep linksrc-tauri/capabilities/default.json — add deep-link capabilitysrc/services/runtime-config.ts — existing getSecretState/setSecretRisk: Tauri WKWebView has known limitations. Use system browser for OAuth callback, pass token back via deep link.
Acceptance criteria:
Title: feat(auth): migrate waitlist registrations → users table
Labels: auth, migration, P1
Priority: P1 | Size: M | Dependencies: #1.1
Description:
Migrate existing Convex registrations table entries to the new users table.
Migration playbook:
normalizedEmailreferralCode, referralCount, source, appVersionregistrations table intact, only deprecate after 30-day validation periodregistrations count vs users count, flags mismatchesAcceptance criteria:
users entriesregistrations table untouched (rollback safety)Title: feat(backend): users/subscriptions/entitlements/apiKeys/usage/savedViews/alertRules schema
Labels: backend, convex, P0
Priority: P0 | Size: M | Dependencies: #0.1, #0.3
Description: Design and implement the full Convex schema for Pro features.
Schema:
// New tables alongside existing registrations + counters
users: {
clerkId: string (indexed),
email: string (indexed),
name: string,
stripeCustomerId?: string (indexed),
referralCode: string (indexed),
referralCount: number,
createdAt: number,
updatedAt: number,
}
subscriptions: {
userId: Id<"users"> (indexed),
stripeSubscriptionId: string (indexed),
product: "pro" | "api_starter" | "api_business",
status: "active" | "past_due" | "canceled" | "trialing",
currentPeriodStart: number,
currentPeriodEnd: number,
cancelAtPeriodEnd: boolean,
createdAt: number,
}
entitlements: {
userId: Id<"users"> (indexed, unique),
dashboardTier: "free" | "pro",
apiTier: "none" | "starter" | "business",
rateLimitTier: "free_anon" | "free_authed" | "pro" | "api_starter" | "api_business",
features: string[], // ["equity_research", "ai_briefs", "saved_views", ...]
derivedFrom: Id<"subscriptions">[],
computedAt: number,
}
// Derived projection — recomputed on every subscription change
// Single source of truth for ALL gating decisions
stripeEvents: {
eventId: string (indexed, unique),
processedAt: number,
eventType: string,
}
// Idempotency table — prevents duplicate webhook processing
apiKeys: {
userId: Id<"users"> (indexed),
keyHash: string (indexed), // SHA-256 hash — NEVER store plaintext
prefix: string, // first 8 chars for UI identification
name: string,
scopes: string[], // ["read:market", "read:conflict", "*"]
tier: "starter" | "business",
expiresAt?: number,
lastUsedAt?: number,
createdAt: number,
revokedAt?: number,
}
// 256-bit random keys (crypto.getRandomValues), prefixed wm_live_ / wm_test_
// Constant-time comparison via crypto.timingSafeEqual on hash
usage: {
apiKeyId: Id<"apiKeys"> (indexed),
date: string, // YYYY-MM-DD
endpoint: string,
count: number,
}
savedViews: {
userId: Id<"users"> (indexed),
name: string,
panels: string[],
mapLayers: object,
watchlistSymbols: string[],
createdAt: number,
}
alertRules: {
userId: Id<"users"> (indexed),
name: string,
type: "threshold" | "event" | "keyword",
config: object,
channels: object[],
enabled: boolean,
createdAt: number,
}
auditLog: {
userId: Id<"users"> (indexed),
action: string,
resource: string,
metadata: object,
ip?: string,
createdAt: number,
}
// Structured audit for: auth events, key lifecycle, billing changes, entitlement decisions
Key file: convex/schema.ts
Acceptance criteria:
npx convex dev)entitlements table has unique constraint on userIdTitle: feat(backend): user CRUD mutations & queries
Labels: backend, convex, P0
Priority: P0 | Size: M | Dependencies: #2.1
Description: Implement Convex mutations and queries for user management.
Functions:
users.getByClerkId(clerkId) — queryusers.getByApiKey(keyHash) — query (joins apiKeys → users → entitlements)users.create({ clerkId, email, name }) — mutation (from Clerk webhook)users.update({ userId, ...fields }) — mutationusers.anonymize(userId) — mutation (for account deletion — tombstone PII, preserve audit/billing)entitlements.recompute(userId) — mutation (rebuild from active subscriptions)entitlements.getByUserId(userId) — queryauditLog.write({ userId, action, resource, metadata, ip }) — mutationAcceptance criteria:
recompute correctly derives entitlements from multiple subscriptionsdeleted-{hash} but preserves audit recordsTitle: feat(backend): API key generation (wm_live_xxx), hashing, validation
Labels: backend, convex, P1
Priority: P1 | Size: M | Dependencies: #2.1
Description: Implement secure API key lifecycle management.
Implementation:
crypto.getRandomValues(), prefixed wm_live_ or wm_test_crypto.timingSafeEqual on hashed input["read:market", "read:conflict", "*"])expiresAt fieldauditLogFunctions:
apiKeys.create({ userId, name, scopes, tier }) — returns plaintext key ONCEapiKeys.validate(keyHash) — query, returns entitlements if validapiKeys.revoke(keyId) — mutation, sets revokedAtapiKeys.listByUser(userId) — query (returns prefix + metadata, never hash)Acceptance criteria:
wm_live_<32 hex chars>Title: feat(backend): usage tracking — daily counters per API key per endpoint
Labels: backend, convex, P2
Priority: P2 | Size: S | Dependencies: #2.1
Description: Track API usage per key per day for billing and dashboard display.
Functions:
usage.record(apiKeyId, endpoint) — mutation (increment or create daily counter)usage.getDaily(apiKeyId, date) — queryusage.getMonthly(apiKeyId, month) — query (aggregate)Acceptance criteria:
Title: feat(payments): Stripe products — Pro Monthly/Annual + API Starter/Business
Labels: payments, infra, P0
Priority: P0 | Size: S | Dependencies: #0.2
Description: Create Stripe products and price objects for all tiers.
Products:
Environment variables:
STRIPE_SECRET_KEY, STRIPE_PUBLISHABLE_KEY, STRIPE_WEBHOOK_SECRETSTRIPE_PRO_MONTHLY_PRICE_ID, STRIPE_PRO_ANNUAL_PRICE_IDSTRIPE_API_STARTER_PRICE_ID, STRIPE_API_BUSINESS_PRICE_IDAcceptance criteria:
.env.example updatedTitle: feat(payments): checkout flow — Convex HTTP action → Stripe Checkout redirect
Labels: payments, backend, P0
Priority: P0 | Size: M | Dependencies: #2.1, #3.1
Description: Create a Convex HTTP action that generates a Stripe Checkout Session and returns the URL.
Implementation:
stripeCustomerId on user)success_url and cancel_urlAcceptance criteria:
Title: feat(payments): Stripe webhook handler — subscription lifecycle in Convex
Labels: payments, backend, P0
Priority: P0 | Size: L | Dependencies: #3.2
Description: Handle Stripe webhook events to manage subscription lifecycle in Convex.
Safety requirements:
stripe.webhooks.constructEvent() with STRIPE_WEBHOOK_SECRETstripeEvents table by event.id before processing; skip duplicatesstripe.subscriptions.retrieve() and reconcile status, current_period_end, and items. This correctly handles past_due → active, resumed subscriptions, and plan switches.auditLog with full event payload for manual retryrecomputeEntitlements(userId) + Redis cache invalidationWebhook events:
checkout.session.completed → create subscription, link to user, recompute entitlementsinvoice.paid → renew subscription periodinvoice.payment_failed → update status to past_due, send warning email via Resendcustomer.subscription.updated → reconcile from Stripe object, recompute entitlementscustomer.subscription.deleted → mark canceled, recompute entitlements (downgrade)Acceptance criteria:
triggerTitle: feat(payments): pricing page — replace waitlist form with real plans + checkout
Labels: payments, frontend, P1
Priority: P1 | Size: M | Dependencies: #3.2
Description:
Replace the current waitlist form on /pro with a real pricing page that initiates checkout.
Implementation:
Acceptance criteria:
Title: feat(payments): billing management via Stripe Customer Portal
Labels: payments, frontend, P1
Priority: P1 | Size: S | Dependencies: #3.3
Description: Add a link/button that redirects to Stripe Customer Portal for self-service billing management (update payment method, view invoices, cancel subscription, switch plans).
Acceptance criteria:
/account/billingTitle: feat(payments): 14-day free trial for Pro
Labels: payments, backend, P2
Priority: P2 | Size: S | Dependencies: #3.3
Description: Configure Stripe to offer a 14-day trial for Pro tier (no credit card required). Trial expiry → email reminder via Resend. Auto-downgrade on trial end via webhook.
Acceptance criteria:
Title: feat(gating): server-side entitlement verification in gateway.ts
Labels: gating, backend, P0
Priority: P0 | Size: L | Dependencies: #2.2, #2.3
Description: Add entitlement-aware middleware to the server gateway so pro-only endpoints are enforced server-side.
Implementation:
validateApiKey() (gateway.ts line 161), inject entitlement checkent:{userId} or ent:key:{keyHash})recomputeEntitlements() deletes Redis cache entry immediately via Upstash REST API403 { error: "Upgrade required", requiredPlan: "pro", upgradeUrl: "/pro" } for gated endpointsEntitlement matrix:
| Endpoint Category | free_anon | free_authed | pro | api_starter | api_business |
|---|---|---|---|---|---|
| Public data (seismology, news, weather) | ✓ | ✓ | ✓ | ✓ | ✓ |
| Market quotes, crypto, commodities | ✓ | ✓ | ✓ | ✓ | ✓ |
| Equity research (financials, targets) | — | — | ✓ | — | ✓ |
| AI briefs, flash alerts | — | — | ✓ | — | — |
| Economy analytics (correlations) | — | — | ✓ | — | ✓ |
| Risk scoring, scenario analysis | — | — | ✓ | — | ✓ |
API key migration (dual-read rollout):
WORLDMONITOR_VALID_KEYS AND new entitlements. Log comparison metrics.Key files:
server/gateway.ts — main middleware injection pointapi/_api-key.js — extend validation logicserver/_shared/rate-limit.ts — rate limit by entitlement tierAcceptance criteria:
Title: feat(gating): client-side plan context service (src/services/plan-context.ts)
Labels: gating, frontend, P0
Priority: P0 | Size: M | Dependencies: #1.2, #2.2
Description: Create a client-side service that exposes user plan/entitlements for UI gating.
Implementation:
src/services/plan-context.tsisPro(), hasApiAccess(), getPlan(), hasFeature(name)getSecretState('WORLDMONITOR_API_KEY').present checks with plan contextcomputedAt timestamp for staleness detectionKey files to update:
src/components/Panel.ts — replace getSecretState checksrc/components/DeckGLMap.ts — replace layer premium checksrc/components/GlobeMap.ts — replace layer premium checksrc/app/panel-layout.ts — replace _wmKeyPresent logicAcceptance criteria:
isPro() returns true for pro users, false for freegetSecretState('WORLDMONITOR_API_KEY') references replacedTitle: feat(gating): refactor panel/layer premium flags → plan context
Labels: gating, frontend, P1
Priority: P1 | Size: M | Dependencies: #4.2
Description:
Update panel and map layer configurations to use the new plan context instead of desktop-only isDesktopRuntime() checks.
Changes:
src/config/panels.ts — premium flags read from plan context, apply to web AND desktopsrc/config/map-layer-definitions.ts — sameAcceptance criteria:
/pro pricing pageTitle: feat(gating): per-plan rate limiting in gateway
Labels: gating, backend, P1
Priority: P1 | Size: M | Dependencies: #4.1
Description: Implement tiered rate limiting based on user plan.
Rate limits:
| Tier | Requests/day | Requests/min |
|---|---|---|
| Free (no auth) | 100 | 5 |
| Free (authenticated) | 500 | 10 |
| Pro | 10,000 | 60 |
| API Starter | 1,000 | 30 |
| API Business | 50,000 | 300 |
Unauthenticated identity:
cf-connecting-ip + endpoint path bucketcf-connecting-ip from Cloudflare IP ranges. Non-CF sources fall back to actual remote address. Log spoofing attempts.Acceptance criteria:
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-ResetTitle: feat(dashboard): /account page — profile, plan badge, API keys
Labels: dashboard, frontend, P1
Priority: P1 | Size: M | Dependencies: #1.2, #2.2, #2.3
Description:
Create an account page at /account showing profile info, current plan, and API key management.
Sections:
Acceptance criteria:
Title: feat(dashboard): /account/billing — invoices, plan management
Labels: dashboard, frontend, P1
Priority: P1 | Size: M | Dependencies: #3.3
Description: Create a billing page showing current subscription, next payment date, and link to Stripe Customer Portal.
Sections:
Acceptance criteria:
Title: feat(dashboard): API usage stats with daily/monthly charts
Labels: dashboard, frontend, P2
Priority: P2 | Size: M | Dependencies: #2.4, #5.1
Description: Display API usage charts on the account page (daily and monthly breakdowns).
Acceptance criteria:
Title: feat(dashboard): notification preferences & delivery channels config
Labels: dashboard, frontend, P2
Priority: P2 | Size: M | Dependencies: #5.1
Description: Settings page for configuring notification delivery channels (Slack webhook URL, Telegram bot, Discord webhook, email preferences).
Acceptance criteria:
Title: feat(docs): interactive API docs page with OpenAPI 3.1 from proto defs
Labels: dashboard, docs, P2
Priority: P2 | Size: L | Dependencies: #4.1
Description: Generate OpenAPI 3.1 spec from existing sebuf proto definitions (50+ RPCs across 15+ domains). Host interactive API explorer.
Implementation:
(sebuf.http.config) annotations/developers or /api/docsAcceptance criteria:
Title: feat(pro): equity research — financials, analyst targets, valuation metrics
Labels: pro-feature, backend, P1
Priority: P1 | Size: XL | Dependencies: #4.1
Description: Build a new data pipeline for equity research features (pro-only).
Data to add:
Sources (evaluate): Finnhub premium, Financial Modeling Prep (FMP), Alpha Vantage
Implementation:
worldmonitor/equity/v1/get-company-financials, get-analyst-consensus, get-valuation-metrics, list-earnings-calendarcachedFetchJson patternAcceptance criteria:
Title: feat(pro): AI daily briefs engine — scheduled LLM summaries
Labels: pro-feature, backend, P1
Priority: P1 | Size: XL | Dependencies: #4.1, #6.5
Description: Build a scheduled AI briefing system that synthesizes overnight developments and delivers via configured channels.
Implementation:
deduct-situation.ts)briefs tableFlash alerts: real-time event detection → LLM classification (existing classify-event RPC) → push notification
Acceptance criteria:
Title: feat(pro): sub-60s data refresh for pro users
Labels: pro-feature, backend, P1
Priority: P1 | Size: L | Dependencies: #4.1
Description: Reduce data refresh interval for pro users from 5-15 minutes to <60 seconds.
Phased approach:
DataLoaderManager interval for pro users)Acceptance criteria:
Title: feat(pro): persistent server-side watchlists & custom views
Labels: pro-feature, fullstack, P1
Priority: P1 | Size: M | Dependencies: #2.1, #4.2
Description:
Migrate watchlists from localStorage to Convex savedViews table for cross-device sync.
Currently localStorage-only:
src/services/market-watchlist.tssrc/services/aviation/watchlist.tsImplementation:
Acceptance criteria:
Title: feat(pro): delivery channels — Slack, Telegram, Discord, Email
Labels: pro-feature, backend, P1
Priority: P1 | Size: XL | Dependencies: #2.1
Description: Build multi-channel delivery infrastructure for AI briefs and alerts.
Channels (in priority order):
@WorldMonitorBot. User starts conversation, store chat_id.Security:
hooks.slack.com, discord.com/api/webhooks, Telegram APIAPP_ENCRYPTION_KEY env var)Acceptance criteria:
Title: feat(pro): economy analytics — GDP/inflation/rates correlation views
Labels: pro-feature, frontend, P2
Priority: P2 | Size: L | Dependencies: #4.1
Description: Build correlation views on top of existing economic data (FRED, BIS, World Bank RPCs already exist).
New visualizations:
Acceptance criteria:
Title: feat(pro): risk monitoring — convergence alerting & scenario analysis
Labels: pro-feature, fullstack, P2
Priority: P2 | Size: L | Dependencies: #4.1
Description: Enhance existing risk analytics with scenario analysis and convergence alerting.
Existing engines (enhance, don't rebuild):
src/services/geo-convergence.ts — convergence detectionsrc/services/focal-point-detector.ts — focal point detectionsrc/services/country-instability.ts — CII scoringsrc/services/signal-aggregator.ts — signal aggregationNew:
Acceptance criteria:
Title: feat(pro): 22-services-1-key — replace BYOK with Pro key for all services
Labels: pro-feature, fullstack, P1
Priority: P1 | Size: M | Dependencies: #4.1
Description: Pro users should NOT need to configure individual API keys for Finnhub, FRED, ACLED, etc. A single World Monitor Pro subscription gives access to all 24 services.
Implementation:
Key files:
src/services/settings-constants.ts — 20+ key definitionsserver/gateway.ts — skip BYOK check for pro usersAcceptance criteria:
Title: feat(api-tier): API key issuance & management portal
Labels: api-tier, fullstack, P1
Priority: P1 | Size: M | Dependencies: #2.3, #5.1
Description: Extend the account page with API key management specifically for API tier subscribers.
Features:
Acceptance criteria:
Title: feat(api-tier): per-key usage tracking with daily limits
Labels: api-tier, backend, P1
Priority: P1 | Size: M | Dependencies: #2.4, #4.4
Description: Track and enforce daily usage limits per API key based on tier (Starter: 1,000/day, Business: 50,000/day).
Implementation:
usage counter on each request429 with Retry-After header when limit exceededAcceptance criteria:
Title: feat(api-tier): OpenAPI 3.1 spec auto-generation from sebuf protos
Labels: api-tier, docs, P2
Priority: P2 | Size: L | Dependencies: None
Description: Auto-generate OpenAPI 3.1 specification from existing sebuf proto definitions.
Acceptance criteria:
Title: feat(api-tier): webhook delivery system with retry & HMAC signatures
Labels: api-tier, backend, P2
Priority: P2 | Size: L | Dependencies: #7.1
Description: Allow API tier subscribers to configure webhook endpoints for event delivery.
Implementation:
webhookEndpoints (userId, url, events, secret)Acceptance criteria:
Title: feat(enterprise): organization accounts & team management
Labels: enterprise, fullstack, P3
Priority: P3 | Size: XL | Dependencies: #1.1
Description: Multi-user organizations with shared dashboards, seat management, and invite flow.
Title: feat(enterprise): RBAC (role-based access control)
Labels: enterprise, backend, P3
Priority: P3 | Size: L | Dependencies: #8.1
Description: Role-based access: admin, analyst, viewer. Per-role permissions for panels, data access, and configuration.
Title: feat(enterprise): SSO (SAML/OIDC via Clerk Enterprise)
Labels: enterprise, auth, P3
Priority: P3 | Size: L | Dependencies: #8.1
Description: Enterprise SSO via Clerk's Enterprise plan. Requires Clerk Enterprise subscription.
Title: feat(enterprise): TV/SOC display mode
Labels: enterprise, frontend, P3
Priority: P3 | Size: M | Dependencies: None
Description:
Full-screen dashboard for wall displays with auto-rotating panels and custom layouts. Some exists in src/services/tv-mode.ts.
Title: feat(enterprise): white-label & embeddable panels
Labels: enterprise, frontend, P3
Priority: P3 | Size: XL
Description: Your brand, your domain, your desktop app. Embeddable iframe panels (50+ available).
Title: feat(enterprise): satellite imagery & SAR integration
Labels: enterprise, backend, P3
Priority: P3 | Size: XL
Description: Live-edge satellite imagery and SAR (Synthetic Aperture Radar) with change detection. Requires partnerships with Maxar/Planet.
Title: feat(enterprise): AI agents with investor personas & MCP
Labels: enterprise, backend, P3
Priority: P3 | Size: XL
Description: Autonomous intelligence agents using Model Context Protocol. Connect as tool to Claude, GPT, or custom LLMs.
Title: feat(enterprise): 100+ data connectors
Labels: enterprise, backend, P3
Priority: P3 | Size: XL
Description: PostgreSQL, Snowflake, Splunk, Sentinel, Jira, Slack, Teams. Export to PDF, PowerPoint, CSV, GeoJSON. Multi-quarter effort.
Title: feat(enterprise): on-premises / air-gapped deployment
Labels: enterprise, infra, P3
Priority: P3 | Size: XL
Description: Docker-based on-premises deployment with air-gapped option. Full architecture rethink required — currently all cloud-native (Vercel + Convex + Railway).
Title: feat(enterprise): Android TV app
Labels: enterprise, frontend, P3
Priority: P3 | Size: XL
Description: Dedicated Android TV app for SOC walls and trading floors. Separate codebase.
@clerk/clerk-js headless is less documented than React SDK. Prototype early.entitlements projection table mitigates scattered logic.worldmonitor:// deep link callback.auditLog tableregistrations table preserved 30 days alongside usersuser.deleted webhook → delete user data. Audit logs and billing records are NOT deleted — user identifiers anonymized/tombstoned (deleted-{hash}). Stripe customer marked deleted; invoice history retained by Stripe.