Overview
Components, local development, deployment topology, and an honest capabilities list.
Components
- control-plane (Go + Postgres) — the
/v1REST API, the connect rails, the propagation poller, and/internal/ask. - edge (Go, on-demand TLS via ACME autocert + reverse proxy) — terminates TLS
and proxies live custom domains, gated by
ask. - console (
apps/app, Next.js) — the developer dashboard and this docs site; it brokers control-plane calls with a sealed per-tenant key. - mcp (Go) — an optional Model Context Protocol server
that exposes domain search/connect/purchase to AI agents over JSON-RPC; it wraps
the same control-plane
/v1API. - Postgres — the system of record.
The full compose files, Caddyfile, and ops scripts live in
infra/; a
component-level design overview is in docs/architecture/ARCHITECTURE.md.
Local development
make up # docker compose: Postgres + control-plane + edge
make build # go build across the services
make test # go test across the servicesThe control-plane listens on :8080; the edge on :8443 (TLS) and :80
(ACME HTTP-01). With no JUSTEASY_DATABASE_URL set the control-plane uses an
in-memory store, and the edge runs in dev mode (self-signed certs + a mock gate)
until EDGE_ASK_URL / EDGE_ACME_PROD are set.
Deployment topology
- Run Postgres and set
JUSTEASY_DATABASE_URL(required in production). - Run the control-plane; expose only
/v1/*publicly. Keep/internal/askreachable only from the edge, protected by a sharedEDGE_ASK_SECRET. - Run the edge with a public IP; point customer domains at it. Set
EDGE_ASK_URLto the control-plane origin andEDGE_ACME_PROD=1(withEDGE_ACME_EMAIL) for real Let's Encrypt certs. - Set
JUSTEASY_MANAGEMENT_KEYandJUSTEASY_PROVISION_SECRET— the control-plane refuses to start in production with provisioning left open.
Full environment-variable tables are on the configuration page.
Capabilities & limitations (honest)
What is fully automated today, and what still needs a human or a business step:
| Area | Status |
|---|---|
| DNS detection + record synthesis | ✅ automated (domains:check, connections) |
| Manual rail (copy records, poll to live) | ✅ automated end-to-end |
| API-token rail (Rail B) | ✅ automated; the customer must mint a scoped provider token |
| Machine-credential providers (Route 53 / GCP / Azure) | ✅ adapters built; the customer creates the cloud identity |
| Domain Connect (Rail A) | ✅ code-complete; needs DC_SIGNING_KEY_FILE configured for signed templates |
| OAuth-into-provider (Rail C) | ⚠️ code-complete, but you must register an OAuth app per provider and pass its approval process (OAUTH_<PROVIDER>_CLIENT_ID/_SECRET) |
| On-demand TLS + reverse proxy | ✅ code-complete at the edge; certs are Let's Encrypt staging (not browser-trusted) until EDGE_ACME_PROD=1 |
Secure — /ssl certificate lifecycle | ⚠️ built but flag-gated; every /ssl route reports not-configured unless SECURE_ENABLED=1 |
Power — /power edge origin lifecycle | ⚠️ built but flag-gated; off unless POWER_ENABLED=1 |
Monitor — on-demand monitor:check | ✅ automated; the hourly drift sweep (and its domain.record_missing/restored alerts) is off unless MONITOR_ALERTS_ENABLED=1 |
| MCP agent server | ✅ built; runs as a separate services/mcp process, off by default |
| Domain purchase (Sell) | ⚠️ fail-closed; disabled unless SELL_PURCHASE_ENABLED, and needs registrar credentials |
| Billing checkout/portal | ⚠️ served only when STRIPE_SECRET_KEY and the STRIPE_PRICE_* ids are wired; the plan catalog is always public |
| Connection delete / archive | ❌ no API endpoint yet (see Offboarding) |
| Provider-eligibility gates | ⚠️ some providers (GoDaddy tier, Namecheap IP allowlist) gate who can get API access — not removable in code |
The takeaway: the code paths are complete, but "frictionless as a service" for a given provider can still require an OAuth-app approval or a provider account tier that only your company (or the customer) can obtain.