17 KiB
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.
Current delivered scope
The initial operator UI and CTX-09 final reduction are now implemented. The
control room polls a bounded, coordinator-owned read model every two seconds
while a tab is visible. It shows the worker fleet, recent jobs, safe shard
diagnostics, the actual reducing phase, and final-result availability. A job
detail page renders the concrete pipeline stages—input accepted, shards,
worker CSVs, reduction, final CSV—from coordinator state and replaces task and
artifact views as work changes. All browser mutations remain limited to
validated dataset upload and operator cancellation.
The interface must distinguish an in-progress distributed search from a run whose reducer has produced a durable final result:
| Mode | What it proves | What it must not claim |
|---|---|---|
| In-progress run | Upload, task creation, claim, heartbeat, artifact upload, task completion, retries, and shard diagnostics work end-to-end. | That the partial CSVs are a global scientific answer. |
| Final run | A reducer has produced a durable final CSV for the full job. | Available for similarity-search after CTX-09; graph remains unavailable until CTX-10. |
Never label a partial artifact as a final molecular result. The UI must show a
clear waiting or reducing stage until a final artifact exists and the job is
completed.
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 withdocker 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_TOKENfor browser/operator access. It must never reuseWORKER_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. IfUI_AUTH_TOKENis unset,/uiand/ui/api/*return404and the coordinator stays API-only. - Keep all user-controllable text escaped by
html/template; JavaScript renders API fields throughtextContent, neverinnerHTML. - 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-searchandsimilarity-graphrecommended, matching the CLI) and keep legacy underscore aliases only at the worker boundary. Updatedocs/api-contract.mdanddocs/openapi.yamlin the same change.
3. Target user journey
- Start coordinator/PostgreSQL and one or more
scimesh-workerprocesses. - Open
http://localhost:8080/ui, authenticate with the UI token, and see readiness plus the registered-worker table. - Choose New run, select a workload, fill validated parameters, choose a TSV, and submit it.
- The UI redirects to
/ui/jobs/{job_id}and polls every two seconds. - 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.
- 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
completedand a final artifact exists. - 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 | CTX-09 final artifact and download route exist | Show the reducing stage, then make the final CSV prominent only for completed. |
| Distributed graph correctness | Planner/reducer unavailable | Do not advertise a multi-shard graph as final until CTX-10. |
5. Proposed structure
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.
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_resultis downloadable only after the job iscompleted; 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_idandcanonical_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.
The current upload form accepts query_smiles, because resolving a
cross-shard query_id has not yet been connected to coordinator uploads. The
detail page calls an artifact a partial top-k CSV until all shards are
complete and CTX-09 reduction stores the final global result.
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 — implemented
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
# 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
The hand-testable release is complete when a clean local checkout can run a
trusted, authenticated local UI; display workers, jobs, pipeline stages, tasks
and safe errors; submit a valid small search; poll it through reducing; and
download the coordinator-owned final CSV only after completion. The page must
make the distinction between partial diagnostics and the final result
impossible to miss.