nodeledge management UI
Vue 3 + TypeScript + Vite single-page app for managing the stack: devices
and their settings, time-varying attribute timelines, app tokens and
message browsing. It has no backend of its own — every action is a
plain X-App-Token-authenticated call to the FastAPI api service
(/api prefix in production, see nginx.conf.template).
Auth today: paste an app token into the prompt (stored in the browser's localStorage). A real login flow will replace this later.
Running in the stack
The ui compose service builds this directory (see Dockerfile), serves
the built SPA with nginx and proxies /api/* to the api service
(API_UPSTREAM, default api:8000). Browser port: UI_HOST_PORT
(default 18090).
Local development (hot reload)
# requires a running api on localhost:18080 (docker compose up api db)
npm install
npm run dev # http://localhost:5173, /api proxied to :18080
Build / type-check
npm run build # vue-tsc --noEmit && vite build → dist/
The container build runs exactly this; dist/ is never committed.
Layout
src/
api.ts fetch wrapper: token header, 401 → token prompt, ApiError
store.ts toasts + token prompt state
router.ts hash routing (SPA routes can't collide with /api paths)
format.ts ISO 8601 helpers (local time display; naive input = UTC)
views/
Dashboard.vue totals + latest messages
Devices.vue list / add / delete devices
DeviceDetail.vue settings editor + attribute timeline (append/backdate/undo)
Tokens.vue add / rotate / delete app tokens
Messages.vue filter + page through stored messages, payload + resolved attributes
Two things worth knowing
- Timestamps: the API treats naive timestamps as UTC and returns
ISO 8601 with offsets; the UI always converts through
Dateso what you see is local time, anddatetime-localinputs are converted withnew Date(value).toISOString()before being sent. - Hash routing: routes look like
/#/deviceson purpose — with nginx serving both the SPA and the/apiproxy, path-routing could collide with API endpoints.