How it fits together
import { Aside } from ‘@astrojs/starlight/components’;
Melbora runs on AWS and ships everything client-facing through Vercel. At a glance:
┌─────────────┐ JWT ┌──────────────────┐│ Portal │ ─────────▶ │ API Gateway ││ (Vite SPA) │ │ (us-east-1) │└─────────────┘ └────────┬─────────┘ │┌─────────────┐ vc_pat_ ││ CLI / SDK │ ─────────────────────┤│ MCP / cURL│ │└─────────────┘ ▼ ┌──────────────────┐ │ Lambda (api.ts) │ │ custom Router │ └────────┬─────────┘ │ ┌────────────┬───────────────┼───────────────┬──────────────┐ ▼ ▼ ▼ ▼ ▼┌──────────────┐ ┌──────────┐ ┌─────────────┐ ┌────────────┐ ┌─────────────┐│ DynamoDB │ │ Secrets │ │ SQS │ │ Cognito │ │ Integrations││ (~12 tables) │ │ Manager │ │ (provision, │ │ (auth) │ │ GH, Vercel,││ │ │ │ │ webhooks) │ │ │ │ Shopify,…) │└──────────────┘ └──────────┘ └──────┬──────┘ └────────────┘ └─────────────┘ │ ▼ ┌──────────────────┐ │ Worker Lambdas │ │ (provisioning, │ │ webhook, SEO) │ └──────────────────┘The pieces
Section titled “The pieces”Portal (packages/portal) — Vite + React + React-Router SPA served
at vantageconnections.dev. Cognito JWT auth. Two role groups: admin
(operators) and client (end customers managing their own site). The
Blueprint canvas, the new-website wizard, the content editor, the API
key minter all live here.
API (packages/api) — a single Lambda function (handlers/api.ts)
fronted by API Gateway. Routes are registered in packages/api/src/routes/*.ts,
collected into one custom Router at startup. Two auth modes:
- JWT for portal traffic (paths without
/v1/prefix) - PAT (
vc_pat_*bearer tokens) for SDK / CLI / MCP traffic (paths under/v1/)
Same route handlers run for both — the router just resolves a different
AuthContext upstream.
Infrastructure (packages/infra) — AWS CDK definition of the whole
stack. DDB tables, the API Gateway, the Lambdas, SQS queues, Cognito
user pools, Secrets Manager entries, IAM roles. cdk deploy ships it.
Data layer — about a dozen DynamoDB tables, accessed via
packages/api/src/repositories/*.ts. The naming is vantage-<entity>:
vantage-websites, vantage-website-services, vantage-domains,
vantage-clients, vantage-provisioning-jobs, etc. No relational DB.
Integrations (packages/api/src/integrations/*.ts) — wrappers
around each third-party API: GitHub, Vercel, Shopify Admin GraphQL,
Cal.com, Resend, OpenRouter, Stripe. Each module hides the auth flow
and exposes a few high-level operations.
Worker Lambdas — SQS-triggered for long-running work that can’t fit in an API request:
- Provisioning worker drives the multi-step pipeline for new websites and feature toggles
- Shopify webhook worker processes webhook deliveries (GDPR ack, APP_UNINSTALLED cleanup)
- SEO cron runs scheduled scans + GEO probes
Request lifecycle (CLI → API)
Section titled “Request lifecycle (CLI → API)”When you run vantage websites list:
- CLI loads
~/.vantage/credentials.json, picks up thevc_pat_*token - SDK sends
GET /v1/websiteswithAuthorization: Bearer vc_pat_... - API Gateway forwards to the API Lambda
- Router sees
/v1/prefix → strips it, switches to PAT auth mode - PAT resolver hashes the token, looks it up in
vantage-api-keys, resolves to a Cognito sub + role - Route matched:
GET /websites(admin-only) → admin role required - Handler queries
vantage-websites(scan or query depending on role) - JSON serialized, returned
Round-trip is typically 80-200ms warm, 400-800ms cold start.
Provisioning lifecycle (CLI → SQS → worker)
Section titled “Provisioning lifecycle (CLI → SQS → worker)”When you run vantage websites create:
- API handler validates input, creates the
Websiterow invantage-websiteswithstatus: "provisioning" - API enqueues a
ProvisioningJobmessage to the SQS queue - API returns the Website immediately — the deploy hasn’t started yet
- SQS triggers the provisioning worker Lambda
- Worker walks the orchestrator pipeline step-by-step:
github_create_repo(from template)github_invite_collaboratorvercel_create_projectvercel_set_env_varsvercel_initial_deployfinalize→ flipsstatus: "active"
- Each step persists progress to
vantage-provisioning-jobsso the portal can show live state - Failures retry per-step; permanent failures mark the job
failedwith a reason
See Provisioning for the full step-by-step.
Webhook lifecycle (third party → SQS → worker)
Section titled “Webhook lifecycle (third party → SQS → worker)”When Shopify sends an APP_UNINSTALLED webhook:
- POST hits
/webhooks/shopify(public route, no JWT/PAT) - Handler verifies the HMAC signature with the shared webhook secret
- Cross-checks the
X-Shopify-Shop-Domainheader against the websiteId in the URL — defense against cross-tenant webhook spoofing - Enqueues the verified payload to SQS
- Returns
200 OKimmediately (Shopify cuts you off if you delay) - Webhook worker Lambda processes the payload: deletes the WebsiteService row, revokes secrets, log-acks GDPR compliance webhooks
Auth model in one paragraph
Section titled “Auth model in one paragraph”Three auth flavors. Portal uses Cognito JWT — sign in with email, JWT issued, sent on every request. SDK / CLI / MCP use personal access tokens (vc_pat_*) minted in the portal under Settings → API keys; bearer-authed against /v1/*. Webhooks use shared secrets verified per-message — no Cognito, no PAT. The router resolves the appropriate AuthContext upstream so handlers don’t care which mode they’re running in.
Where state lives
Section titled “Where state lives”| State | Where |
|---|---|
| Websites, Services, Domains, Jobs | DynamoDB |
| Auth users + groups | Cognito |
| OAuth tokens (Shopify, etc.) | Secrets Manager |
| Webhook payloads in flight | SQS |
| CMS content documents | DynamoDB (vantage-website-content) |
| Blueprint node positions | DynamoDB (vantage-website-blueprint-layout) |
| Vercel deploy state | Vercel (we don’t mirror) |
| GitHub repo state | GitHub (we don’t mirror) |
The general principle: Melbora owns the platform’s view of each integration; the integration owns its own state. We don’t re-store deploys, commits, products — we query the source of truth on demand and cache only what’s hot.
Where to read next
Section titled “Where to read next”- Concepts → Websites — the data model in detail
- Concepts → Provisioning — the orchestrator pipeline
- Reference → SDK — programmatic access from TypeScript