docs: ADR 0022 hosting on DigitalOcean (WeOwn Cloud)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SdXCbrN5PtGExkpvMaMHx
This commit is contained in:
Claude
2026-10-12 14:36:49 +00:00
parent 1634763180
commit ab485703f2
4 changed files with 53 additions and 1 deletions
+1
View File
@@ -50,6 +50,7 @@ The `.agents/skills/` directory is a family of rigor skills modeled on Cursor's
- Frontend: Next.js (App Router) + React + TypeScript. Server layer holds tokens; browser gets a session cookie only (ADR 0018). Existing Vite shell is being migrated.
- Sign-in: emailed 8-character code, emailed link and passkeys (ADR 0019)
- Cloud sites: provisioned on WeOwn Cloud behind the platform interface (ADR 0020)
- Hosting: DigitalOcean for Wursor and WeOwn Cloud, one VPC per plane, Terraform (ADR 0022)
- Direction: see PRD.md (Headless, revision 4) and IMPLEMENTATION.md section 0
- Sandboxes: Docker on VPS, pre-baked WordPress image, overlayfs layers, media proxied (not copied)
- Plugin: standard WordPress PHP plugin, REST API + token auth
+1 -1
View File
@@ -8,7 +8,7 @@ The project is pre-1.0. Versions below `1.0.0` are internal milestones, not publ
### Added
- ADRs 0018 to 0021: Next.js web app (partly supersedes ADR 0011), sign-in by code, link and passkeys, Cloud provisioning on WeOwn Cloud, and keeping the "never sees a diff" rule wording. PRD, IMPLEMENTATION and AGENTS.md updated to match.
- ADRs 0018 to 0022 (0022: hosting on DigitalOcean): Next.js web app (partly supersedes ADR 0011), sign-in by code, link and passkeys, Cloud provisioning on WeOwn Cloud, and keeping the "never sees a diff" rule wording. PRD, IMPLEMENTATION and AGENTS.md updated to match.
- `docs/prd-assets/headless-architecture.png`, the architecture diagram used in the PRD.
- Design reference: Figma file "Wursor - Experiment" (Design system, Product Design, Marketing site and Brand Guideline pages).
- **Monorepo workspace** — `pnpm` workspace (`api`, `web`, `e2e`), root `package.json` / `pnpm-workspace.yaml` / `tsconfig.base.json`, and a PHP `plugin` package (`composer.json`). Empty packages by design (see [ADR 8](docs/decisions/0008-empty-packages-not-stubs.md)).
@@ -0,0 +1,50 @@
# 22. Wursor and WeOwn Cloud run on DigitalOcean
- **Status:** Accepted for the platform choice. The service-level picks below are recommendations to confirm in the infrastructure spike (see Consequences).
- **Date:** 2026-10-12
## Context
[ADR 0020](0020-weown-cloud-provisioning.md) puts Cloud sites on WeOwn Cloud, and WeOwn uses DigitalOcean. Wursor itself will be hosted there too. The PRD describes three separate environments that must not share a network trust boundary: the control plane (Next.js app, Wursor API, Conductor, identity), the execution plane (sandboxes, verification workers, evidence store) and the hosting plane (Cloud sites). The existing infrastructure brief ([DEVOPS.md](../../infrastructure/DEVOPS.md)) assumes a single Docker VPS and a Vite static web build, and `infrastructure/terraform/` is empty.
## Decision
Host all three planes on **DigitalOcean**, each in its own VPC, defined as code with **Terraform** (DigitalOcean provider) in `infrastructure/terraform/`.
Recommended mapping:
| Need | DigitalOcean product | Why |
|---|---|---|
| Next.js app, Wursor API, Conductor | App Platform (containers) if its streaming and timeout limits fit the run stream; otherwise Droplets or DOKS | Managed TLS, deploys from the container registry, small ops load. |
| Wursor database | Managed PostgreSQL with point-in-time recovery | PRD section 21 requires PITR and 15-minute backups, and a quarterly restore drill. |
| Queue and cache | Managed Redis or Valkey | Event queue and short caches. |
| Evidence store, site archives, backups | Spaces (S3-compatible) with versioning, private by default | Signed expiring links for evidence and archive downloads. |
| Sandboxes (execution plane) | Droplets running Docker, in a separate VPC | Matches the existing `DockerodeClient`, warm pool and GC. |
| Cloud sites (hosting plane) | Droplets (or DOKS) in a separate VPC, one isolated container per site, own database credentials and file space | PRD SH-14 and the Cloud isolation rows in section 18.1. |
| Images | Container Registry | Base WordPress image and service images. |
| DNS, domains, certificates | DigitalOcean DNS plus automated certificates (for example Caddy with on-demand TLS) for customer domains | SH-12 needs certificates issued as customers connect domains. |
| Preview origin | Wildcard certificate on a separate registrable domain behind a load balancer | PRD requires previews on a different site from the app (SB-02). |
Network rules: the hosting plane has no inbound path to the Wursor API. Sandboxes have deny-by-default egress through a proxy (SB-03). Only the Conductor reaches the hosting plane, with a service token.
### Options considered
- **DigitalOcean (chosen).** WeOwn's existing provider, so no new vendor or contract, and the existing Docker and `dockerode` work carries over.
- **Another cloud for Wursor, DigitalOcean only for Cloud sites.** More capability, but two clouds to run for a small team.
### Rejected
- Another cloud for the control plane: adds a second provider with no stated need.
## Consequences
- [DEVOPS.md](../../infrastructure/DEVOPS.md) is out of date: it describes React + Vite and a single VPS. Update it after the spike.
- Confirm these before building on them, each as a short written result in `spikes/`:
1. Whether App Platform supports the long-lived run stream (HTTP timeouts, resume after reconnect), or the Conductor needs Droplets or DOKS.
2. The isolation level achievable for Cloud sites on Droplets. The PRD's open choice is container versus microVM. Do not assume a microVM runtime is available on Droplets; test it, and treat container hardening plus a cross-site isolation test in CI as the baseline.
3. Customer-domain certificate issuance at the expected volume.
4. Backup and restore: daily verified restores of Cloud sites, 30-day retention, a backup before every change (SH-04, SH-14).
5. Cost per Cloud site and per sandbox, to inform plans and pricing (D-HL-8).
- WeOwn operations staffing (on-call, patching to the 72-hour target, abuse handling) is a readiness item from ADR 0020, not something DigitalOcean removes.
- Secrets live in the platform secret store and the Terraform state is stored in a private Spaces bucket with locking; never in the repo.
- Terraform plans run in CI against a staging project. Nothing is applied to production from a developer machine.
+1
View File
@@ -35,6 +35,7 @@ Each ADR is a single file following the [Nygard format](https://cognitect.com/bl
| [0019](0019-sign-in-methods.md) | Sign-in supports an emailed code, an emailed link and passkeys | Accepted |
| [0020](0020-weown-cloud-provisioning.md) | Cloud sites are provisioned on WeOwn Cloud | Accepted |
| [0021](0021-keep-no-diff-rule-wording.md) | Keep the "never sees a diff" rule in AGENTS.md as written | Accepted |
| [0022](0022-digitalocean-hosting.md) | Wursor and WeOwn Cloud run on DigitalOcean | Accepted (service picks to confirm) |
## How to add one