373 lines
16 KiB
Markdown
373 lines
16 KiB
Markdown
# SciMesh: plan for the initial web interface
|
|
|
|
## 1. Purpose and outcome
|
|
|
|
Build a small, local-first web interface for manually checking the complete
|
|
SciMesh pipeline. A person should be able to open one address, upload a small
|
|
ChEMBL-style TSV, configure a supported run, observe workers and task progress,
|
|
inspect failures, and download artifacts without composing raw HTTP requests.
|
|
|
|
This is not a public multi-tenant product. It is an operator and demo interface
|
|
for a trusted local team. The coordinator remains the only process with direct
|
|
database and artifact-storage access; the browser never calls PostgreSQL and
|
|
never receives a worker bearer token.
|
|
|
|
The first release must be useful before CTX-07--CTX-10 are complete. Therefore
|
|
it has two visibly different modes:
|
|
|
|
| Mode | What it proves | What it must not claim |
|
|
| --- | --- | --- |
|
|
| **Pipeline check** | Upload, task creation, claim, heartbeat, artifact upload, task completion, retries, and downloads work end-to-end. | That multiple shard results have been scientifically reduced into one answer. |
|
|
| **Final run** | A reducer has produced a durable final CSV for the full job. | Available only after CTX-09, and for graph only after CTX-10. |
|
|
|
|
Never label a partial artifact as a final molecular result. The UI must show a
|
|
clear `Pipeline check — partial results` badge while a reducer is unavailable.
|
|
|
|
## 2. Constraints and decisions
|
|
|
|
- Serve the UI from the Go coordinator at the same origin. No React, Vue, Node
|
|
build, CDN, or separate frontend service.
|
|
- Use Go `html/template`, `embed`, ordinary CSS, and small vanilla JavaScript
|
|
modules. The page works locally with `docker compose up`.
|
|
- Keep worker APIs and UI APIs separate. The UI handlers call Go use cases;
|
|
they do not make HTTP calls to worker endpoints.
|
|
- Add a distinct `UI_AUTH_TOKEN` for browser/operator access. It must never
|
|
reuse `WORKER_AUTH_TOKEN`, appear in page HTML, localStorage, logs, URLs, or
|
|
error messages. For the initial local UI use HTTP Basic Auth over a trusted
|
|
local/reverse-proxied connection. If `UI_AUTH_TOKEN` is unset, `/ui` and
|
|
`/ui/api/*` return `404` and the coordinator stays API-only.
|
|
- Keep all user-controllable text escaped by `html/template`; JavaScript renders
|
|
API fields through `textContent`, never `innerHTML`.
|
|
- All downloads go through coordinator-owned UI endpoints with authorization.
|
|
Do not expose filesystem paths, `storage_key`, database errors, worker tokens,
|
|
or raw worker tracebacks.
|
|
- The API vocabulary should be canonicalised before UI forms are implemented.
|
|
Choose one external workload spelling (`similarity-search` and
|
|
`similarity-graph` recommended, matching the CLI) and keep legacy underscore
|
|
aliases only at the worker boundary. Update `docs/api-contract.md` and
|
|
`docs/openapi.yaml` in the same change.
|
|
|
|
## 3. Target user journey
|
|
|
|
1. Start coordinator/PostgreSQL and one or more `scimesh-worker` processes.
|
|
2. Open `http://localhost:8080/ui`, authenticate with the UI token, and see
|
|
readiness plus the registered-worker table.
|
|
3. Choose **New run**, select a workload, fill validated parameters, choose a
|
|
TSV, and submit it.
|
|
4. The UI redirects to `/ui/jobs/{job_id}` and polls every two seconds.
|
|
5. The operator sees counters, per-task attempt/lease/error state, and worker
|
|
activity. They may copy the worker launch command but cannot start arbitrary
|
|
processes from the browser.
|
|
6. During a pipeline check, download an input shard or partial CSV to validate
|
|
manually. For a final run, download the final CSV only when the job status is
|
|
`completed` and a final artifact exists.
|
|
7. A failed run exposes only its sanitized failure reason and retry state. The
|
|
browser offers a safe retry action only after an explicit future API supports
|
|
it; v1 never fabricates a retry by changing task rows directly.
|
|
|
|
## 4. What exists today and required gaps
|
|
|
|
| Capability | Current state | UI plan |
|
|
| --- | --- | --- |
|
|
| Upload/chunk dataset | `POST /jobs/upload` exists | Reuse through a UI handler with server-side multipart validation. |
|
|
| Aggregate status | `GET /jobs/{id}` exists | Add list/detail read models for the UI. |
|
|
| Worker registration/lease flow | Implemented | Add a read-only worker list; no browser worker controls. |
|
|
| Task diagnostics | No public list/detail response | Add sanitized job task list with attempt, status, lease owner, expiry and error. |
|
|
| Artifact download | Worker endpoint exists | Add UI-authorized, job-scoped download proxy. |
|
|
| Final result | Reducer is not implemented | Gate behind CTX-09; show partial diagnostic artifacts meanwhile. |
|
|
| Distributed graph correctness | Planner/reducer unavailable | Do not advertise a multi-shard graph as final until CTX-10. |
|
|
|
|
## 5. Proposed structure
|
|
|
|
```text
|
|
coordinator/
|
|
web/
|
|
templates/
|
|
layout.html
|
|
dashboard.html
|
|
job_new.html
|
|
job_detail.html
|
|
error.html
|
|
static/
|
|
app.css
|
|
dashboard.js
|
|
job-detail.js
|
|
internal/
|
|
transport/http/
|
|
ui_handlers.go
|
|
ui_dto.go
|
|
ui_auth.go
|
|
ui_handlers_test.go
|
|
usecase/
|
|
ui.go # read-only DTO orchestration, no HTML
|
|
domain/
|
|
ui.go # only if a shared value object is genuinely needed
|
|
storage/postgres/
|
|
ui_read_repo.go # parameterized listing/detail queries
|
|
```
|
|
|
|
Embed `web/templates` and `web/static` into the coordinator binary with
|
|
`go:embed`. No assets are generated at runtime; `go test ./...` must work
|
|
without Node/npm.
|
|
|
|
## 6. UI surface and routes
|
|
|
|
### HTML routes
|
|
|
|
| Route | Purpose | Availability |
|
|
| --- | --- | --- |
|
|
| `GET /ui` | Dashboard: readiness, recent jobs, workers, quick actions. | WUI-03 |
|
|
| `GET /ui/jobs/new` | New-run form and parameter help. | WUI-04 |
|
|
| `GET /ui/jobs/{id}` | Job detail and polling shell. | WUI-03 |
|
|
| `GET /ui/jobs/{id}/artifacts/{artifact_id}` | Authorized download proxy with attachment headers. | WUI-05 |
|
|
|
|
### JSON routes used only by the pages
|
|
|
|
| Route | Response / action | Notes |
|
|
| --- | --- | --- |
|
|
| `GET /ui/api/overview` | readiness, recent jobs, workers | No secrets, no storage paths. |
|
|
| `GET /ui/api/jobs` | cursor/page of compact job cards | Default 20, deterministic `created_at DESC, id DESC`. |
|
|
| `POST /ui/api/jobs/upload` | validates form, streams dataset, returns `201 {job_id}` | Same input limits as `/jobs/upload`; form fields first, file last. |
|
|
| `GET /ui/api/jobs/{id}` | job detail, counters, tasks, allowed artifacts | Polling endpoint, no raw DB model. |
|
|
| `GET /ui/api/jobs/{id}/events` | **deferred** | Start with polling; no SSE/WebSocket in v1. |
|
|
|
|
All `/ui` routes use UI authentication. Existing worker API routes keep worker
|
|
authentication and are not relaxed for the browser.
|
|
|
|
## 7. Read models and data minimisation
|
|
|
|
Create UI-specific DTOs; do not return domain/database entities directly.
|
|
|
|
```text
|
|
JobCard:
|
|
id, workload, created_at, status,
|
|
total, pending, leased, running, completed, failed
|
|
|
|
JobDetail:
|
|
JobCard fields,
|
|
parameters (allowlisted/redacted),
|
|
tasks: [{id, chunk_index, status, attempt, max_attempts,
|
|
lease_owner_display, lease_expires_at, error_code, error_message}],
|
|
artifacts: [{id, kind, filename, size_bytes, sha256, downloadable}]
|
|
|
|
WorkerCard:
|
|
id, name, capabilities, status, last_heartbeat_at, created_at
|
|
```
|
|
|
|
Rules:
|
|
|
|
- Display a shortened UUID by default but provide a copy button with the full
|
|
value; never interpolate it into HTML.
|
|
- Do not expose `storage_key`, absolute artifact paths, raw metrics containing
|
|
unexpected values, auth configuration, or worker-local directories.
|
|
- An artifact is downloadable only when it belongs to the requested job. A
|
|
`final_result` is downloadable only after the job is `completed`; partial
|
|
artifacts are marked diagnostic.
|
|
- SQL uses explicit columns, pagination/cursors, deterministic ordering, and
|
|
joins constrained by `job_id`.
|
|
|
|
## 8. Workload forms and validation
|
|
|
|
### 8.1 Common fields
|
|
|
|
- TSV file, required, streamed; show expected columns
|
|
`chembl_id` and `canonical_smiles`.
|
|
- `chunk_rows`: integer 1--100000, default 1000.
|
|
- `max_rows`: optional positive integer. The coordinator creates shards only
|
|
from the first N data rows, so a user can test a large upload without
|
|
creating thousands of tasks. It does not truncate the stored source blob.
|
|
- optional human-readable run name is a later schema/API addition; v1 does not
|
|
silently store it.
|
|
- display file name and client-side size only as convenience; server limits and
|
|
validation remain authoritative.
|
|
|
|
### 8.2 Similarity search
|
|
|
|
Inputs: exactly one `query_smiles` or `query_id`, `top_k`, optional threshold,
|
|
threshold direction, `max_rows`, and `progress_every`.
|
|
|
|
For a runnable manual pipeline check before CTX-08, offer `query_smiles` and
|
|
default `chunk_rows` large enough to create one shard. A `query_id` across
|
|
multiple shards is disabled with an explanation until CTX-07 resolves it once
|
|
before fan-out. The detail page calls an artifact a **partial top-k CSV**, not
|
|
a global top-k, until CTX-09 reduction exists.
|
|
|
|
### 8.3 Similarity graph
|
|
|
|
Inputs: threshold, threshold direction, block size, `max_rows`, and progress
|
|
interval. The form may show a disabled **Experimental — not globally reduced**
|
|
card, but it must not submit multi-shard graph jobs until CTX-10 implements
|
|
block-pair planning and deterministic reduction. A one-shard pipeline check is
|
|
allowed only behind an explicit acknowledgement and produces a diagnostic edge
|
|
list, not a final graph.
|
|
|
|
Validation exists in three places: HTML constraints for feedback, a small
|
|
JavaScript schema for form behaviour, and authoritative Go validation mapped to
|
|
typed workload parameters. Never pass arbitrary parameter maps straight from
|
|
the browser to workers.
|
|
|
|
## 9. Delivery packages
|
|
|
|
Each package is a separate PR/task context. Do not start a later package until
|
|
its listed dependency and tests are green.
|
|
|
|
### WUI-00 — Freeze UI contract and demo scope
|
|
|
|
**Depends on:** current `main`.
|
|
|
|
**Deliver:** this plan, canonical workload naming decision, and updates to
|
|
`docs/api-contract.md`/`docs/openapi.yaml` if names or statuses change.
|
|
|
|
**Acceptance:** API has a precise distinction between diagnostic artifacts and
|
|
final results; UI security model has a distinct token; CTX-07/09/10 limitations
|
|
are visible.
|
|
|
|
### WUI-01 — UI read models and PostgreSQL queries
|
|
|
|
**Depends on:** WUI-00.
|
|
|
|
**Deliver:** repository/use-case methods for deterministic job lists, sanitized
|
|
job details, task summaries, artifact metadata, and worker lists. Add indexes
|
|
only if `EXPLAIN ANALYZE` on a realistic list query shows need.
|
|
|
|
**Acceptance:** no N+1 query path; no storage key/secret leaks; unknown job is
|
|
404; artifact lookup is constrained to its job; Go unit plus real-PostgreSQL
|
|
integration tests cover ordering, empty lists and ownership boundaries.
|
|
|
|
### WUI-02 — UI auth and embedded asset foundation
|
|
|
|
**Depends on:** WUI-01.
|
|
|
|
**Deliver:** `UI_AUTH_TOKEN` config validation, Basic Auth middleware, embedded
|
|
template/static serving, security headers, and an API-only fallback when UI is
|
|
disabled.
|
|
|
|
**Acceptance:** worker token never authorizes `/ui`; UI token never authorizes
|
|
worker routes; `/ui` is 404 when disabled; HTML/content-security headers are
|
|
tested; no token appears in logs or errors.
|
|
|
|
### WUI-03 — Read-only dashboard and job detail
|
|
|
|
**Depends on:** WUI-01, WUI-02.
|
|
|
|
**Deliver:** dashboard, worker table, job list, detail page, two-second polling
|
|
with pause when the tab is hidden, error/retry display, and accessible empty/
|
|
loading/error states.
|
|
|
|
**Acceptance:** a manually created job changes from pending to running on the
|
|
page without reload; all text is escaped; polling stops on terminal states;
|
|
task attempts and sanitized errors are visible; handler/template tests cover
|
|
XSS-shaped names and errors.
|
|
|
|
### WUI-04 — New-run upload form
|
|
|
|
**Depends on:** WUI-02, WUI-03.
|
|
|
|
**Deliver:** workload-specific form, typed Go validation, streamed upload,
|
|
progress/submit state, redirect to job detail, and copyable worker launch
|
|
instructions.
|
|
|
|
**Acceptance:** invalid query combinations fail with 400 and clear UI feedback;
|
|
valid small similarity-search upload creates deterministic shard count; upload
|
|
limits are enforced; browser never sees worker auth; test covers malformed TSV,
|
|
large/invalid fields, duplicate form fields, and failed coordinator storage.
|
|
|
|
### WUI-05 — Safe artifact downloads and diagnostic preview
|
|
|
|
**Depends on:** WUI-01--04.
|
|
|
|
**Deliver:** job-scoped download proxy, CSV preview limited by byte/row count,
|
|
checksum/size metadata display, and prominent partial/final labels.
|
|
|
|
**Acceptance:** artifact from another job is 404; path traversal cannot select a
|
|
file; `Content-Disposition` is safe; preview never loads an unbounded CSV; no
|
|
final-result button exists before CTX-09.
|
|
|
|
### WUI-06 — Final-result UX after CTX-09
|
|
|
|
**Depends on:** CTX-09 and WUI-05.
|
|
|
|
**Deliver:** `reducing` state, final artifact card, final CSV preview/download,
|
|
and deterministic result metadata.
|
|
|
|
**Acceptance:** final link is shown only for `completed`; reducer failure is
|
|
sanitized; page refresh/restart preserves final artifact; end-to-end test
|
|
compares downloaded final search CSV with local reference output.
|
|
|
|
### WUI-07 — Full similarity-graph UX after CTX-10
|
|
|
|
**Depends on:** CTX-10 and WUI-06.
|
|
|
|
**Deliver:** enabled graph form, block-pair planning summary, graph-specific
|
|
progress, final edge-list preview/download, and warnings for low thresholds.
|
|
|
|
**Acceptance:** graph result equals local brute force on a small fixture; no
|
|
dense matrix is introduced; threshold direction is displayed and preserved;
|
|
result order is deterministic.
|
|
|
|
### WUI-08 — Manual-demo script and CI browser checks
|
|
|
|
**Depends on:** WUI-05; extend after WUI-06/07.
|
|
|
|
**Deliver:** `make demo-ui` (or documented compose profile), a tiny tracked TSV
|
|
fixture, start/stop instructions, and headless browser smoke tests.
|
|
|
|
**Acceptance:** clean checkout can start coordinator, a worker, open UI,
|
|
submit fixture, observe task completion, and download a diagnostic artifact.
|
|
CI covers auth, upload, polling JSON, job isolation, and download permission.
|
|
|
|
## 10. Testing strategy
|
|
|
|
| Layer | Required checks |
|
|
| --- | --- |
|
|
| Go domain/use case | status projection, artifact/job ownership, pagination ordering, redaction. |
|
|
| Go HTTP | UI auth separation, malformed multipart, CSRF-safe same-origin policy, 404/401, headers, escaping. |
|
|
| PostgreSQL | fresh migrations, list/detail query ordering, cross-job artifact denial, completed/final state. |
|
|
| Browser | form validation, upload success/failure, polling transition, terminal state, safe text rendering. |
|
|
| End-to-end | real PostgreSQL + coordinator + Python worker + small fixture; verify actual bytes/checksum. |
|
|
|
|
Use Playwright only if it can run in CI without adding a production runtime
|
|
dependency. Otherwise start with Go handler tests and a small `curl`/HTML
|
|
smoke script, then add browser automation in WUI-08.
|
|
|
|
## 11. Manual verification script after WUI-05
|
|
|
|
```sh
|
|
# terminal 1
|
|
cd coordinator
|
|
UI_AUTH_TOKEN='local-ui-secret' make up
|
|
|
|
# terminal 2: use a separate worker token; do not paste it into the browser
|
|
SCIMESH_COORDINATOR_URL=http://localhost:8080 \
|
|
SCIMESH_BEARER_TOKEN='worker-secret' \
|
|
scimesh-worker --work-dir ./worker-data
|
|
|
|
# browser
|
|
# http://localhost:8080/ui
|
|
# authenticate with the UI token, upload a tiny TSV, then watch /ui/jobs/{id}
|
|
```
|
|
|
|
The actual configuration variable names, compose wiring, and launch command are
|
|
implemented in WUI-02/WUI-08; this block is the acceptance target, not a claim
|
|
that the interface exists today.
|
|
|
|
## 12. Explicit non-goals for the initial interface
|
|
|
|
- no database browser or SQL console;
|
|
- no browser-side RDKit or scientific calculation;
|
|
- no worker start/stop shell execution from UI;
|
|
- no multi-user accounts, RBAC, password reset, public internet exposure, or
|
|
user-provided storage credentials;
|
|
- no WebSocket/SSE, React/Vue, Docker requirement for the Python package, or
|
|
deployment platform;
|
|
- no claim that a distributed graph or search result is final before its
|
|
planner/reducer acceptance criteria are met.
|
|
|
|
## 13. Definition of done for the first hand-testable release
|
|
|
|
WUI-00 through WUI-05 are complete when a clean local checkout can run a
|
|
trusted, authenticated local UI; display coordinator readiness, workers, jobs,
|
|
tasks and safe errors; submit a valid small search pipeline check; poll it to a
|
|
terminal task state; and download/preview the coordinator-owned partial CSV.
|
|
The page must make the absence of final reduction impossible to miss.
|