Skip to content

feat: add static sites hosting gateway#208

Open
vigneshrajsb wants to merge 5 commits into
mainfrom
vb/lifecycle-static-sites-hosting
Open

feat: add static sites hosting gateway#208
vigneshrajsb wants to merge 5 commits into
mainfrom
vb/lifecycle-static-sites-hosting

Conversation

@vigneshrajsb
Copy link
Copy Markdown
Contributor

@vigneshrajsb vigneshrajsb commented May 13, 2026

Summary

Adds a v2 static sites hosting flow to Lifecycle:

  • Adds /api/v2/sites APIs for create, list, read, replace content, extend TTL, and soft delete.
  • Adds Site and SiteVersion models plus a migration-seeded sites global config, disabled by default.
  • Adds upload validation for HTML, ZIP, and common safe static asset/document extensions with 10 MiB limits.
  • Adds S3/MinIO-backed object storage and rollback cleanup for uploaded prefixes if DB activation fails.
  • Adds a gateway mode in ws-server.ts that serves GET/HEAD site traffic from object storage by configured host parsing.
  • Adds local/default Helm environment wiring for the gateway component and local Tilt port-forward support.

Notes

The temporary planning doc and local test UI are intentionally not included in this PR.

Configuration

This PR seeds a sites row in global_config and defaults it to disabled. Runtime site-hosting behavior is controlled there, so most values below can be changed without redeploying Lifecycle. The gateway component, wildcard ingress host, DNS/cert wiring, and object-store/IAM setup are still deploy-time infrastructure concerns.

Example global_config.config shape for key sites:

{
  "enabled": false,
  "domain": "sites.lifecycle.example.com",
  "port": null,
  "hostPrefix": "site",
  "ttl": {
    "enabled": true,
    "defaultDays": 7,
    "extensionDays": 7
  },
  "upload": {
    "maxUploadBytes": 10485760,
    "maxExtractedBytes": 10485760,
    "maxFiles": 500,
    "allowedExtensions": [
      "html",
      "zip",
      "json",
      "md",
      "markdown",
      "txt",
      "css",
      "js",
      "mjs",
      "map",
      "csv",
      "xml",
      "svg",
      "png",
      "jpg",
      "jpeg",
      "gif",
      "webp",
      "avif",
      "ico",
      "webmanifest",
      "wasm",
      "woff",
      "woff2",
      "ttf",
      "otf",
      "pdf"
    ]
  },
  "storage": {
    "backend": "minio",
    "bucket": "lifecycle-sites",
    "prefix": "sites",
    "region": "us-west-2",
    "endpoint": null,
    "forcePathStyle": true
  },
  "cleanup": {
    "enabled": true,
    "intervalMinutes": 15
  }
}

Option notes:

  • enabled: gates the v2 sites APIs and gateway host matching.
  • domain, port, hostPrefix: generate and parse URLs as https://{hostPrefix}-{siteId}.{domain}; local dev can use localhost plus a forwarded port.
  • ttl.enabled: when disabled, new sites do not get an expiration and the cleanup job does not expire hosted sites.
  • upload: caps uploads and extracted ZIP content at 10 MiB by default; ZIP uploads must contain an index.html at root or one top-level folder.
  • storage: supports minio and s3. MinIO can create the bucket on demand; S3 expects the bucket and credentials/IAM to already be provisioned.
  • cleanup: schedules expired-site cleanup when enabled, ttl.enabled, and cleanup.enabled are all true. Cleanup soft-deletes DB rows and removes object-store prefixes.

Deploy-time gateway options live in Helm values rather than global_config:

  • components.gateway.enabled: deploys the separate gateway process.
  • components.gateway.deployment.replicaCount, resources, nodeSelector, tolerations, and extraEnv: size and schedule the gateway like the other Lifecycle components.
  • components.gateway.service: controls the ClusterIP/service port.
  • components.gateway.ingress: controls ingress class, annotations, paths, and the wildcard host, for example *.sites.lifecycle.example.com.
  • Gateway pods must run with LIFECYCLE_MODE=gateway and need the same DB/object-store/global-config access as web/worker.

Validation

Passed:

  • Local smoke test through Tilt/port-forward:
    • GET /api/health on web and gateway returned 200.
    • Uploaded a single HTML file through POST /api/v2/sites.
    • Served the generated site root through the gateway with 200.
    • Verified /missing-route returns 404.
    • Deleted the smoke-test site and verified the gateway returns 404.
  • pnpm run lint
  • pnpm test -- src/server/lib/sites
  • Targeted ESLint over sites files and ws-server.ts
  • git diff --check
  • Filtered typecheck output for touched sites/gateway paths had no matches.

Known repo/environment failures not introduced by this PR:

  • pnpm run ts-check fails on existing repo-wide TypeScript errors outside the sites/gateway paths.
  • pnpm test fails many suites before execution because this shell does not provide DATABASE_URL / DB env; the new sites tests pass.

vigneshrajsb and others added 2 commits May 13, 2026 11:13
- Capped ZIP decompression by actual inflated bytes to prevent upload
OOM bypasses.
- Made object cleanup retryable by only marking rows deleted after
storage deletion succeeds.
- Closed gateway object streams on HEAD requests.
- Added OpenAPI coverage for /api/v2/sites* and regenerated UI API
types.
- Verified create, fetch, HEAD, replace, extend, and delete end to end
in Tilt.
@vigneshrajsb vigneshrajsb marked this pull request as ready for review May 14, 2026 17:09
@vigneshrajsb vigneshrajsb requested a review from a team as a code owner May 14, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants