Skip to content

Multi-Repo Strategy ​

Why Nine Repositories (And Growing) ​

The VelaPay workspace has evolved from 5 repos to 11 across 8 milestones:

vela-labs/
├── vela-protocol/   # Anchor/Rust on-chain program (dual: protocol + transfer hook)
├── vela-sdk/        # TypeScript SDK + CLI + webhook event schemas
├── vela-dashboard/  # Merchant dashboard + backend API
├── vela-admin/      # Internal admin ops dashboard
├── vela-checkout/   # Hosted checkout at pay.velapay.com
├── vela-portal/     # Subscriber portal at portal.velapay.com
├── vela-widget/     # Embedded checkout for merchant pages
├── vela-webhook/    # Webhook event SDK (@vela/webhook)
├── vela-web/        # Landing page at velapay.com
├── vela-docs/       # Developer documentation at docs.velapay.com
└── vela-synthetic/  # E2E cron worker for staging validation

Evolution Timeline ​

PhaseRepo CountWhat Was AddedWhy
v1.05vela-protocol, vela-sdk, vela-dashboard, vela-web, vela-docsInitial workspace — the billing primitive works
v1.16+ vela-widgetMerchants needed embeddable checkout on their own pages
v1.27+ vela-adminProtocol team needed internal ops dashboard
v1.59+ vela-checkout, vela-portalHosted billing surfaces for payment links and subscriber self-service
v1.811+ vela-webhook, vela-syntheticTyped webhook delivery and continuous staging validation

Each new repo was added when a distinct runtime concern, auth model, or deploy lifecycle emerged that couldn't be cleanly contained in an existing repo.

Why Not Monorepo ​

A monorepo would add complexity without benefit for this project:

  1. Different deploy targets — Protocol deploys to Solana, dashboard to Railway, everything else to Cloudflare Workers. Monorepo CI would need 5+ deploy pipelines.
  2. Different toolchains — Rust for protocol, TypeScript for everything else. Shared tooling is limited to git.
  3. Different update cadences — SDK needs frequent small updates, protocol needs careful versioning. Monorepo would force coordinated releases.
  4. Different testing strategies — cargo test with LiteSVM for protocol, bun test for TypeScript repos. Shared test infrastructure is minimal.
  5. Different security models — Admin has wallet-gated SIWS auth, dashboard has email-primary auth, checkout/portal are public-facing with magic-link auth. Monorepo makes auth boundary management harder.
  6. Cleaner ownership — Each team (or agent session) works in their own repo without cross-contamination.

CI/CD Strategy Per Repo ​

RepoCI PipelineCD TargetTrigger
vela-protocolcargo test + anchor buildSolana devnet (manual deploy)Push to master
vela-sdkbun test + tsc type checknpm publish (@vela/sdk)Version tag
vela-dashboardbun test + Docker buildRailway (SSR) + Cloudflare (Worker, D1)Push to master
vela-adminbun test + buildCloudflare WorkersPush to master
vela-checkoutbun test + buildCloudflare WorkersPush to master
vela-portalbun test + buildCloudflare WorkersPush to master
vela-widgetbun test + buildCDN (Cloudflare Workers static)Version tag
vela-webhookbun test + schema-diff checknpm publish (@vela/webhook)Version tag
vela-webbun test + Astro buildCloudflare Workers (static)Push to master
vela-docsbun test + Astro buildCloudflare Workers (static)Push to master
vela-syntheticbun test + buildCloudflare Workers (cron)Push to master

Special CI Patterns ​

  • Schema-diff check (vela-webhook): CI enforces additive-only event evolution. New event types are allowed; removing or changing existing events fails the build.
  • Staging E2E (vela-synthetic): 15-minute cron against devnet staging. Pages on failure.
  • Playwright E2E (vela-checkout, vela-portal): Full browser tests with Mailpit for email-dependent flows.

Cross-Repo Update Protocol ​

Protocol → SDK → Consumers ​

When vela-protocol updates, a specific chain of updates is required:

1. vela-protocol: Make changes, run cargo test, anchor build
       ↓ IDL output
2. vela-sdk: Copy new IDL, update instruction builders, run bun test
       ↓ published to npm
3. vela-dashboard: Update @vela/sdk dependency, adapt to API changes
   vela-checkout: Update @vela/sdk dependency, adapt to API changes
   vela-portal: Update @vela/sdk dependency, adapt to API changes
   vela-widget: Update @vela/sdk dependency, adapt to API changes
   vela-webhook: Update @vela/sdk dependency, adapt to event schemas

Version Compatibility Rules ​

  • Protocol ↔ SDK: Must match exactly. SDK encodes program IDL, instruction discriminators, and account layouts.
  • SDK → Consumers: Semantic versioning. Breaking SDK changes require major version bump.
  • Consumers → Each Other: No direct dependencies. Communication via shared D1 database and on-chain state.

Coordinated Change Protocol ​

  1. Update protocol first (source of truth).
  2. Update SDK second (encoding layer).
  3. Update consumers last (product surfaces).
  4. Use conventional commits for tracking (feat(protocol):, feat(sdk):, feat(dashboard):).
  5. Each step is a separate PR and deploy.

Why vela-checkout and vela-portal Are Separate ​

From the Dashboard ​

vela-checkout and vela-portal were extracted from vela-dashboard in v1.5 because they have fundamentally different runtime concerns:

Dimensionvela-dashboardvela-checkoutvela-portal
Auth modelEmail-primary + org membershipPublic (Turnstile-gated)Magic-link + SIWS
AudienceMerchants (authenticated)Subscribers (anonymous)Subscribers (authenticated)
RuntimeRailway SSR + CF Worker APICF Worker onlyCF Worker only
Deploy cadenceChanges with merchant featuresChanges with checkout UXChanges with portal features
Security boundaryInternal — merchant dataPublic — payment flowPublic — subscription management
Domainapp.velapay.compay.velapay.comportal.velapay.com

Why Not Merge Them ​

Merging checkout or portal into the dashboard would:

  • Expose merchant auth boundaries to public traffic.
  • Force a single deploy cycle for merchant features and subscriber UX.
  • Create a larger attack surface (checkout doesn't need merchant auth, portal doesn't need merchant data).
  • Make independent scaling harder (checkout has bursty traffic during payment campaigns).

How They Communicate ​

Checkout and portal share patterns with the dashboard:

  • Checkout session creation: Both vela-checkout and vela-portal (for plan switching) create checkout sessions via a shared pattern that writes to D1.
  • Public billing apps proxy to dashboard internal routes: Some API endpoints are shared, with the dashboard Worker handling the backend logic.
  • D1 database: Shared database for checkout sessions, subscription state, and billing records.

Trade-offs Analysis ​

What Multi-Repo Gives Us ​

BenefitImpact
Independent deploysProtocol can be redeployed without touching the dashboard. Checkout can be updated without touching the widget.
Independent versioningSDK can publish a patch without coordinating with protocol. Widget can version independently from docs.
Clearer ownershipEach repo has a clear owner, clear test suite, clear deploy pipeline.
Smaller clone/fetch sizeOnly clone what you need. Protocol developers don't need checkout code.
Optimal toolchain per repoRust for protocol, TypeScript+Hono for Workers, Astro for docs. No compromise.
Auth boundary isolationEach repo enforces its own auth model without cross-contamination.

What Multi-Repo Costs ​

CostMitigation
No atomic commits across reposConventional commits + update protocol. Accept that cross-repo changes require coordination.
Shared config managed separately@biomejs/biome config is similar but not shared. Acceptable divergence.
Cross-repo refactoring is harderProtocol versioning (v1.7 reserved space) makes additive changes the default. Breaking changes are rare and planned.
More CI pipelines to maintainEach pipeline is simple (build + test + deploy). Complexity per pipeline is low.
Dependency drift across reposWorkspace-level bun.lock anchors versions. SDK version pinning prevents drift.

When Monorepo Would Be Better ​

If the team grows to 5+ engineers working on the same product surfaces, monorepo benefits (atomic commits, shared CI, unified versioning) might outweigh the deploy isolation benefits. For the current team size and architecture, multi-repo is the right choice.

GitHub Organization Structure ​

All repos live under the GitHub organization:

github.com/vela-labs/
├── vela-protocol        # Anchor/Rust on-chain program
├── vela-sdk             # TypeScript SDK + CLI
├── vela-dashboard       # Merchant dashboard
├── vela-admin           # Internal admin dashboard
├── vela-checkout        # Hosted checkout
├── vela-portal          # Subscriber portal
├── vela-widget          # Embedded checkout
├── vela-webhook         # Webhook event SDK
├── vela-web             # Landing page
├── vela-docs            # Developer documentation
├── vela-synthetic       # E2E cron worker
└── (internal-wiki)      # Internal wiki (separate repo or workspace directory)

Branch Strategy ​

  • master: Default branch for all repos. Protected by CI.
  • Feature branches: Used during development, merged via PR.
  • No release branches: Continuous deployment from master.

Workspace-Level Files ​

The workspace root (vela-labs/) contains:

  • .planning/: Authoritative project state (requirements, roadmap, state).
  • internal-wiki/: This wiki.
  • Root strategy docs (01-vela-labs-brand.md through 10-future-vision-layer3-and-beyond.md): Founding context.
  • CLAUDE.md / AGENTS.md: AI agent instructions shared across repos.
  • docker-compose.staging.yml: Staging environment for E2E tests.

Shared Dependencies ​

All TypeScript repos share these dependencies (managed separately per repo):

PackageVersionPurpose
typescript5.8+Type checking
@biomejs/biomelatestLinting + formatting
wrangler4.78.xCloudflare CLI (Workers repos)
@vela/sdklatestProtocol client (all product repos)

No shared package.json — each repo manages its own dependencies independently.

.claude Directory ​

Each repo has a .claude/ directory with:

  • Project context (CLAUDE.md with repo-specific instructions).
  • Agent instructions for automated development.
  • Repository-specific conventions and constraints.

This enables AI agents to work effectively in any repo without cross-repo context.

Internal knowledge base for the Vela Labs workspace.