# Xyvenra Cloud preview links by Ouroboros

Cloud can create a shareable, private preview snapshot from the current editor. The snapshot is not published as a live site and does not change when the editor changes later.

## Link behavior

- A link is a 256-bit random bearer token, shown only when created. The database stores its SHA-256 digest, not the token.
- Each link expires seven days after creation. Owners can revoke it sooner. Revocation takes effect immediately.
- Each account can have at most five active links. Expired rows are removed on the next preview creation.
- Each snapshot is limited to 180 KB. The standard Cloud site size limit still applies.
- Anyone with the complete link can view the snapshot until it expires or the owner revokes it. Treat the link like a secret.
- Links use a no-cache response, a no-referrer policy, and `noindex` headers. Page contents run in a sandboxed iframe with an opaque origin.
- Cloud adds a restrictive Content Security Policy to previews and public sites. Scripts and styles can run inline; network fetches, forms, embedded frames, external images, scripts, and fonts are blocked. Use embedded `data:` or `blob:` assets. Third-party APIs and widgets will not work.
- Clicking an external link may still navigate inside the isolated frame and contact that destination. Review links and do not share pages containing sensitive content.

The editor preview endpoint requires the signed-in site owner and same-origin request protections; listing and revocation are also owner-scoped. A site-scoped Cloud deployment key can create a preview from CI through the separate `?preview=1` upload path, under the same five-link account limit. The public preview page accepts only the random token and never exposes the preview table through the Data API.

## API

```text
GET    /api/cloud/sites/{site_id}/previews
POST   /api/cloud/sites/{site_id}/previews
GET    /api/cloud/sites/{site_id}/previews/{preview_id}  (owner review)
POST   /api/cloud/sites/{site_id}/previews/{preview_id}  (owner apply)
DELETE /api/cloud/sites/{site_id}/previews/{preview_id}
GET    /preview/{one_time_token}
POST   /api/cloud/v1/{site_id}?preview=1  (site key; HTML JSON or static-site ZIP)
```

The editor's `POST /api/cloud/sites/{site_id}/previews` takes `{ "site_name": "My app", "html": "<!doctype html>..." }` and returns the preview ID, expiration time, and one-time path. It accepts a current editor snapshot; it does not publish the site. Keep the returned path private and copy it before leaving the Cloud editor, because it cannot be recovered later.

## Review and apply a preview

The site owner can choose **Review** beside any active preview link in Cloud, including a preview uploaded from CI. Cloud fetches that snapshot only for the signed-in owner and shows it in the same network-restricted sandbox used by the editor. This owner review still works if the one-time share URL was lost; it does not reveal or regenerate the bearer URL.

After reviewing, choose **Apply to site** and confirm. Cloud replaces the site's saved name and HTML with that snapshot, keeps the current published/private setting, and captures the replaced saved state in the existing five-version history. A published site's new content goes live immediately; a private site stays private. Unsaved editor changes are discarded after successful apply. If another save changed the site since the owner loaded it, Cloud returns a conflict and the owner must reload before trying again. Expired or revoked previews cannot be reviewed or applied. Applying a preview does not revoke its share link; use **Revoke** separately when review is finished.

The owner-only endpoints are `GET /api/cloud/sites/{site_id}/previews/{preview_id}` for review and `POST` to that path for application. The `POST` body contains the site's last `updated_at` value as `expected_updated_at`, and requires a signed-in owner and same-origin request. CI deployment keys can create preview links but cannot review or apply them through these endpoints.

The CI preview upload uses the same HTML or ZIP format and limits as a normal Cloud CI deployment. It returns a temporary URL without changing the live site; see [the CI deployment guide](xyvenra-cloud-ci-deploy.md). Anyone with the returned URL can view it until expiry or revocation, including people who can read the CI log where the helper prints it.

## Operating limits

Preview rows are stored in the existing platform Postgres project. The cap is five active links per account, each no larger than 180 KB and retained for at most seven days. No new paid service or build worker is provisioned. The links use the same storage and database service as the rest of Xyvenra; measure actual database growth and service costs before raising these limits or selling the feature.
