Skip to content

Architecture

ShipSquares is a lean, AI-native, multi-tenant deploy platform. It runs well on a single small server, with no external managed services required.

Control plane ....... Node.js / TypeScript, Fastify, REST + OpenAPI, WebSocket
Database ............ PostgreSQL + Drizzle ORM (native)
Queue / schedules ... pg-boss (on Postgres) (no extra broker)
Auth ................ better-auth + an RBAC policy layer
Edge / SSL .......... Caddy (native; pluggable driver)
Workloads ........... Docker + docker compose (local socket / over SSH)
MCP ................. Model Context Protocol server (streamable HTTP)
Web ................. React + Vite + Tailwind
Mobile .............. native Swift/SwiftUI + Kotlin/Compose

ShipSquares splits infrastructure from workloads:

  • Native (systemd) — infrastructure: Caddy, the control-plane PostgreSQL, and the control plane itself. OS-managed, own :80/:443, standard backups, and they survive a Docker restart.
  • Docker — workloads: every deployed app and its accessory databases (per-app Postgres/MySQL/Mongo) — isolated, version-pinned, disposable.
  • No extra broker: pg-boss (queue) + Postgres LISTEN/NOTIFY + in-process events keep the queue and pub/sub in Postgres itself.
┌──────────────── Control server (native base) ────────────────┐
push/MCP │ Caddy (:80/:443) → Control plane (Node/TS) │
web/app │ ├─ REST API + OpenAPI + WebSocket │
│ ├─ MCP server │
│ ├─ deploy engine → docker.sock (local) │
│ └─ pg-boss queue │
│ PostgreSQL (single source of truth) │
│ Docker: [apps] [app DBs] │
└─────────────────────────────┬────────────────────────────────┘
│ SSH (agentless)
┌──────────────────────────────▼──── Added VM ────────────────┐
│ Caddy (native) + Docker: [apps] — stateless Docker host │
└──────────────────────────────────────────────────────────────┘

The control plane drives Caddy through its admin API: when an app or domain is added, it writes a route plus a TLS policy, and Caddy issues and renews the certificate automatically — including on-demand TLS for customer custom domains. The proxy is a pluggable driver (Caddy by default; Traefik / nginx alternates) so advanced users can swap it.

  • REST + OpenAPI — orgs, teams, members, servers, apps, domains, env/secrets, deployments, logs, webhooks, and API keys. One OpenAPI spec generates the clients for web, iOS, Android, and the MCP server.
  • MCP server — exposes tools (deploy_app, rollback, get_status, tail_logs, set_env, add_domain, list_apps, …) over streamable HTTP with API-key auth, all audited — so “ship it” is something an AI agent can do.
  • Mobile — native iOS + Android built on the same OpenAPI client, with push for deploy status and a WebSocket for live logs.
  1. git push → webhook (HMAC-verified) hits the control plane.
  2. Resolve repo + branch → app → target server.
  3. Build & run — locally via the Docker socket, or remotely over SSH → docker compose; pre-up hooks (e.g. migrations) run first.
  4. Route — write the domain → container into that server’s Caddy; the certificate is issued automatically.
  5. Stream & record — live logs over WebSocket; the deployment and its steps are persisted; you get a push/web notification.
  • Control server: one command installs Caddy + PostgreSQL + the control plane as systemd units and creates the first owner account. See Installation.
  • Add a server: enter an SSH host/key in the UI and the platform installs Docker + Caddy on the remote VM — agentlessly.

Every action is RBAC-checked, secrets are sealed and never logged, and only the webhook endpoint is internet-facing beyond the proxy. See Security for the full model.