Frontend modules
Module reference for src/frontend/src/. The SPA is Vue 3 + Vite + Pinia + Fomantic UI. State is held in Pinia stores; HTTP via axios; streaming inference via a fetch-based composable that parses SSE. For an overview of how the SPA fits into the deployed container, see explanation/architecture.md.
Project layout
src/frontend/src/
βββ main.js # bootstrap (Pinia, router, theme init)
βββ App.vue # shell with NavBar, RouterView, GraphBackground
βββ api/ # axios client + per-method API wrappers
βββ composables/ # reusable logic (SSE stream)
βββ stores/ # Pinia stores (one per demo + theme)
βββ router/ # vue-router routes incl. SPA 404
βββ views/ # page-level components
βββ components/ # feature-grouped components
βββ data/ # static data (CV)
βββ styles/ # design tokens + theme + responsive CSS
main.js β bootstrap
Imports Fomantic CSS, design-token sheets, the App shell, the router and the theme store. Creates a Pinia instance, wires it into the app, calls useThemeStore().init() to apply the persisted theme, and mounts to #app.
api/ β HTTP client and endpoint wrappers
client.js
Creates the axios instance. The base URL is ${import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:8000'}/api/v1. The ?? (not ||) is load-bearing: the production env file sets VITE_API_BASE_URL= to an empty string so the SPA hits the same origin, and ?? preserves that empty string while || would have fallen back to localhost.
Also exports apiError(error) β pulls the structured { code, message, details } envelope back out of an axios error.
coins.js, graphGeneration.js, kgAnomaly.js, health.js
Thin wrappers around the discovery endpoints. Each function returns the parsed JSON response. The streaming endpoints are not hit through these wrappers β they go through useSseStream directly.
composables/useSseStream.js
The SSE client. Implements:
InferenceHttpErrorβ typed error withstatus,code,details(matches the backend error envelope).useSseStream({ path, body, onProgress, onPreview, onResult, signal })β POSTs to${baseURL}${path}, reads the response body as a stream, parses SSE frames, and dispatches them. Honours anAbortSignalfor client-side cancellation.
The base URL is computed the same way as in client.js β same ?? rule applies.
This composable is the only place in the frontend that talks to the streaming endpoints. Stores instantiate it from their action functions.
stores/ β Pinia state
theme.js
Stores the active theme (light / dark / auto), persists it to localStorage, and toggles <html> classes on change. init() reads the persisted value at app start.
coinsDemo.js
Holds:
- The dataset / algorithm / query-structure metadata fetched from
/coins/*. - The user's currently selected
(dataset_id, queryStructure, algorithm, anchors, variables, relations, topK). loading,error,errorCode,resultfor the prediction call.
Getters expose selectedStructure and allowedAlgorithms (the intersection of the algorithms the dataset has and the ones that support the chosen query structure). Actions wrap the API client functions.
multiproxanDemo.js
Mirrors coinsDemo.js for the graph-generation demo. State includes the chosen model_type (discrete / continuous), sampling_mode (standard / multiprox), generation parameters, the live preview URL, the kg_log_likelihood trace (only for the kg-anomaly correction case but kept here too for future symmetry), and the continuation state blob between Gibbs rounds.
kgAnomalyDemo.js
The KG-anomaly demo state. Holds the picked sample subgraph, the user's edits, the running progress, the preview reel and the kg_log_likelihood trace.
router/index.js
Five named routes:
| Path | Name | View |
|---|---|---|
/ |
home |
HomeView.vue |
/cv |
cv |
CVView.vue |
/demos/coins |
demo-coins |
CoinsView.vue (lazy) |
/demos/multiproxan |
demo-multiproxan |
MultiProxAnView.vue (lazy) |
/demos/kganomaly |
demo-kganomaly |
KgAnomalyView.vue (lazy) |
/:pathMatch(.*)* |
not-found |
NotFoundView.vue |
The catch-all is the Lara Croft 404 β the Django backend serves the SPA shell for unknown paths and Vue Router takes it from there. meta.title is applied to document.title in router.afterEach.
views/ β pages
| View | Purpose |
|---|---|
HomeView.vue |
Hero intro, demo preview cards, fact of the day, system status. |
CVView.vue |
CV rendering driven by data/cv.js. |
NotFoundView.vue |
Lara Croft 404 with random hero image and credits. |
demos/CoinsView.vue |
The COINs demo (query construction, prediction results). |
demos/MultiProxAnView.vue |
Graph-generation demo (parameter panel, preview reel, chain GIF). |
demos/KgAnomalyView.vue |
KG-anomaly demo (subgraph picker, change list, log-likelihood plot). |
components/ β feature groups
Components are grouped by feature folder, not by type. Cross-feature primitives live in common/ and layout/.
| Folder | Notable components |
|---|---|
background/ |
GraphBackground.vue, FloatingMotif.vue β animated graph drawing background. |
common/ |
EtaTracker.js, FitText.vue, InferenceErrorBanner.vue, PreviewReel.vue, SseProgressBar.vue, StepTimeline.vue β primitives used across demos. |
layout/ |
NavBar.vue, PageSection.vue, ThemeToggle.vue. |
home/ |
HeroIntro.vue, DemoPreviewCard.vue, FactOfTheDay.vue, SystemStatus.vue. |
cv/ |
Education.vue, WorkExperience.vue, Publication.vue, ProjectCard.vue, Skill.vue, Language.vue, LogoOrAcronym.vue, Reference.vue, SocialLink.vue. |
coins/ |
AlgorithmSelector.vue, QueryStructurePicker.vue, QueryGraph.vue, QueryDescription.vue, SearchableEntityDropdown.vue, SearchableRelationDropdown.vue, SearchablePicker.vue, PredictionList.vue, ResultsDashboard.vue, CommunityRankCallout.vue, TimingPanel.vue. |
multiproxan/ |
ParametersPanel.vue β parameter form for both sampling modes. |
kganomaly/ |
SampleSubgraphCard.vue, ChangeList.vue β subgraph picker and per-edge change explanations. |
data/cv.js
A static JS module exporting the CV's structured data (education, work, publications, etc.). Updating the CV is a plain code edit β no DB.
styles/
| File | Purpose |
|---|---|
tokens.css |
Design tokens (color, spacing, font sizes). |
theme.css |
Light / dark theme variable bindings. |
responsive.css |
Breakpoint helpers. |
Build and env
npm run devβ Vite dev server onhttp://localhost:5173, proxied to the Django dev server athttp://localhost:8000viaVITE_API_BASE_URLfrom.env.development.npm run buildβ emitsdist/(the production bundle that the container copies into Django'sdist/so WhiteNoise serves it)..env.developmentβVITE_API_BASE_URL=http://localhost:8000..env.productionβVITE_API_BASE_URL=(empty for same-origin).
See also
- explanation/architecture.md β how the SPA is served by the Django container.
- reference/sse-protocol.md β exactly what the demo stores parse from streaming responses.
- guides/local-development.md β running the frontend dev server alongside Django.