Skip to main content

ADR-0004: Hosting Topology and Platform Selection

Status

Accepted - 2025-10-24


Context

TVL Platform requires hosting for:

  • Frontend: React web app (static assets + SSR)
  • Backend: Node.js API server
  • Workers: Background job processors
  • Database: PostgreSQL
  • Cache/Queue: Redis
  • Observability: Metrics, logs, traces

Requirements:

  • Fast time-to-market (< 3 months)
  • Low operational overhead (small team)
  • Cost-effective for MVP (< $200/mo)
  • Scalable to 10,000+ users
  • 99.9% uptime target

Decision

Multi-platform managed services architecture:

ComponentPlatformRationale
FrontendVercelBest DX, global CDN, auto-scaling
Backend APIRailway or Fly.ioSimple Docker deployment, auto-scaling
DatabaseSupabaseManaged Postgres with RLS, Auth built-in
Cache/QueueUpstash RedisServerless Redis, pay-per-request pricing
ObservabilityGrafana Cloud + SentryFree tier sufficient for MVP
StorageAWS S3 or Supabase StorageObject storage for media

Frontend: Vercel

# vercel.json
{
"framework": "vite",
"buildCommand": "npm run build",
"outputDirectory": "dist",
"regions": ["iad1"], # US East (closest to API)
"env": {
"VITE_API_URL": "https://api.tvl.com"
}
}

Cost: $0/mo (Hobby) → $20/mo (Pro for custom domain + analytics)

Backend: Railway

# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
CMD ["node", "dist/server.js"]
# railway.toml
[build]
builder = "dockerfile"

[deploy]
healthcheckPath = "/health"
healthcheckTimeout = 30
restartPolicyType = "on_failure"

Cost: $5/mo (Hobby) → $20/mo (Pro with autoscaling)

Alternative: Fly.io (similar pricing, slightly more complex)

Database: Supabase

Plan: Free (dev/staging) → Pro $25/mo (production)

Features Used:

  • Postgres 15 with RLS
  • Connection pooler (PgBouncer)
  • Automatic backups
  • Supabase Auth (Google OIDC)

Redis: Upstash

Plan: Free (10k commands/day) → Pay-as-you-go $0.20/100k commands

Features:

  • Serverless Redis (no idle cost)
  • TLS by default
  • Global replication (future)

Alternatives Considered

Alternative 1: AWS (ECS + RDS + ElastiCache)

Rejected

Pros:

  • Enterprise-grade
  • Full control
  • Can optimize costs at scale

Cons:

  • Steep learning curve (VPC, security groups, IAM)
  • High operational overhead
  • More expensive ($100-500/mo for MVP)
  • Slower time-to-market (2-4 weeks setup)

Decision: Managed platforms faster for MVP; migrate to AWS if needed at scale.


Alternative 2: Single Platform (all on Railway)

Rejected

Pros:

  • Simpler (one platform)
  • Unified billing

Cons:

  • Vercel better for frontend (global CDN, edge functions)
  • Railway doesn't have managed Postgres (must self-host)
  • Supabase RLS + Auth valuable

Decision: Multi-platform worth the complexity for better DX and features.


Alternative 3: Self-Hosted on DigitalOcean

Rejected

Pros:

  • Full control
  • Lower cost at scale ($50-100/mo)

Cons:

  • Must manage Postgres, Redis, backups, scaling, security
  • High ops burden (not suitable for small team)
  • No managed Auth or RLS

Decision: Managed services reduce ops burden; worth the cost for MVP.


Consequences

Positive

  1. Speed

    • Deploy frontend in < 1 minute (Vercel)
    • Deploy backend in < 5 minutes (Railway)
    • Zero infrastructure setup
  2. Developer Experience

    • Git-based deployments (push to deploy)
    • Preview deployments for PRs (Vercel)
    • Automatic HTTPS (Let's Encrypt)
  3. Cost

    • Total: ~$50-100/mo for production MVP
    • Free tiers for staging/dev
    • No upfront costs
  4. Scalability

    • Vercel: global CDN, auto-scaling
    • Railway: horizontal scaling (add instances)
    • Supabase: connection pooler handles 1000+ connections

Negative

  1. Vendor Lock-in

    • Dependent on 4 platforms (Vercel, Railway, Supabase, Upstash)
    • Migration effort if switching
    • Mitigation: Use Docker (portable), keep business logic platform-agnostic
  2. Cost at Scale

    • Managed services more expensive than self-hosted at large scale
    • Mitigation: Optimize when revenue justifies; enterprise plans available
  3. Limited Control

    • Can't customize infrastructure (e.g., network topology)
    • Mitigation: Sufficient for MVP; re-evaluate post-PMF

Migration Path

If Scaling Beyond Managed Services:

Phase 1: Optimize Managed ($100-500/mo)

  • Upgrade to Pro/Team plans
  • Enable autoscaling
  • Add read replicas (Supabase)

Phase 2: Hybrid ($500-2000/mo)

  • Keep frontend on Vercel (CDN)
  • Move backend to AWS ECS
  • Keep Supabase (or migrate to AWS RDS)

Phase 3: Fully Self-Hosted ($2000-10000/mo)

  • Multi-region AWS
  • Kubernetes for orchestration
  • Dedicated ops team

Trigger: Revenue > $500k/year or scaling limits hit.


Validation Checklist

  • Frontend deploys in < 2 minutes
  • Backend deploys in < 5 minutes
  • Zero-downtime deployments
  • HTTPS enforced on all endpoints
  • Health checks configured
  • Automatic backups (database)
  • Monitoring and alerting (Grafana, Sentry)
  • Cost tracking per environment

Sources

  • docs/01-architecture/deployment-views.md
  • docs/00-overview/platform-overview.md