CARR Platform Architecture (Current Build)
The four-layer view of everything the CARR platform is made of today — the app, the Edge Functions it calls, the database, and the supply chain that feeds it.
Current Virtual Environment
Built in GitHub
CDN + custom domain
Session JWT
message generation
send · reply/stat sync
account classify · match
webhooks
101 views
46 triggers
15-min → weekly
pg_net / http (outbound)
ClinicalTrials · NIH · SEC · PatentsView · PubMed · 22 RSS
Sourcing + enrichment SaaS:
Sales Navigator · PhantomBuster · Clay · FullEnrich
bc-ops VPS crons · Colab notebooks
Work it does:
capture → summarize → match → enrich → internalize into CARR
HeyReach · EmailBison
(reply source + send destination)
Seed feed:
BC Hub DB (17K-company master)
pull sources → 4b Agent VE
capture · match · enrich · internalize → CARR DB
Layer 3 → App + EFs
Layers 1–2 ↕ 4c Outreach (send) + Hub (seed)
Architecture Overview
Download .docx17 - CARR Platform Architecture (Current Build)
What the CARR platform is made of today — the "Current Virtual Environment." This is the clean overview discussed on the 2026-07-21 working session. The platform is four layers: the app users see, the Edge Functions (backend logic) it calls, the database underneath, and the external supply chain that keeps it fed. Understanding all four is required before planning how each moves to Azure.
Triggers: "architecture overview", "current build", "virtual environment", "four layers", "how is carr built", "what does carr run on".
How it's built and hosted today
Layer 1 — The App (what users see)
The CARR Intel Hub is a React/Vite single-page application (SPA) with 22+ pages: Accounts, Target Universe, Campaigns, Pipeline, Content Studio, Team Analytics, and more.
How it's built:
- Source code lives in GitHub (carr-biosystems-hub repository)
- Built with React 18 + TypeScript + Vite (standard modern web stack)
- Developed by BioCreative using Windsurf IDE; code changes are committed to GitHub
How it's hosted:
- Lovable watches the GitHub repo (via sync) and serves the compiled static files on its CDN
- A custom domain purchased by BioCreative points to Lovable's hosting
- Lovable is hosting only — it provides no auth, no data, no build logic. It is purely a static-file CDN
How login/access works:
- BioCreative manually adds users to the user_profiles table in Supabase and creates their Supabase Auth credentials (email + password)
- The frontend uses supabase-js to sign in (signInWithPassword) and get a session JWT
- Every page checks: (1) valid session exists, (2) user's is_active = true in user_profiles — shows the app or redirects to login
- The supabase-js library also connects the frontend to PostgREST (the auto-generated API) and the Edge Functions
What connects the app to the backend:
- PostgREST (Supabase's auto-API): the frontend reads/writes data via supabase-js → PostgREST → Postgres, with RLS enforcing per-user access
- Edge Functions (Layer 2 below): the app also calls supabase-js's functions.invoke() to run the backend verbs
Layer 2 — Edge Functions (backend logic)
Between the app and the database sits a tier of 26 Edge Functions — Deno/TypeScript serverless functions that hold the backend logic the app calls. Important: these run on Supabase Edge (Deno runtime), which is separate compute from the Postgres database — they are not stored inside the DB. They are the "back-end verbs":
| Group | What these functions do |
|---|---|
| AI / Content | Generate messages + content via Claude/OpenAI (generate-content, message generation) |
| Outreach Sync | Push sends to HeyReach + EmailBison and sync replies/stats back (~17 functions) |
| Scoring / Classify | ICP scoring, account classification, account matching |
| Utility | Imports, exports, webhook handlers, data validation |
The app invokes them with a session JWT; they in turn talk to the database over SQL/PostgREST. Full census (all 26 + their Azure landing): 08_edge_function_census.md.
Layer 3 — The Database (the engine room)
Everything the app does is powered by a Supabase-hosted PostgreSQL database. This is where the real value lives.
| Component | Count | What it does |
|---|---|---|
| Tables | 86 | Accounts, contacts, classifications, scoring, campaigns, outreach, engagement, news/signals, validation |
| Views | 101 | Pre-joined queries for the frontend (rep dashboards, pipeline, analytics) |
| Functions (PL/pgSQL) | 131 | Business logic: messaging strategy resolution, scoring, sync RPCs, campaign state machines |
| RLS policies | 252 | Row-Level Security: every query is filtered by the authenticated user's identity |
| Triggers | 46 | Automated reactions (e.g., 300-char LinkedIn message guard, timestamp stamping) |
| pg_cron jobs | 21 | Scheduled automation: HeyReach sync every 15 min, EmailBison push every 2h, news sync every 4h, daily rollups, weekly data pulls |
| Vault secrets | ~15 | API keys (EmailBison, HeyReach, Anthropic, OpenAI, scrapers) |
| Extensions | pg_cron, pg_net, http, pgcrypto, supabase_vault, uuid-ossp, pg_stat_statements |
Key point: the database is not just storage — it is an active execution environment. The pg_cron jobs, pg_net/http outbound calls, and triggers mean the database does things on its own without any user or frontend interaction.
Layer 4 — The Supply Chain (three separate things to replace)
The CARR database doesn't fill itself. It is fed by a supply chain that runs outside the database on BC infrastructure. This layer is three separate things — and CARR has to stand up its own version of each. Keeping them separate matters because they are replaced in different ways: one is subscriptions, one is compute, one is SaaS workspaces.
4a — Data-source APIs (the feeds that continually pull data in)
The raw material. These APIs are pinged on a schedule to pull in life-science intelligence and people data.
- Life-science + news feeds: ClinicalTrials.gov (trials), NIH RePORTER (grants), SEC EDGAR (filings), PatentsView (patents), PubMed + 22+ RSS feeds (news/signal scoring)
- Sourcing + enrichment SaaS: Sales Navigator (lead search definitions), PhantomBuster (scrapes Sales Nav → ~81K contacts), Clay (Find-People + contact enrichment), FullEnrich (email find + verify)
What CARR must stand up: their own API subscriptions + keys for each third-party service, stored in Key Vault, plus the integration code (the pull/push chains) that calls them. This is a procurement + wiring task, not a rebuild.
4b — The Agent Virtual Environment (the compute that does the work)
The APIs are just taps — something has to run continuously to open them, capture the results, and turn raw data into CARR-ready records. Today that "something" is BC's virtual environment:
- bc-ops VPS crons:
carr_burst_classify_seed.sh(every 30 min),sync_carr_emails.py(every 20 min), Clay push (manual) - Colab notebooks: account import, contact import, account matcher, classifier, enrichment, Clay orchestration, batch email generation — run manually against the CARR DB
The work this environment does, in sequence: capture (pull from the 4a APIs) → summarize (score/condense news + signals) → match (resolve to canonical CARR accounts) → enrich (fill contact/company fields) → internalize (write clean records into the CARR DB for downstream app work).
What CARR must stand up: their own virtual environment — a set of containers / scheduled jobs (Azure Container Apps + Functions timers, or a VPS) running the 7-agent fleet (11_carr_agent_fleet.md) that manages the 4a APIs and performs this enrich/normalize/match pipeline. This is the genuine build.
4c — Outreach platforms + BC Hub (send + seed)
Distinct from the data-pull chain: the platforms that send outreach and the master DB that seeds CARR.
- HeyReach + EmailBison: LinkedIn + email send platforms, wired via 17 Edge Functions (Layer 2). Both a source (replies, accepted connections sync back) and a destination (sends go out)
- BC Hub DB feed: the BC Hub (
mjsgtszehjltxmbxtctz, 17,290-company master) seeds CARR via sync RPCs:sync_cgt_accounts_from_hub,sync_clinical_trials_from_hub,sync_grants_from_hub,sync_news_from_life_science,sync_academic_*_from_hub,import_hub_contacts
What CARR must stand up: their own HeyReach/EmailBison workspaces + keys (the integration code moves with the Edge Functions). The Hub is retired over time — the 4b Ingestion agent pulls the 4a APIs directly instead of leaning on the Hub feed.
The pipeline in one line
4a APIs (pull) → 4b Agent VE (capture · summarize · match · enrich · internalize) → CARR DB (Layer 3) → Edge Functions + app (Layers 2–1)
↕
4c Outreach (send) + Hub (seed)
This is the layer BW has the least visibility into today. It runs entirely on BC infrastructure and pushes into CARR via webhooks and sync RPCs. The full inventory is in 09_upstream_data_agents.md; the target-state fleet is in 11_carr_agent_fleet.md.
Migration target for each layer
| Layer | Current | Azure target | Effort | Key doc |
|---|---|---|---|---|
| 1 — App (frontend) | React/Vite on Lovable (hosting only) + Supabase Auth | Azure Static Web Apps (host) + Entra workforce auth (MSAL) + custom API middleware | M — hosting swap is trivial; auth replacement is the real work | 03, 04 |
| 2 — Edge Functions | 26 Deno/TS functions on Supabase Edge (separate compute from Postgres) | Azure Functions (Node/TS) or Deno on Container Apps + Foundry Model Router + Key Vault | M per group, L in aggregate | 08 |
| 3 — Database | Supabase Postgres | Azure SQL (T-SQL rewrite) — functions, RLS, triggers, crons all rewritten | L — major rewrite, not a port | 07 |
| 4a — APIs | BC-held third-party subscriptions + keys (life-sci/news feeds + sourcing/enrichment SaaS) | CARR's own subscriptions + keys (Key Vault) + integration code | S–M — procurement + wiring, not a rebuild | 09 |
| 4b — Agent VE | BC virtual environment (bc-ops crons + Colab) that captures/matches/enriches/internalizes | CARR's own virtual environment (Container Apps + Functions timers) running the 7-agent fleet | L — the genuine build | 09, 11 |
| 4c — Outreach + Hub | HeyReach/EmailBison (BC workspaces) + BC Hub feed | CARR's own HeyReach/EmailBison workspaces; Hub retired via the Ingestion agent | M — workspaces + phased Hub retirement | 09, 11 |
The full component-by-component crosswalk is in 05_carr_migration_map.md. The sequenced migration plan with decisions and blockers is in 18_migration_roadmap.md.