BioCreative Strategies × CARR Biosystems Azure Migration Program

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

Layer 1 — App (frontend)
React / Vite SPA
22 pages · TypeScript
Built in GitHub
Lovable
Hosting only
CDN + custom domain
Supabase Auth
Email/password login
Session JWT
→ Azure: Static Web Apps (host) + Entra workforce auth (MSAL)
app calls (supabase-js invoke) · JWT
Layer 2 — Edge Functions (backend logic)
AI / Content
generate-content
message generation
Outreach Sync
HeyReach + EmailBison
send · reply/stat sync
Scoring / Classify
ICP scoring
account classify · match
Utility
imports · exports
webhooks
26 functions · Deno / TypeScript · run on Supabase Edge (separate compute from Postgres) — the "backend verbs" the app calls
→ Azure: Azure Functions (Node/TS) or Deno on Container Apps + Foundry Model Router + Key Vault
SQL / PostgREST · RLS
Layer 3 — Database
Schema & Data
86 tables
101 views
In-DB Business Logic
131 functions · 252 RLS
46 triggers
Automation
21 pg_cron jobs
15-min → weekly
Secrets & Networking
Vault (~15 keys)
pg_net / http (outbound)
Not just storage — an active execution environment: crons fire, triggers react, and the DB makes outbound HTTP calls on its own
→ Azure: Azure SQL (T-SQL rewrite) + SQL Agent/Elastic Jobs + Key Vault + Functions timers
Webhooks · sync RPCs · Hub feed
Layer 4 — The Supply Chain (three separate things to replace)
4a
Data-source APIs
Life-sci + news feeds:
ClinicalTrials · NIH · SEC · PatentsView · PubMed · 22 RSS

Sourcing + enrichment SaaS:
Sales Navigator · PhantomBuster · Clay · FullEnrich
CARR provides: own API subscriptions + keys + integration code
4b
Agent Virtual Environment
The BC compute that runs the agents:
bc-ops VPS crons · Colab notebooks

Work it does:
capture → summarize → match → enrich → internalize into CARR
CARR provides: own virtual environment (containers / scheduled jobs) running the 7-agent fleet
4c
Outreach + Hub
Send platforms:
HeyReach · EmailBison
(reply source + send destination)

Seed feed:
BC Hub DB (17K-company master)
CARR provides: own HeyReach/EmailBison workspaces; Hub retired via Ingestion agent
→ Azure: 7-agent CARR fleet on Foundry + Container Apps
4a APIs
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 .docx

17 - 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.