diff --git a/.agent/context/20260908T000000Z-recovery-route-composition.md b/.agent/context/20260908T000000Z-recovery-route-composition.md new file mode 100644 index 0000000..bdd21c2 --- /dev/null +++ b/.agent/context/20260908T000000Z-recovery-route-composition.md @@ -0,0 +1,88 @@ +# Session Context: recovery-route-composition + +## Date/time + +- UTC: 2026-09-08T18:25:19Z + +## User goal + +Serve the existing `apps/web` frontend at the domain root and the recovery UI +at `/recovery` from the same Cloudflare assets deployment. + +## Original prompt/request + +The current Cloudflare deployment includes `./apps/web/dist`, while UI exists +in `packages/recovery-ui`. Combine them so `oneshot.kapustazh.dev` keeps the +current pages and `oneshot.kapustazh.dev/recovery` serves the recovery UI; do +this on a new branch. + +## Assumptions + +- The recovery site is the existing synthetic fixture viewer, not a new live + API integration. +- The current Wrangler assets directory remains `apps/web/dist`. +- The branch should start from the clean current `develop` branch. + +## Plan + +1. Build the main app and recovery site into one static asset tree. +2. Verify asset paths, production builds, and Wrangler configuration. + +## Key decisions + +- Emit recovery files to `apps/web/dist/recovery` and use Vite base + `/recovery/`, preserving the root app bundle and making nested assets resolve + under the route. +- Keep Cloudflare's existing SPA fallback because both apps are static entry + points and the recovery viewer does not require server-side routes. + +## Files/components touched + +- `package.json`: added the combined frontend build script. +- `wrangler.jsonc`: changed the Cloudflare build command to the combined build. +- `packages/recovery-ui/vite.site.config.ts`: configured the `/recovery/` base + and shared output directory. +- `apps/web/README.md`: documented the deployed route and build command. +- `packages/recovery-ui/README.md`: updated the package deployment instructions + for the combined asset tree and `/recovery/` route. + +## Commands/checks + +- Branch creation: `feature/recovery-route-composition`. +- `pnpm build:frontend` - passed; root output and `/recovery/` output were + emitted into one asset tree. +- `pnpm --filter @oneshot/web test` - passed, 27 tests. +- `pnpm --filter @oneshot/recovery-ui test` - passed, 51 tests. +- Both package typechecks and linters - passed. +- `pnpm exec wrangler deploy --dry-run` - passed; Wrangler read 9 asset files + from `apps/web/dist` and exited without uploading. +- Prettier check on changed config files - passed. +- Documentation correction: `packages/recovery-ui/README.md` now documents + `pnpm build:frontend`, `apps/web/dist/recovery`, and `/recovery/`. + +## External-doc findings + +- None required; this change uses the repository's existing Vite and Wrangler + configuration. + +## Unresolved questions + +- None. + +## Git and PR state + +- Branch: `feature/recovery-route-composition` +- Base: `develop` (working tree was clean at branch creation) +- Commit: uncommitted +- PR: not created +- CI: not run + +## Review gates + +- Gate A: FAIL on prior tree due stale recovery deployment docs; fresh review + pending for the corrected tree. +- Gate B: NOT RUN + +## Handoff/next steps + +1. Review the branch and deploy it through the normal Cloudflare workflow. diff --git a/apps/web/README.md b/apps/web/README.md index 1024e3f..68a3ceb 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -2,9 +2,10 @@ Minimal operator UI for creating or replaying a Business Intent and reading its authoritative status. -This package is not the production Worker asset target yet. Deploy it only after -`VITE_ONESHOT_API_BASE_URL` points to a reachable OneShot API. An assets-only -Worker cannot serve `/health` or `/v1`. +The Cloudflare asset deployment serves this app at the domain root and the +recovery fixture viewer from `@oneshot/recovery-ui` at `/recovery/`. Deploy it +only after `VITE_ONESHOT_API_BASE_URL` points to a reachable OneShot API. An +assets-only Worker cannot serve `/health` or `/v1`. ```powershell pnpm --filter @oneshot/web dev @@ -12,4 +13,13 @@ pnpm --filter @oneshot/web dev Vite proxies `/v1` and `/health` to the local API. For a separate deployed API, set the public build variable `VITE_ONESHOT_API_BASE_URL`. Enter the demo service token at runtime; the UI keeps it in memory and never persists it. +The combined production asset tree is built with: + +```powershell +pnpm build:frontend +``` + +This emits the main app to `apps/web/dist` and the recovery viewer to +`apps/web/dist/recovery`, matching the Wrangler asset directory. + The client consumes generated `@oneshot/contracts` types from frozen OpenAPI v1. Tests use deterministic fetch responses matching that contract. diff --git a/package.json b/package.json index e48f794..10e7bc7 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "db:reset-demo": "pnpm --filter @oneshot/storage-postgres build && node scripts/reset-demo-db.mjs", "deploy": "wrangler deploy", "dev:frontend": "wrangler dev", + "build:frontend": "pnpm --filter @oneshot/web build && pnpm --filter @oneshot/recovery-ui build:site", "dev:web": "pnpm --filter @oneshot/web dev", "format": "prettier --write \"**/*.{ts,mts,mjs,json,jsonc,yml,yaml}\"", "format:check": "prettier --check \"**/*.{ts,mts,mjs,json,jsonc,yml,yaml}\"", diff --git a/packages/recovery-ui/README.md b/packages/recovery-ui/README.md index 73f00cc..ce1af7b 100644 --- a/packages/recovery-ui/README.md +++ b/packages/recovery-ui/README.md @@ -24,10 +24,11 @@ pnpm --filter @oneshot/recovery-ui dev Open `/?scenario=aged-unknown`. Any scenario exported by `RECOVERY_SCENARIOS` may be selected. -The same fixture viewer is the Wrangler static-asset target. From the repository -root, `pnpm deploy` builds `site-dist` and deploys it to the configured custom -domain. Its persistent banner identifies all data as synthetic review fixtures; -it is not live sponsor evidence. +The same fixture viewer is included in the combined Wrangler static-asset +target. From the repository root, `pnpm build:frontend` builds the main app and +emits this viewer to `apps/web/dist/recovery`, where it is served at +`/recovery/` on the configured custom domain. Its persistent banner identifies +all data as synthetic review fixtures; it is not live sponsor evidence. ## Frozen mock boundary diff --git a/packages/recovery-ui/vite.site.config.ts b/packages/recovery-ui/vite.site.config.ts index b393ce3..fcf3198 100644 --- a/packages/recovery-ui/vite.site.config.ts +++ b/packages/recovery-ui/vite.site.config.ts @@ -3,8 +3,9 @@ import { defineConfig } from 'vite'; export default defineConfig({ plugins: [react()], + base: '/recovery/', build: { - outDir: 'site-dist', + outDir: '../../apps/web/dist/recovery', emptyOutDir: true, }, }); diff --git a/wrangler.jsonc b/wrangler.jsonc index 2850434..3f79f6c 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -3,7 +3,7 @@ "name": "oneshot", "compatibility_date": "2026-09-07", "build": { - "command": "pnpm --filter @oneshot/web build", + "command": "pnpm build:frontend", }, "assets": { "directory": "./apps/web/dist",