Frontend Runtime Architecture
Frontend Runtime Architecture
Status: draft
Last updated: 2026-05-11
Audience: frontend implementers, backend implementers, atlas-engine implementers, Rust/WASM implementers, accessibility reviewers, and architecture reviewers.
Related documents:
- Backend runtime architecture
- Offline index runtime architecture
- Solver system architecture
- Frontend application shell spec
- Frontend backend contract spec
- Atlas engine and WASM spec
- Backend API spec
- Query evaluation semantics spec
- Graph view response spec
- Student state schema spec
- ADR 0020
- ADR 0021
- ADR 0022
- ADR 0023
Primary external references:
- Svelte overview
- SvelteKit routing
- SvelteKit loading data
- SvelteKit Node servers
- SvelteKit hooks
- SvelteKit state management
- SvelteKit accessibility
- SvelteKit performance
- MDN Web Workers
- MDN WebAssembly
wasm-bindgenguide- MDN WebGL API
- MDN WebGPU API
- three.js documentation
- three.js WebGPU renderer documentation
wgpucrate documentation- Zod documentation
- TanStack Query Svelte overview
- Playwright documentation
- Vitest documentation
- Waterloo undergraduate Academic Calendar
- Waterloo guide to navigating the Undergraduate Studies Academic Calendar
1. Thesis
The frontend is the experiential surface of UWScrape.
The backend is the academic authority of UWScrape.
The atlas is a projection of backend graph and query data.
The atlas is not the truth model.
The browser should feel immediate.
The browser should not become academically authoritative.
The SvelteKit server should make frontend deployment and routing flexible.
The SvelteKit server should not become a shadow backend.
Rust/WASM should make heavy atlas projection deterministic and responsive.
Rust/WASM should not become a second evaluator for academic rules.
WebGL should make the first atlas broadly usable.
WebGPU should be a progressive renderer backend.
Accessibility fallback should be part of the architecture.
The UI should help students understand pathways without pretending to be official advising.
2. Central Rule
Backend owns academic meaning.
Frontend owns immediacy.
Frontend owns presentation of projection.
Frontend owns interaction.
Frontend owns rendering.
Frontend owns local view state.
Rust/WASM owns bounded deterministic layout kernels.
Index-build and backend services own dense projection preparation.
Renderer backends own drawing.
No frontend component owns academic correctness.
No geometry owns academic correctness.
No renderer owns academic correctness.
No local cache owns academic correctness.
3. Architectural Shape
The version 1 product has three major runtime processes or execution contexts.
The first is the Go backend.
The second is the SvelteKit Node server.
The third is the browser runtime.
The browser runtime includes the Svelte client app.
The browser runtime includes the atlas engine.
The browser runtime includes the Rust/WASM layout worker.
The browser runtime includes the WebGL renderer.
The browser runtime may include a WebGPU renderer later.
The browser runtime also includes non-canvas fallback UI.
The Go backend can run without the SvelteKit server for API-only testing.
The SvelteKit server can run without becoming an academic runtime.
The browser can render public catalog exploration without a state token.
State-dependent academic results require backend calls.
4. Topology Diagram
flowchart LR User["student browser"] --> SvelteClient["SvelteKit client app"] SvelteClient --> AtlasEngine["AtlasEngine"] AtlasEngine --> LayoutWorker["RustWasmLayoutWorker"] AtlasEngine --> Renderer["RendererBackend"] Renderer --> WebGL["WebGL / Three.js"] Renderer -. optional .-> WebGPU["WebGPU backend"] SvelteClient --> Fallback["AtlasFallbackView"] SvelteClient --> SvelteServer["SvelteKit Node server"] SvelteServer --> GoAPI["Go backend /api/v1"] SvelteClient -. split origin .-> GoAPI GoAPI --> Index["published index"] GoAPI --> StateDB["state SQLite"]The diagram is descriptive.
It is not a deployment mandate beyond ADR 0020.
ADR 0020 makes the SvelteKit Node server the primary v1 frontend deployment.
The split-origin path remains useful for local development.
The Go backend remains the only runtime that opens the published index.
The Go backend remains the only runtime that opens the state database.
5. Product Mission
The frontend should make academic pathway structure navigable.
The frontend should let students explore before choosing a target credential.
The frontend should let students add a target credential when they want a degree-CAD workflow.
The frontend should show courses as spatial entities in the atlas.
The frontend should show requirement groups and conditions as explicit graph entities where useful.
The frontend should show prerequisite, unlock, antirequisite, equivalence, cross-listing, and requirement-participation relationships.
The frontend should show completed and planned courses as user state overlays.
The frontend should show unknown and conflict states without shame or panic.
The frontend should make source references part of normal inspection.
The frontend should preserve the distinction between exploration and authoritative academic advice.
6. Non-Goals
The frontend does not scrape Waterloo data.
The frontend does not parse Kuali rules.
The frontend does not publish indexes.
The frontend does not approve release gates.
The frontend does not store token verifier records.
The frontend does not choose index schema support.
The frontend does not perform credential-progress evaluation as academic truth.
The frontend does not perform course-unlock evaluation as academic truth.
The frontend does not implement a complete planning solver.
The frontend does not replace advisor judgment.
The frontend does not require WebGPU.
The frontend does not require canvas for basic access to information.
7. Framework Decision
The frontend uses SvelteKit with TypeScript.
This follows ADR 0020.
Svelte is documented as a compiler-based UI framework.
SvelteKit provides routing, data loading, hooks, state-management guidance, accessibility behavior, performance features, and adapters.
SvelteKit route files should express the main product routes.
Svelte components should express panels, details, forms, and fallback views.
TypeScript should express frontend contracts.
Runtime validation should protect the network boundary.
SvelteKit should not hide backend response semantics.
SvelteKit should not absorb academic responsibility.
8. SvelteKit Node Server Decision
The v1 production frontend uses the SvelteKit Node adapter/server.
The SvelteKit docs describe adapter-node as generating a standalone Node server.
The Node server can run route loads.
The Node server can serve frontend assets.
The Node server can provide same-origin API proxying.
The Node server can set frontend headers.
The Node server can record frontend observability.
The Node server can simplify future session work.
The Node server is not a second Go backend.
The Node server is not an index reader.
The Node server is not a state database reader.
The Node server is not an academic evaluator.
9. Why Not Static-Only First
Static-only deployment would be simpler.
Static-only deployment would reduce one runtime process.
Static-only deployment would make local hosting easy.
Static-only deployment would also remove server-side frontend hooks that are useful for same-origin proxying, observability, headers, and future sessions.
The frontend is expected to become a substantial application surface.
The SvelteKit server buys deployment freedom.
The cost is operational complexity.
This architecture accepts that cost.
The cost is controlled by keeping the SvelteKit server thin.
Go static serving remains a fallback, not the primary v1 frontend path.
10. Server Thinness Rule
Thin means no academic data ownership.
Thin means no direct index access.
Thin means no direct state store access.
Thin means no solver or evaluator logic.
Thin means no parser logic.
Thin means no scraper logic.
Thin means no token verifier storage.
Thin means frontend request handling only.
Thin means proxying is allowed.
Thin means response validation is allowed.
Thin means observability is allowed.
Thin means rendering routes is allowed.
11. Go Backend Boundary
The Go backend owns /api/v1.
The Go backend owns the published index runtime contract.
The Go backend owns source-reference authority.
The Go backend owns query evaluation.
The Go backend owns explanation trees.
The Go backend owns unknown propagation.
The Go backend owns conflict reporting.
The Go backend owns state persistence.
The Go backend owns state export.
The Go backend owns state deletion.
The Go backend owns state migration.
The frontend calls the backend for academic answers.
12. Browser Boundary
The browser owns camera state.
The browser owns hover state.
The browser owns selection state.
The browser owns focus state.
The browser owns panel state.
The browser owns route navigation.
The browser owns local filters.
The browser owns semantic zoom.
The browser owns renderer selection.
The browser owns fallback selection.
The browser owns temporary unsaved edits.
The browser does not own saved academic state.
13. Frontend-Owned Compute
Frontend-owned compute includes camera transforms.
Frontend-owned compute includes viewport culling.
Frontend-owned compute includes local visual filters.
Frontend-owned compute includes hover and selection.
Frontend-owned compute includes pointer picking.
Frontend-owned compute includes label visibility decisions.
Frontend-owned compute includes animation.
Frontend-owned compute includes small-slice visual clustering when the backend or index projection does not already provide the needed grouping.
Frontend-owned compute includes small visible-subgraph preparation from already-loaded graph views.
Frontend-owned compute includes local preview rendering.
Frontend-owned compute excludes catalog-wide closure, catalog-wide Advisory enumeration, and large universal Canva layout preparation.
Frontend-owned compute excludes academic satisfaction.
Frontend-owned compute excludes source-backed truth claims.
14. Backend-Owned Compute
Backend-owned compute includes course unlock.
Backend-owned compute includes credential progress.
Backend-owned compute includes credential gap summary.
Backend-owned compute includes what-if academic results.
Backend-owned compute includes source-backed course impact metrics.
Backend-owned compute includes unknown propagation.
Backend-owned compute includes conflict propagation.
Backend-owned compute includes solver routing.
Backend-owned compute includes explanation tree construction.
Backend-owned compute includes state persistence and migration.
Backend-owned compute includes source-reference authority.
Backend-owned compute includes release metadata.
Backend-owned compute includes dense course-universe projection serving and cache lookup.
Backend-owned compute includes bounded Advisory and pathway traversal.
Backend-owned compute includes relation-index preparation that protects weak clients from expensive graph walks.
Index-build-owned compute includes deterministic universal graph projection artifacts and layout hints when the published index includes them.
Future server-side accelerator compute may include GPU-backed projection, layout, or solver-preparation kernels behind the same backend contracts after profiling proves a CPU/cache path insufficient.
15. Rust/WASM-Owned Compute
Rust/WASM-owned compute includes deterministic atlas layout for small active slices, fallback views, and interaction-local jobs.
Rust/WASM-owned compute includes spatial indexing.
Rust/WASM-owned compute includes hit-test acceleration.
Rust/WASM-owned compute includes collision checks.
Rust/WASM-owned compute includes label candidate placement.
Rust/WASM-owned compute includes visible-subgraph filtering over loaded projections when the slice is already bounded for the client.
Rust/WASM-owned compute includes short path tracing over loaded projection data.
Rust/WASM-owned compute includes layout metrics.
Rust/WASM-owned compute excludes full catalog-universe closure and large universal Canva coordinate generation when server or index hints are available.
Rust/WASM-owned compute excludes academic status generation.
Rust/WASM-owned compute excludes source-reference generation.
Rust/WASM-owned compute excludes backend API calls.
Rust/WASM-owned compute excludes token handling.
16. The Atlas Engine
AtlasEngine is the orchestrating frontend subsystem.
It consumes graph view responses.
It converts graph responses into compact layout inputs.
It schedules layout jobs.
It coordinates worker lifecycle.
It coordinates renderer lifecycle.
It coordinates camera and selection state.
It exposes events to Svelte components.
It exposes diagnostics.
It can degrade to fallback.
It is not a backend API.
It is not an academic model.
17. Atlas Data Adapter
AtlasDataAdapter converts backend graph views into atlas input.
It preserves backend ids.
It preserves node types.
It preserves edge types.
It preserves source reference ids.
It preserves omitted counts.
It preserves graph bounds.
It preserves overlays.
It can create numeric ids for arrays.
It must maintain a reversible mapping.
It must not infer academic type from id formatting.
It must not invent academic edges.
18. Layout Backend
LayoutBackend is the interface for layout compute.
The first implementation uses RustWasmLayoutWorker.
The interface should include initialization.
The interface should include graph loading.
The interface should include layout execution.
The interface should include viewport updates.
The interface should include filter updates.
The interface should include cancellation.
The interface should include disposal.
The interface should include diagnostics.
The interface should distinguish degraded output from failure.
The interface should distinguish worker failure from academic unknown.
19. RustWasmLayoutWorker
RustWasmLayoutWorker runs in a Web Worker.
MDN documents Web Workers as background threads that can run scripts without interfering with the UI.
The worker loads the WASM module.
The worker receives compact graph data.
The worker returns layout arrays.
The worker returns picking structures.
The worker returns label candidates.
The worker returns cluster ids.
The worker returns visibility masks.
The worker returns layout diagnostics.
The worker never receives raw state_token.
The worker never calls /api/v1.
20. WebAssembly Role
MDN documents WebAssembly as a binary instruction format for a stack-based virtual machine that can run in web contexts.
The wasm-bindgen guide documents Rust and JavaScript interoperability.
For UWScrape, WebAssembly is a bounded client compute boundary.
It is not a security boundary.
It is not an academic boundary.
It is not a persistence boundary.
It is not a renderer requirement.
It is required for the first atlas layout implementation.
It should make deterministic algorithms easier to isolate.
It should keep heavy work away from the main thread.
It should not become the primary compute tier for the full course universe.
It should prefer backend/index layout hints when they are present.
It should not be used for every piece of frontend code.
It should not be introduced outside atlas compute without a measured reason or later ADR.
21. Worker Message Discipline
Worker messages should be explicit.
Worker messages should include request ids.
Worker messages should include message type.
Worker messages should include compact payloads.
Worker messages should avoid raw source text.
Worker messages should avoid raw tokens.
Worker messages should avoid large nested objects when arrays are enough.
Worker responses should preserve request ids.
Worker responses should include timing diagnostics.
Worker responses should include warnings for degraded output.
Worker responses should include structured error categories.
Worker responses should not include academic statuses invented by the worker.
22. Deterministic Layout
The same graph input and seed should produce the same layout within documented tolerance.
The seed should be explicit.
The layout mode should be explicit.
The layout parameters should be explicit.
The worker should avoid nondeterministic iteration where output depends on order.
Floating-point behavior must be tested within tolerance.
The renderer is not required to rasterize identically across devices.
Deterministic layout supports debugging.
Deterministic layout supports visual regression tests.
Deterministic layout supports user trust when reopening the same view.
Deterministic layout does not create academic truth.
23. Renderer Backend
RendererBackend is the drawing interface.
It initializes graphics resources.
It receives scene data from AtlasEngine.
It updates camera.
It updates viewport size.
It updates status overlays.
It updates selection overlays.
It renders frames.
It reports capabilities.
It disposes resources.
It never evaluates requirements.
It never persists academic state.
It never changes backend result statuses.
24. WebGL Baseline
WebGL is the required canvas baseline.
MDN documents WebGL as a web API for rendering interactive 2D and 3D graphics.
Three.js is the preferred v1 rendering library.
Three.js has a mature WebGL-centered documentation and ecosystem.
WebGLRendererBackend must be tested.
WebGLRendererBackend must initialize without WebGPU.
WebGLRendererBackend must handle context failure.
WebGLRendererBackend must expose diagnostics.
WebGLRendererBackend must support fallback.
WebGL absence cannot make the entire app unusable.
The non-canvas fallback remains required.
25. WebGPU Progressive Path
WebGPU is optional.
MDN documents WebGPU as available only in secure contexts and not uniformly available across all browsers.
Three.js documents a WebGPU renderer.
WebGPURendererBackend may be implemented later.
It should use capability detection.
It should fall back to WebGL on failure.
It should use the same atlas scene semantics.
It should not require a different backend API.
It should not change academic results.
It may improve large-view rendering.
It may improve GPU batching.
It may improve visual fidelity.
26. Why Not Rust Rendering First
Rust rendering through wgpu is plausible.
The wgpu crate documents a cross-platform Rust graphics API based on WebGPU concepts.
It can run over native graphics APIs and web backends.
It is powerful.
It would also increase the first implementation’s toolchain complexity.
The v1 split keeps rendering in TypeScript and Three.js.
The v1 split keeps deterministic layout in Rust/WASM.
This separates visual library risk from layout algorithm risk.
The project can revisit Rust rendering after measuring the TypeScript renderer.
No current doc should make Rust rendering mandatory for v1.
27. Fallback Requirement
The atlas must have a non-canvas fallback.
The fallback is not optional.
The fallback is part of accessibility.
The fallback is part of low-power support.
The fallback is part of graphics failure recovery.
The fallback should render graph nodes and relationships as navigable lists or tables.
The fallback should support search.
The fallback should support filters.
The fallback should support selection.
The fallback should support detail opening.
The fallback should show academic statuses.
The fallback should show source references.
28. Accessibility Architecture
SvelteKit documents route announcements, focus management, and compile-time accessibility checks.
SvelteKit also states that application code remains responsible for accessibility.
UWScrape must not treat the atlas canvas as the only interface.
Every primary object in the atlas must be reachable through text UI.
Every academic result must be reachable through text UI.
Every source reference must be reachable through text UI.
Every destructive state flow must be keyboard usable.
Color must not be the only status indicator.
Motion must not be required for comprehension.
Reduced-motion preferences must be respected.
The fallback view must be tested.
29. Routing Architecture
SvelteKit routing should provide the main page structure.
The root route should lead to the atlas workspace.
Course detail routes should use subject and catalog number.
Credential detail routes should use backend credential ids.
State routes should handle state editing and lifecycle flows.
Timeline routes should handle completed and planned terms.
Source routes should handle source-reference inspection.
The atlas workspace may open detail panels without route changes.
Dedicated routes must still work without atlas initialization.
Routes must not include raw tokens.
Routes may include catalog-neutral visual state later if no token is included.
30. Route Data Loading
SvelteKit load functions may fetch route-level data.
Route-level catalog metadata is a good load candidate.
Course detail data is a good load candidate.
Credential detail data is a good load candidate.
Highly interactive graph expansion may use browser-side requests.
Interactive overlay refresh may use browser-side requests.
The same validation and token rules apply in both cases.
Server load functions must not store raw tokens.
Server load functions must not directly read backend files.
Server load functions must call the Go backend or proxy to it.
31. State Management
Frontend state splits into academic state, server state, and view state.
Academic state is saved through the backend.
Server state is cached backend API data.
View state is local UI state.
Academic state includes completed courses, grades, planned courses, progress, standing, credentials, unresolved references, notes, and preferences.
Server state includes course data, credential data, graph data, query results, source references, and catalog metadata.
View state includes camera, selection, filters, panels, renderer choice, and local drafts.
Only backend APIs can persist academic state.
View state must not be mistaken for academic state.
Server state must be invalidated when token or catalog changes.
32. State Token Handling
The raw state_token is a bearer secret.
The frontend must keep it out of URLs.
The frontend must keep it out of logs.
The frontend must keep it out of telemetry.
The frontend must keep it out of worker messages.
The frontend sends it as Authorization: Bearer <state_token>.
The browser may hold it in memory for the active session.
Persistent browser storage requires a deliberate later product decision or explicit user choice.
The SvelteKit server must not persist raw tokens.
The SvelteKit server may forward the token to the Go backend.
Invalid-token and deleted-token recovery should avoid leaking sensitive distinctions unless backend policy allows them.
33. API Client Architecture
The frontend should use a narrow API client.
The API client should own base URL resolution.
The API client should own token attachment.
The API client should own request ids.
The API client should own cancellation.
The API client should own envelope validation.
The API client should own redacted error conversion.
The API client should expose typed functions.
Components should not hand-roll /api/v1 calls.
Route load functions should reuse the same validation logic.
Proxy code should preserve backend response semantics.
34. Runtime Validation
TypeScript protects compile-time code.
It does not prove runtime JSON matches the spec.
The network boundary needs runtime validation.
Zod is the preferred first validation library.
Zod documents TypeScript-first schema validation.
Zod documents static type inference.
Zod documentation says strict TypeScript mode is required.
Validation failure is a contract error.
Validation failure is not academic unknown.
Validation failure should surface a redacted developer diagnostic.
Validation failure should not show fake data.
35. Server-State Library Posture
The project may use SvelteKit load functions directly.
The project may use TanStack Query for Svelte.
TanStack Query documents a Svelte API for query and mutation state.
This architecture does not require TanStack Query.
The implementation should choose based on the first frontend build.
If a library is used, it must preserve response envelopes.
If a library is used, it must support cancellation and invalidation.
If a library is not used, the app must implement those behaviors explicitly.
Cache keys must include catalog identity where data depends on catalog.
Cache keys must include state identity where data depends on token-backed state.
36. Cache Architecture
Catalog data may be cacheable.
Graph data may be cacheable when public and catalog-bound.
State-dependent data is private.
Query results that depend on state are private.
The app must respect backend cache headers.
The app must clear state-dependent cache when token changes.
The app must clear state-dependent cache after deletion.
The app must invalidate overlays after state mutation.
The app must not use stale cache to strengthen academic status.
The app must show stale or refreshing state when relevant.
37. Source References
Source references are first-class UI data.
The frontend must preserve source-reference ids.
The frontend must preserve source-reference links.
The frontend must preserve source snippets within publication policy.
The frontend should fetch full source reference details from backend endpoints.
The frontend must not generate authoritative source ids.
The frontend must not broadly republish raw calendar text.
The frontend should display the official source relationship plainly.
The frontend should let users move from claim to source.
The frontend should let users move from source to related claims when supported.
38. Unknowns
Academic unknown is a normal result.
Academic unknown is not a crash.
Academic unknown is not a transport error.
Academic unknown is not the same as timeout.
Academic unknown is not the same as unimplemented renderer.
Academic unknown should be visually distinct.
Academic unknown should explain why it is unknown when the backend says why.
Academic unknown should preserve source references.
Academic unknown should remain visible in atlas overlays.
Academic unknown should remain visible in detail panels.
Academic unknown should remain visible in explanation trees.
39. Conflicts
Academic conflict is a normal result.
Academic conflict is not a rendering error.
Academic conflict is not the same as antirequisite edge drawing.
Academic conflict should identify conflicting facts or constraints when backend data supports it.
Academic conflict should preserve source references.
Academic conflict should be visible in state editor contexts.
Academic conflict should be visible in query result contexts.
Academic conflict should be visible in atlas overlays.
Academic conflict should not be collapsed into not satisfied.
Academic conflict should prompt inspection, not panic.
40. Explanation Trees
Explanation trees are backend-facing academic explanations rendered by the frontend.
They should be stable across solver engines.
They should not expose raw solver internals.
They should support nested requirement groups.
They should support child statuses.
They should support unknown reasons.
They should support conflict reasons.
They should support source references.
They should support user-state facts.
They should support numeric thresholds.
They should be accessible without canvas.
They should be test fixtures for frontend rendering.
41. Course Detail Page
The course detail page is the exact inspection surface for a listing.
It should use /courses/[subject]/[catalog_number].
It should display canonical ids.
It should distinguish listing from credit identity.
It should show cross-listing relationships.
It should show prerequisites.
It should show antirequisites.
It should show enrollment constraints.
It should show source references.
It should show graph actions.
It should show user-state overlays when a token is active.
It should not infer contribution status locally.
42. Credential Detail Page
The credential detail page is the exact inspection surface for a credential.
It should use backend credential ids.
It should show credential type.
It should show requirement groups.
It should show requirement conditions.
It should show nested logic.
It should show source references.
It should show current progress when state is available.
It should show gap summary when requested.
It should show unknown requirements.
It should show conflicts.
It should not claim complete feasibility unless backend planning support exists.
43. State Editor
The state editor is the user-state editing surface.
It should preserve user-entered text.
It should resolve course references through backend endpoints.
It should resolve credential references through backend endpoints.
It should separate academic progress from academic standing.
It should preserve grades carefully.
It should display exact units from backend data.
It should avoid authoritative counts_for_credit user input.
It should allow user notes.
It should show migration and catalog mismatch states.
It should use backend state mutation endpoints.
It should support export and deletion flows.
44. Timeline
The timeline shows completed and planned terms.
It should show academic progress labels when present.
It should not infer academic standing.
It should show completed courses.
It should show planned courses.
It should show missing grades.
It should show unresolved references.
It should show local previews when edits are unsaved.
It should call backend what-if queries for academic claims.
It should link to course detail.
It should link to source references through explanations.
45. Target Credentials
Target credentials are optional.
The app should support exploration with no target.
The app should support at least one active target.
The state model can preserve desired credentials.
Declared credentials are separate from desired credentials.
Target selection may affect graph overlays.
Target selection may affect relevance ranking.
Target selection may affect visible filters.
Target selection must not change backend catalog truth.
Target selection must not cause local credential satisfaction claims.
Backend query results remain authoritative.
46. Command Surface
The app should provide a keyboard-friendly command surface.
It should search courses.
It should search credentials.
It should open the atlas.
It should open state editor.
It should add completed courses.
It should add planned courses.
It should choose target credentials.
It should export state.
It should import state.
It should request state deletion.
Destructive commands must require confirmation.
47. Import Flow
Import is a backend-mediated state operation.
The frontend may pre-validate file shape.
The backend owns import semantics.
The backend owns migration semantics.
The frontend should show catalog version before import.
The frontend should show migration warnings.
The frontend should preserve unresolved text.
The frontend should distinguish validation failure from academic unknown.
The frontend should not create state records locally.
The frontend should not hide import conflicts.
48. Export Flow
Export is read-only in v1.
The frontend calls the backend export endpoint.
The frontend must not wrap export in a hidden mutation.
The frontend should show export metadata.
The frontend should warn that exported state can be sensitive.
The frontend should not include token verifier material.
The frontend should not claim export audit was written.
The frontend should not put token values in downloaded file names.
The frontend should preserve backend response shape.
49. Delete Flow
Deletion is destructive.
The frontend must require explicit confirmation.
The frontend calls the backend deletion endpoint.
The backend owns hard deletion semantics for v1.
After deletion, the frontend clears active token state.
After deletion, the frontend clears state-dependent caches.
After deletion, the frontend should route to a safe recovery page.
After deletion, later token lookup should be treated like invalid-token recovery.
The frontend must not retain course history in hidden local caches.
The frontend must not promise retention.
50. Graph View Consumption
The graph view spec defines typed graph responses.
The frontend should request graph views by use case.
The frontend should not request a general graph query language in v1.
The frontend should use course-neighborhood for course context.
The frontend should use credential-requirements for credential context.
The frontend should use unlock-overlay for state overlays.
The frontend should use target-relevance for selected targets.
The frontend should use expand-node for intentional expansion.
The frontend should show bounds and omitted counts.
The frontend should not invent missing graph nodes.
51. Atlas Visual Grammar
Courses may be drawn as spatial nodes.
Requirement groups may be drawn as group nodes or gates.
Requirement conditions may be drawn as condition nodes.
Credentials may be drawn as target anchors.
Prerequisite edges may be drawn as directed threads.
Unlock edges may be drawn as directed threads.
Antirequisite edges may be drawn as conflict-like relationships.
Cross-listed edges may be drawn as equivalence relationships.
Source references may be drawn as inspectable annotations.
Visual grammar is explanatory.
Backend graph types are semantic.
52. Visual Size
Visual size may represent backend-provided metrics.
Visual size may represent unlock count.
Visual size may represent unlock diversity.
Visual size may represent credential relevance.
Visual size may represent bottleneck score.
Visual size may represent bridge score.
Visual size may represent conflict risk.
Visual size must be explainable.
Visual size must not imply official importance.
Visual size must be bounded so small nodes remain selectable.
Visual size must have text equivalents in fallback.
53. Color and Icons
Color may encode academic status.
Icons should also encode academic status.
Text labels should be available for academic status.
Unknown should be distinct from locked.
Conflict should be distinct from locked.
Partial should be distinct from satisfied.
Local preview should be distinct from backend result.
Renderer fallback should be distinct from academic result.
Color palettes should avoid one-note visual themes.
Contrast must be tested.
54. Motion
Motion can help preserve mental map.
Motion can also harm accessibility.
The app must respect reduced-motion preferences.
Camera moves should be interruptible.
Layout transitions should be interruptible.
Selection feedback should not depend only on animation.
Hover feedback should not move layout.
Background layout should not cause uncontrolled shifts.
The fallback view should work without motion.
55. Performance Principles
Measure before adding complexity outside the locked atlas WASM boundary.
Keep main-thread work small.
Use workers for heavy layout.
Use compact data transfer.
Cull invisible geometry.
Use semantic zoom.
Limit label density.
Avoid repeated full graph conversions.
Avoid waterfall API requests.
SvelteKit performance docs warn about waterfalls and describe built-in performance features.
Frontend performance must not hide correctness warnings.
56. Initial Performance Targets
The first target is usable atlas interaction on ordinary student laptops.
The second target is route responsiveness.
The third target is nonblank rendering after graph data arrives.
The fourth target is no long main-thread layout stalls.
The fifth target is clear fallback when graphics fails.
Concrete frame-rate targets should wait for real fixtures.
Concrete node-count targets should wait for first published index projections.
Performance claims must be measured.
Measurements should include low-power conditions when practical.
Measurements should be repeated after WebGPU work.
57. Deployment Topology
The primary v1 production topology has a SvelteKit Node server and Go backend.
They may run behind one reverse proxy.
They may run on the same host.
They may run in separate containers.
The SvelteKit server serves frontend routes.
The Go backend serves /api/v1.
The SvelteKit server may proxy /api/v1.
The reverse proxy may route /api/v1 directly to Go.
The topology should keep the browser origin simple when possible.
The Go backend can still run independently for API tests.
58. Same-Origin Proxy Mode
Same-origin proxy mode is the primary frontend-friendly deployment.
The browser calls the SvelteKit origin.
The SvelteKit server forwards API requests to Go.
The proxy preserves method.
The proxy preserves path.
The proxy preserves query.
The proxy preserves request body.
The proxy forwards authorization only to Go.
The proxy redacts logs.
The proxy preserves backend response status and envelope.
The proxy does not cache private state responses.
59. Split-Origin Mode
Split-origin mode remains supported for development or infrastructure preference.
The browser calls the Go backend origin directly.
The backend must use explicit allowed origins.
The backend must allow authorization headers only for trusted origins.
The frontend must be configured with the API origin.
The frontend must still use the same API client.
The frontend must still validate envelopes.
The frontend must still redact tokens.
Split-origin mode does not change academic semantics.
Split-origin mode does not make CORS wildcard acceptable for state endpoints.
60. Configuration
Frontend public configuration should include frontend origin.
Frontend public configuration may include API base path.
Frontend private configuration may include upstream Go backend origin for proxying.
Frontend configuration must not include token secrets.
Frontend configuration must not include state verifier keys.
Frontend configuration must not include raw index paths.
SvelteKit adapter-node deployment variables such as HOST, PORT, and ORIGIN must be configured according to deployment topology.
Reverse proxy header trust must be explicit.
Development configuration may point to a local Go backend.
Production configuration should prefer same-origin or explicit trusted-origin behavior.
61. Static Asset Fallback
The Go backend may still serve static frontend assets as an optional fallback.
This is no longer the primary v1 frontend path.
Static fallback must not change API semantics.
Static fallback must not enable browser academic evaluation.
Static fallback must still use /api/v1.
Static fallback must still avoid tokens in URLs.
Static fallback must still require non-canvas accessibility.
Static fallback may be useful for demos.
Static fallback may be useful for local single-binary experiments.
Static fallback requires explicit documentation if implemented.
62. Security Posture
The frontend handles sensitive student state.
Grades are sensitive.
Course history can be sensitive.
Desired credentials can be sensitive.
Notes can be sensitive.
The raw token is sensitive.
The frontend must avoid leaking sensitive state to logs.
The frontend must avoid leaking sensitive state to telemetry.
The frontend must avoid leaking sensitive state to URLs.
The frontend must avoid leaking sensitive state to worker diagnostics.
The frontend must avoid third-party scripts that weaken this posture.
63. Content Security Policy
The SvelteKit server may set content security policy.
The policy must account for worker scripts.
The policy must account for WASM loading.
The policy must account for renderer assets.
The policy should prefer same-origin assets.
The policy should avoid unsafe script allowances where practical.
The policy must be tested with the atlas worker.
The policy must be tested with WebGL rendering.
The policy must be tested with fallback views.
The policy must not require WebGPU.
64. Privacy of Diagnostics
Diagnostics should include request ids.
Diagnostics should include renderer backend.
Diagnostics should include worker status.
Diagnostics should include validation category.
Diagnostics should include API route family.
Diagnostics should include graph node counts.
Diagnostics should not include raw tokens.
Diagnostics should not include full grades.
Diagnostics should not include full course histories unless user explicitly exports state.
Diagnostics should not include raw source text beyond allowed snippets.
65. Observability
Frontend observability should answer whether the app is usable.
It should record route load durations.
It should record API durations.
It should record validation failures.
It should record worker job durations.
It should record renderer initialization failures.
It should record fallback activation.
It should record graph sizes.
It should record omitted counts.
It should distinguish semantic unknown from system error.
It should not include secrets.
66. Testing Strategy
Testing must cover pure display logic.
Testing must cover API envelope validation.
Testing must cover explanation tree rendering.
Testing must cover state-token handling.
Testing must cover atlas adapter mapping.
Testing must cover Rust layout determinism.
Testing must cover worker initialization.
Testing must cover WebGL rendering.
Testing must cover fallback rendering.
Testing must cover source-reference access.
Testing must cover unknown and conflict display.
67. Test Tooling
Vitest is the preferred unit test runner unless implementation research finds a blocker.
Playwright is the preferred browser test tool unless implementation research finds a blocker.
Rust unit tests should cover layout data structures.
WASM integration tests should cover JS/Rust boundary behavior.
Browser tests should avoid relying on WebGPU availability.
WebGPU tests should be conditional.
Visual tests should use deterministic layout seeds.
Accessibility tests should include keyboard-only flows.
Contract tests should validate fixture envelopes.
Tests must redact tokens.
68. Fixture Strategy
Frontend fixtures should be small and source-safe.
They should cover a course neighborhood.
They should cover credential requirements.
They should cover nested requirement groups.
They should cover cross-listed courses.
They should cover antirequisites.
They should cover unknown requirements.
They should cover conflicts.
They should cover graph omitted counts.
They should cover catalog mismatch.
They should cover invalid token.
They should not include real student secrets.
69. Acceptance Scenarios
A new visitor can explore public catalog graph data.
A returning visitor can restore state with a token.
A user can add completed courses.
A user can add planned courses.
A user can choose a target credential.
A user can open a course detail page.
A user can open a credential detail page.
A user can inspect an explanation tree.
A user can inspect a source reference.
A user can export state.
A user can delete state.
A user can use fallback without canvas.
70. Failure Scenario Matrix
Backend unavailable means system error.
Backend timeout means system error or incomplete system state.
Academic unknown means backend academic result.
Academic conflict means backend academic result.
Validation failure means contract error.
Invalid token means state access recovery.
Deleted token means state access recovery.
Catalog mismatch means migration or read-only recovery.
WebGPU failure means fallback to WebGL.
WebGL failure means fallback to non-canvas.
Worker failure means fallback or degraded layout.
Source link failure means source access warning.
71. Browser Compatibility
The v1 baseline depends on modern browsers with SvelteKit-supported JavaScript behavior.
The atlas canvas baseline depends on WebGL support.
The atlas layout baseline depends on WebAssembly and Web Worker support.
The app information baseline depends on normal HTML and JavaScript rendering.
WebGPU is not baseline.
The app should detect missing capabilities.
The app should explain missing capabilities.
The app should route to fallback when possible.
The app should avoid blank screens.
The app should test at least Chromium-family and Firefox-family browsers when practical.
Safari behavior should be tested before promising support.
72. Progressive Enhancement
The page shell should load before the atlas is ready.
The fallback view should be available before graphics are ready.
The atlas should enhance the fallback experience.
WebGL should enhance the atlas experience.
WebGPU may enhance the WebGL experience.
Worker layout should enhance responsiveness.
Source references should remain accessible at every enhancement level.
Academic statuses should remain consistent at every enhancement level.
Unknowns should remain visible at every enhancement level.
Conflicts should remain visible at every enhancement level.
73. Local Preview
Local preview is allowed.
Local preview covers unsaved edits.
Local preview covers visual filtering.
Local preview covers tentative graph highlighting from loaded data.
Local preview must be marked when it could be mistaken for backend result.
Local preview must not overwrite backend status.
Local preview must not be exported as academic truth.
Local preview must be invalidated when backend results return.
Local preview should make interaction feel fast.
Local preview should not pretend to be official.
74. Academic Status Display
Academic statuses come from backend payloads.
The frontend maps them to visual treatment.
The frontend may choose icons.
The frontend may choose colors.
The frontend may choose ordering.
The frontend may choose labels.
The frontend may choose animations.
The frontend may choose fallback text.
The frontend may not change the underlying status.
The frontend may not hide statuses in primary views.
The frontend may not merge unknown with not satisfied.
The frontend may not merge conflict with not satisfied.
75. Graph Bounds Display
Backend graph views are bounded.
Bounds protect performance and semantics.
The frontend must display omitted counts when present.
The frontend must display partial-view indicators when present.
The frontend must offer intentional expansion actions where supported.
The frontend must avoid implying that omitted nodes do not exist.
The frontend must avoid using local filters as backend bounds.
The frontend may explain graph bounds in an info panel.
The frontend should preserve bounds metadata through atlas adapter conversion.
The fallback view should show the same bounds information.
76. Source and Publication Discipline
The official Waterloo Academic Calendar remains the authoritative academic source.
Waterloo’s own calendar navigation guidance describes course requisites and program or plan requirements as rule-based academic calendar content.
The frontend should present source references, not republish broad raw calendar text.
The frontend should use backend source reference ids.
The frontend should use backend source URLs.
The frontend should use backend source snippets.
The frontend should show source hashes when helpful.
The frontend should show calendar version metadata.
The frontend should handle stale external links.
The frontend should not fetch live Kuali pages for academic truth.
The frontend should not mix UW Flow or other third-party data into source-backed claims unless a future policy explicitly allows it.
77. UI Copy Posture
UI copy should be calm.
UI copy should be precise.
UI copy should avoid overclaiming.
UI copy should distinguish official source data from tool interpretation.
UI copy should not repeat disclaimers everywhere.
UI copy should make unknowns understandable.
UI copy should make conflicts inspectable.
UI copy should make source references easy to reach.
UI copy should avoid internal solver terminology when not needed.
UI copy may use atlas metaphors where they help orientation.
78. Naming Discipline
Internal names should be operational.
Use AtlasEngine.
Use RendererBackend.
Use LayoutBackend.
Use RustWasmLayoutWorker.
Use GraphViewResponse.
Use ExplanationTree.
Use SourceReference.
Use AcademicResult.
Avoid rhetorical names for crucial architecture components.
Visual metaphors belong in product copy and design language.
79. Relationship to Solver Docs
The solver docs define academic result contracts.
The frontend renders those contracts.
The frontend does not expose raw engine internals.
The frontend does not need to know whether a result came from direct evaluation, Datalog, SAT, SMT, CP, or package-resolution style search.
The frontend should display completeness and unknowns.
The frontend should display explanation trees.
The frontend should display conflicts.
The frontend should display source references.
The frontend should not combine academic statuses on its own.
The frontend should ask the backend for combined results.
80. Relationship to Backend Specs
The backend API spec defines transport envelopes.
The backend state spec defines persisted state.
The query semantics spec defines academic query behavior.
The graph view spec defines typed graph projections.
The frontend backend contract spec defines client behavior.
The frontend app shell spec defines product surfaces.
The atlas spec defines visual engine behavior.
If these docs conflict, ADRs and backend specs own academic API behavior.
Frontend docs own presentation and client runtime behavior.
Conflicts should be corrected rather than patched in implementation.
81. Relationship to Offline Index Architecture
The index is built offline.
The frontend does not run the scraper.
The frontend does not consume raw snapshots.
The frontend consumes backend APIs and graph views.
The frontend may load graph projection data only through approved runtime contracts.
The atlas layout worker is a deliberate exception to earlier caution against requiring WASM before profiling.
That exception applies only to atlas layout and spatial compute.
For dense catalog-wide views, ADR 0026 makes index-build and backend precomputation the preferred compute path.
It does not license WASM for academic evaluation.
It does not license WASM for scraper parsing.
It does not license WASM for backend state logic.
82. Implementation Package Shape
The future frontend source tree will likely live under web/.
The SvelteKit app should own web/src/routes.
Shared frontend libraries should live under web/src/lib.
Atlas engine code should live under a clearly named frontend library path.
Rust/WASM atlas code should live under a clearly named workspace or package path.
Generated WASM bindings should be treated as build artifacts or generated source according to implementation policy.
The repository should avoid mixing generated artifacts with hand-written specs.
Package boundaries should make academic backend calls visible.
Package boundaries should make worker boundaries visible.
Package boundaries should make renderer boundaries visible.
83. Build Pipeline
The frontend build should compile SvelteKit.
The frontend build should compile TypeScript.
The frontend build should compile Rust/WASM atlas layout.
The frontend build should package worker assets.
The frontend build should produce a SvelteKit Node output.
The frontend build should fail on TypeScript errors.
The frontend build should fail on Rust compile errors.
The frontend build should fail on invalid generated bindings.
The frontend build should not require a live backend for static checks.
Integration tests may require a fixture backend or real local backend.
84. Development Workflow
Developers should run the Go backend locally.
Developers should run the SvelteKit dev server locally.
Developers should use fixture API responses for isolated frontend tests.
Developers should use a real local backend for integration tests.
Developers should run Rust tests for layout.
Developers should run browser tests for the atlas.
Developers should inspect screenshots for nonblank canvas behavior.
Developers should test fallback intentionally.
Developers should test token redaction intentionally.
Developers should test unknown and conflict rendering intentionally.
85. Release Readiness
Frontend release readiness requires API contract compatibility.
It requires successful frontend build.
It requires successful unit tests.
It requires successful browser smoke tests.
It requires successful WebGL baseline smoke.
It requires successful fallback smoke.
It requires successful worker initialization smoke.
It requires token redaction checks.
It requires unknown and conflict rendering checks.
It requires source-reference rendering checks.
It does not require WebGPU.
86. Documentation Requirements
Frontend code should link back to specs where behavior is non-obvious.
Architecture docs should stay synchronized with ADRs.
Specs should describe implementable contracts.
Examples should not contradict normative sections.
Docs should not describe the frontend as academic authority.
Docs should not describe WebGPU as required.
Docs should not describe Go static serving as primary v1 frontend deployment.
Docs should not describe WASM as required outside atlas layout.
Docs should not use unresolved placeholder terms.
Docs should keep source links near external claims.
87. Future Session Work
HttpOnly cookie sessions are a future extension.
Cookie sessions are not part of v1.
If cookie sessions are added, token storage and browser behavior must be redesigned.
If accounts are added, privacy and deletion semantics must be redesigned.
If collaboration is added, state authorization must be redesigned.
If public share links are added, token and state leakage must be reviewed.
If frontend offline mode is added, source and cache authority must be reviewed.
If browser WebGPU rendering becomes default, fallback obligations remain and dense graph preparation still belongs to index/backend services.
If Rust rendering is added, academic boundary remains.
If static deployment becomes primary, ADR 0020 must be revisited.
88. Risk Register
Risk one is frontend logic drifting into academic evaluation.
Mitigation is a strict API client and backend result contract.
Risk two is SvelteKit server becoming a shadow backend.
Mitigation is no direct index or state store access.
Risk three is WebGPU being treated as mandatory.
Mitigation is WebGL baseline and fallback tests.
Risk four is WASM increasing toolchain friction.
Mitigation is isolating WASM to atlas layout.
Risk five is canvas-only accessibility.
Mitigation is required non-canvas fallback.
Risk six is token leakage.
Mitigation is authorization-header discipline and redaction.
89. Proof Obligations
Implementation must prove that academic statuses originate from backend payloads.
Implementation must prove that source references survive API parsing and rendering.
Implementation must prove that unknowns survive API parsing and rendering.
Implementation must prove that conflicts survive API parsing and rendering.
Implementation must prove that graph bounds survive adapter conversion.
Implementation must prove that token changes clear state-dependent caches.
Implementation must prove that deletion clears local token state.
Implementation must prove that worker failure does not blank the app.
Implementation must prove that WebGPU absence does not block the app.
Implementation must prove that fallback views can inspect the same academic claims.
90. Example Data Flow
A user selects a course in the atlas.
The atlas maps the picked numeric id to a backend node id.
The Svelte component opens a selection panel.
The API client requests course detail if needed.
The backend returns a response envelope.
The API client validates the envelope.
The UI renders course fields.
The UI renders source references.
The UI offers query actions.
If the user asks whether the course is unlocked, the frontend calls the backend query endpoint.
The UI renders the returned academic result.
No layout component decides the answer.
91. Example Target Overlay Flow
A user selects a desired credential.
The UI stores the active target as view state or saved desired state depending on action.
The API client requests a target-relevance graph view.
The backend returns relevance data and graph metadata.
The API client validates the response.
The atlas adapter converts graph data into compact arrays.
The worker recomputes or updates layout.
The renderer updates visual emphasis.
The panel shows status and source references.
Unknown and conflict indicators remain visible.
The overlay is a projection of backend data.
92. Example State Edit Flow
A user adds a completed course.
The frontend records a local draft.
The frontend may display a local preview.
The local preview is marked as pending.
The user saves.
The API client sends a backend state mutation request.
The backend validates and persists state.
The backend returns updated state metadata.
The frontend invalidates state-dependent caches.
The frontend requests updated overlays or query results.
The frontend removes pending labels when backend results arrive.
93. Example Worker Failure Flow
The user opens the atlas.
The app attempts to initialize RustWasmLayoutWorker.
The worker fails to load the WASM module.
The atlas records a worker failure diagnostic.
The UI shows a degraded-view notice.
The UI opens AtlasFallbackView.
The user can still search graph nodes.
The user can still open detail panels.
The user can still inspect source references.
The failure is not rendered as academic unknown.
The app may offer retry.
94. Example WebGPU Failure Flow
The app detects WebGPU support is absent or initialization fails.
The app selects WebGLRendererBackend.
The app records renderer selection diagnostics.
The atlas renders through WebGL.
The user can continue normal core workflows.
No academic status changes.
No backend request shape changes.
No state migration occurs.
No warning should imply academic risk.
The warning may mention reduced graphics capability.
95. Example WebGL Failure Flow
The app attempts to initialize WebGLRendererBackend.
Initialization fails.
The app records a renderer failure diagnostic.
The app opens AtlasFallbackView.
The app shows a concise graphics fallback notice.
The user can search courses.
The user can inspect credentials.
The user can read explanation trees.
The user can inspect source references.
The failure is not academic unknown.
The failure should be testable.
96. Review Checklist
The architecture keeps backend academic meaning authoritative.
The architecture keeps SvelteKit server thin.
The architecture requires SvelteKit and TypeScript.
The architecture chooses SvelteKit Node server for v1 production.
The architecture requires Rust/WASM for atlas layout.
The architecture keeps rendering in TypeScript and Three.js for v1.
The architecture requires WebGL baseline.
The architecture keeps WebGPU optional.
The architecture requires non-canvas fallback.
The architecture preserves source references.
The architecture preserves unknowns and conflicts.
97. Implementation Checklist
Create SvelteKit TypeScript app under the chosen frontend source directory.
Configure SvelteKit Node adapter.
Create API client with runtime validation.
Create token handling utilities.
Create route shell.
Create atlas engine interface.
Create Rust/WASM worker package.
Create WebGL renderer backend.
Create fallback view.
Create explanation tree renderer.
Create source reference inspector.
Create browser and unit test harnesses.
98. Deferred Decisions
Exact package manager is deferred to implementation.
Exact CSS strategy is deferred to UI implementation.
Exact component library choice is deferred to UI implementation.
Exact server-state library choice is deferred to implementation.
Exact Rust crate layout is deferred to implementation.
Exact WebGPU implementation date is deferred.
Exact numeric performance budgets are deferred until fixtures exist.
Exact visual design system is deferred.
Exact telemetry backend is deferred.
Exact hosted deployment platform is deferred.
These are deferred implementation choices, not gaps in academic boundary decisions.
99. Correctness Summary
Correctness starts at the published index.
Correctness flows through the Go backend.
Correctness is expressed in response envelopes.
Correctness is explained through explanation trees.
Correctness is grounded by source references.
Correctness is weakened honestly by unknowns.
Correctness is protected by conflict reporting.
Correctness is displayed by the frontend.
Correctness is not created by the renderer.
Correctness is not created by layout.
Correctness is not created by visual size.
Correctness is not created by animation.
100. Final Architecture Statement
UWScrape’s frontend should feel like a rich interactive atlas.
Its implementation should be disciplined like a client of a formal academic API.
SvelteKit provides the application shell.
The SvelteKit Node server provides frontend runtime flexibility.
The Go backend provides academic truth.
The atlas engine provides spatial interaction.
Rust/WASM provides bounded deterministic layout compute.
Index-build and backend services provide dense universal graph projection, layout hints, and cached pathway or Advisory preparation.
Three.js WebGL provides the required renderer baseline.
WebGPU provides an optional future renderer path.
Fallback views provide access when graphics are unavailable.
Source references provide trust.
Unknowns and conflicts provide honesty.