website / src /frontend /README.md
Andrej Janchevski
docs: add technical documentation set
175b650

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 β€” createWebHistory mode, 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/*.js parse the response and return data directly.
  • Streaming endpoints (/graph-generation/{generate,continue}, /kg-anomaly/{correct,continue}) are consumed via useSseStream. Stores wire its onProgress / onPreview / onResult callbacks to mutate state.
  • Errors come back as { error: { code, message, details } }. apiError(error) (in client.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