Skip to content

Architecture

Principles

  • Serverless and usage-based. Every service scales to zero: no idle cost when nobody draws. Lambda, API Gateway HTTP, DynamoDB on-demand, S3, CloudFront, Cognito.
  • Multiple sites, one product. Canvas app, marketing site, docs, API, and auth each live on their own hostname, all defined in configuration.
  • Multi-account. dev, stage, prod, and a CI/CD account. Pipelines deploy cross-account; developers never hold prod credentials.
  • Local-first app. The canvas works offline; cloud sync is an enhancement, not a dependency.

Component diagram

┌────────────────────────── AWS (per environment account) ──────────────────────────┐
│ │
Browser │ CloudFront + WAF S3 (static sites) API Gateway + WAF │
┌───────────────┐ │ ┌──────────────────┐ ┌───────────────────┐ ┌──────────────────────┐ │
│ canvas app │──────┼──▶│ app.<domain> │────▶│ app assets │ │ │ │
│ (engine+UI) │ │ │ www.<domain> │────▶│ www assets │ │ /documents/* (JWT) │ │
│ config.json │ │ │ docs.<domain> │────▶│ docs assets │ │ /healthz (public) │ │
└──────┬────────┘ │ └──────────────────┘ └───────────────────┘ │ /published/{t} (pub)│ │
│ │ └──────────┬───────────┘ │
│ OAuth PKCE │ Cognito │ │
├───────────────┼──▶┌─────────────────────────────────────────────┐ │ │
│ │ │ user pool (MFA, adaptive auth) │ │ │
│ │ │ hosted UI @ auth.<domain> │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ presigned │ S3 documents bucket (KMS, versioned) ◀──── Lambda (documents API)│ │
│ PUT/GET │ DynamoDB metadata (PITR, GSIs) ◀────────────┘ │
└───────────────┼──────────────────────────────────────────────────────────────────────┘
└──────────────────────────────────────────────────────────────────────────────────────┘
GitHub ──push main, dev*──▶ CodePipeline (CI/CD account) ──▶ dev account (auto)
└── approval ──▶ stage account
└── approval ──▶ prod account

Data flow

  1. The app fetches /config.json from its own origin (injected per environment at deploy time) — no build-time or hardcoded endpoints.
  2. Sign-in uses Cognito hosted UI with PKCE (public client, no secret). The ID token is presented to the API (Authorization: Bearer …).
  3. Document metadata lives in DynamoDB (id PK; owner-created and published-token GSIs). The body lives in S3 under private/{ownerId}/{id}/{revision}.frond.
  4. Uploads/downloads use short-lived presigned S3 URLs (10 min), so document bytes never transit the Lambda; committing a revision verifies the object (HEAD) and bumps metadata.
  5. Publishing copies the current revision to published/{token}/latest.frond — public viewers never see owner identifiers — and GET /published/{token} serves the read-only view.

Why this stays fast

  • The canvas is a quadtree of raster-cached vector cells (see the engine); visible content is O(screen), not O(document).
  • Static sites are on CloudFront edge caches; the API is a single Lambda with millisecond cold starts; DynamoDB on-demand absorbs spikes.
  • The app bundle is ~70 kB gzipped; everything after first load is local.

Security architecture

  • Least privilege IAM per component; presigned-URL access to S3.
  • KMS customer-managed keys for documents, DynamoDB, and logs (with rotation); TLS-only bucket policies; S3 Block Public Access everywhere.
  • WAF (managed rule sets + IP rate limits) on CloudFront and API Gateway.
  • Cognito: strong password policy, optional MFA (TOTP), adaptive auth, token revocation, preventUserExistenceErrors.
  • GuardDuty, Config managed rules, Security Hub, CloudTrail per account.
  • Security headers (CSP, HSTS, frame-ancestors 'none') on all web origins.
  • See Security and the compliance guides for the full control set.