diff --git a/DEPLOY.md b/DEPLOY.md index 302da456..ee3c29b0 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -15,7 +15,9 @@ against `api.github.com` with no server-side component. **Host the `dist/` build output on any static platform:** GitHub Pages, Netlify, Vercel, S3 + CloudFront, or any CDN that serves SPAs with `index.html` fallback for client-side -routing. +routing. Note: `public/.nojekyll` is copied into `dist/client/.nojekyll` during `pnpm run build` +— keep this file when deploying to GitHub Pages so Jekyll does not strip the `_app/` directory +containing hashed JS and CSS bundles. **What works without a backend:** - All dashboard features (Issues, PRs, Actions tabs) @@ -214,6 +216,20 @@ The OAuth App access token is a permanent credential (no expiry). It is stored i The two tunnel endpoints (`/api/error-reporting` and `/api/csp-report`) receive untrusted browser data and forward it to Sentry. They are hardened with layered fail-fast guards (IP rate limit → Origin check → DSN validation). See `hack/docs/security-runbook.md` for the full threat model, per-endpoint rate limit values, Origin check behavior, CSP field sanitization details, Content-Length pre-check semantics, and fan-out amplification analysis. +### Static asset caching + +- **Hashed bundles (`/_app/*`):** Vite outputs content-hashed JS and CSS bundles to `dist/client/_app/`. `public/_headers` configures `Cache-Control: public, max-age=31536000, immutable` (one year) on `/_app/*` while inheriting the global security headers from `/*`. +- **Entry HTML and unhashed public assets (`index.html`, `/assets/*`):** `index.html` and unhashed images under `public/assets/*` (favicon, logos, social preview) have no custom `Cache-Control` rule in `public/_headers` and use the Cloudflare Workers Static Assets platform default (`Cache-Control: public, max-age=0, must-revalidate`), ensuring browsers revalidate `index.html` on every load. +- **One-time cache miss on initial `/_app/` rollout:** Moving hashed bundles from `/assets/` to `/_app/` causes a one-time cache miss on the deployment that introduces `/_app/`. +- **Stale-chunk 404 handling (`stale_asset_404`):** Under SPA `not_found_handling`, missing non-navigation requests (such as `