Implements the cloud-console OpenSpec change: adds GET /v1/tasks (filterable,
bounded pagination, tasks:read) and GET /v1/tasks/{id}/attempts (404 on unknown
task) to the platform SDK, with matching CloudClient methods and a closed-by-
default CLOUD_CONSOLE_CORS_ORIGINS allow-list wired through CloudControlConfig.
Ships an independent Vue 3 + Vite SPA at cloud-console/ that authenticates with
an operator-supplied bearer token held in sessionStorage, renders tasks with
attempt history, device pool, host registry, and the plugin registry with a
registration form.
Backend test suite: 438 passed (-m "not integration"); cloud-console typecheck
and production build both succeed. PostgreSQL-backed repository tests and
manual end-to-end verification remain pending external infrastructure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
96 lines
3.5 KiB
Markdown
96 lines
3.5 KiB
Markdown
# Cloud Console
|
|
|
|
Independent Vue 3 + Vite single-page app for the Cloud Control Plane
|
|
(`apps/cloud-api`). Operators authenticate by pasting a pre-issued scoped
|
|
bearer token; the console stores it in `sessionStorage`, attaches
|
|
`Authorization: Bearer <token>` to every request, and clears it whenever the
|
|
Cloud API responds `401` or `403`.
|
|
|
|
The app talks only to the platform SDK surface (`/v1/...`) and consumes the
|
|
two listing endpoints added by the `cloud-console` change (`GET /v1/tasks`,
|
|
`GET /v1/tasks/{task_id}/attempts`) alongside the existing
|
|
`/v1/devices`, `/v1/hosts`, `/v1/plugins`, and `POST /v1/plugins` routes.
|
|
|
|
## Prerequisites
|
|
|
|
- Node.js 20+ (matching the existing `console/` SPA project)
|
|
- A running Cloud API (`apps/cloud-api`) reachable from your browser
|
|
- A bearer token issued via `CLOUD_PUBLIC_CREDENTIALS_JSON` whose scopes cover
|
|
what you intend to do from the console. Recommended least-privilege set:
|
|
- `tasks:read` — task list and attempt history views
|
|
- `pool:read` — device and host views
|
|
- `plugins:read` — plugin list
|
|
- Add `tasks:submit`/`plugins:admin` only if you need the write actions from
|
|
the same tab.
|
|
|
|
## Configure the backend CORS allow-list
|
|
|
|
The Cloud API has no CORS middleware by default. Before a browser can call it
|
|
cross-origin, set `CLOUD_CONSOLE_CORS_ORIGINS` to a comma-separated allow-list
|
|
that includes the exact origin your dev server prints (scheme + host + port —
|
|
no trailing slash):
|
|
|
|
```bash
|
|
# Example: allow the default Vite dev origin
|
|
export CLOUD_CONSOLE_CORS_ORIGINS="http://127.0.0.1:5173"
|
|
```
|
|
|
|
Restart `apps/cloud-api` after changing this env. Tokens are still required —
|
|
the allow-list only says which browser origins may send them.
|
|
|
|
## Run the dev server
|
|
|
|
```bash
|
|
cd cloud-console
|
|
cp .env.example .env.local
|
|
# Edit .env.local if your Cloud API is not at http://127.0.0.1:8001
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
Vite prints a local URL (default `http://127.0.0.1:5173`). Open it, paste a
|
|
bearer token, and the task/device/host/plugin dashboards become available.
|
|
|
|
`.env.local` overrides the default base URL via `VITE_CLOUD_API_BASE_URL`
|
|
(defaults to `http://127.0.0.1:8001`).
|
|
|
|
## Build for production
|
|
|
|
```bash
|
|
npm run build # type-checks with vue-tsc, then emits dist/
|
|
npm run preview # serves the built bundle locally
|
|
```
|
|
|
|
`dist/` is a static bundle — host it behind any static file server or CDN and
|
|
point it at a deployed Cloud API via `VITE_CLOUD_API_BASE_URL` set at build
|
|
time.
|
|
|
|
## Token handling
|
|
|
|
- The token is held in `sessionStorage` only. Closing the tab discards it.
|
|
- Every API request attaches `Authorization: Bearer <token>` and targets only
|
|
the configured `VITE_CLOUD_API_BASE_URL`.
|
|
- A `401`/`403` response clears the stored token and returns the operator to
|
|
the token-entry screen with the API's error detail.
|
|
|
|
## Project layout
|
|
|
|
```
|
|
cloud-console/
|
|
├── src/
|
|
│ ├── api.ts # API client wrapper (token storage, fetch, errors)
|
|
│ ├── types.ts # TS interfaces mirroring the REST models
|
|
│ ├── App.vue # Shell: token gate, nav, view router
|
|
│ ├── main.ts # Vue bootstrap
|
|
│ ├── style.css # Dark theme styles
|
|
│ └── views/
|
|
│ ├── TokenScreen.vue
|
|
│ ├── TasksView.vue # list + detail with attempt history
|
|
│ ├── DevicesView.vue # device pool + host registry
|
|
│ └── PluginsView.vue # registry list + registration form
|
|
├── index.html
|
|
├── package.json
|
|
├── tsconfig.json / tsconfig.node.json
|
|
└── vite.config.ts
|
|
```
|