Frontend β Vue 3 SPA
Single-page application for the PhD-research demo site. Vue 3 + Vite + Pinia + Fomantic UI; talks to the Django backend at /api/v1/*. Built once into dist/ at image-build time and served by WhiteNoise on the same origin as the API in production.
Tech stack
- Vue 3 (
^3.5.32) β composition-API components. - Vite 8 β dev server and production bundler.
- Vue Router 4 β
createWebHistorymode, lazy-loaded demo views, wildcard 404. - Pinia 3 β store-per-feature.
- axios β JSON HTTP client for discovery / non-streaming endpoints.
- Fomantic UI CSS β visual primitives (buttons, segments, dropdowns, etc.).
Quick start
From this directory:
npm install
npm run dev
Vite serves on http://localhost:5173. The Django backend must also be running on http://localhost:8000 (see the local-development guide).
Production build:
npm run build
# emits dist/, copied into the Docker image at /app/backend/dist
Project layout
src/frontend/src/
βββ main.js # bootstrap (Pinia, router, theme)
βββ App.vue # shell: NavBar, RouterView, GraphBackground
βββ api/ # axios client + per-method API wrappers
β βββ client.js
β βββ coins.js
β βββ graphGeneration.js
β βββ kgAnomaly.js
β βββ health.js
βββ composables/
β βββ useSseStream.js # SSE client for streaming inference
βββ stores/ # Pinia stores
β βββ coinsDemo.js
β βββ multiproxanDemo.js
β βββ kgAnomalyDemo.js
β βββ theme.js
βββ router/index.js # routes + lazy demo loading + wildcard 404
βββ views/ # page-level components
β βββ HomeView.vue
β βββ CVView.vue
β βββ NotFoundView.vue
β βββ demos/{Coins,MultiProxAn,KgAnomaly}View.vue
βββ components/ # feature-grouped components (coins/, multiproxan/, kganomaly/, cv/, home/, layout/, common/, background/)
βββ data/cv.js # static CV data
βββ styles/ # tokens, theme, responsive helpers
For a full walk-through of every store, composable and component group, see docs/reference/frontend-modules.md.
Environment variables
| File | Purpose | Value |
|---|---|---|
.env.development |
Dev β Vite reads this when running npm run dev. |
VITE_API_BASE_URL=http://localhost:8000 |
.env.production |
Prod β Vite reads this when running npm run build. |
VITE_API_BASE_URL= (empty β same-origin) |
Both src/api/client.js and src/composables/useSseStream.js compute their base URL as:
`${import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:8000'}/api/v1`
The ?? (not ||) is intentional β an empty string from .env.production must survive so the deployed SPA hits a same-origin /api/v1.
API conventions
- Discovery endpoints return JSON; the wrappers in
src/api/*.jsparse the response and returndatadirectly. - Streaming endpoints (
/graph-generation/{generate,continue},/kg-anomaly/{correct,continue}) are consumed viauseSseStream. Stores wire itsonProgress/onPreview/onResultcallbacks to mutate state. - Errors come back as
{ error: { code, message, details } }.apiError(error)(inclient.js) extracts that envelope from an axios error.
The exact event protocol is in docs/reference/sse-protocol.md.
Routing
| 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 (Lara Croft 404) |
In production, the Django backend serves dist/index.html for any non-API path so the SPA's history mode keeps working on hard refreshes.
Theming
stores/theme.js toggles a data-theme attribute on <html> between light and dark, persists the choice to localStorage, and falls back to prefers-color-scheme. The actual colors live in styles/tokens.css and styles/theme.css as CSS custom properties.
Background animation
components/background/GraphBackground.vue renders the floating-graph motif behind every page (the project's visual signature). It's mounted once in App.vue and respects prefers-reduced-motion.
See also
docs/reference/frontend-modules.mdβ full module reference.docs/reference/sse-protocol.mdβ the streaming protocol the demo stores parse.docs/guides/local-development.mdβ running both servers together.docs/explanation/architecture.mdβ how the SPA is served by the deployed container.