File size: 5,169 Bytes
175b650 8bf4795 175b650 8bf4795 175b650 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | # 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:
```bash
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](../../docs/guides/local-development.md)).
Production build:
```bash
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`](../../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:
```js
`${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`](../../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`](../../docs/reference/frontend-modules.md) β full module reference.
- [`docs/reference/sse-protocol.md`](../../docs/reference/sse-protocol.md) β the streaming protocol the demo stores parse.
- [`docs/guides/local-development.md`](../../docs/guides/local-development.md) β running both servers together.
- [`docs/explanation/architecture.md`](../../docs/explanation/architecture.md) β how the SPA is served by the deployed container.
|