22b1b069df
Initialize CLAUDE.md schema, index, and log; ingest three architecture sources (system overview, Teltonika ingestion design, official Teltonika data-sending protocols) into 7 entity pages, 8 concept pages, and 3 source pages with wikilink cross-references.
58 lines
2.9 KiB
Markdown
58 lines
2.9 KiB
Markdown
---
|
|
title: React SPA
|
|
type: entity
|
|
created: 2026-04-30
|
|
updated: 2026-04-30
|
|
sources: [gps-tracking-architecture]
|
|
tags: [service, presentation-plane, frontend]
|
|
---
|
|
|
|
# React SPA
|
|
|
|
The end-user experience for operators and external participants. Single React application, role-based views, served as a static bundle.
|
|
|
|
## Why a separate SPA (not just the Directus admin UI)
|
|
|
|
The Directus admin UI is generic CRUD over collections — right for back-office editing and operators who think in records, wrong for end users who think in domain concepts. A dedicated SPA delivers:
|
|
|
|
- **Domain-shaped UX** — screens organized around the user's mental model.
|
|
- **Independent deployment** — front-end ships on its own cadence.
|
|
- **Targeted access control** — public/partner-facing routes without exposing the admin surface.
|
|
- **Mobile/offline tuning** — bundles tuned for the actual user environment.
|
|
|
|
## Single app, role-based views
|
|
|
|
One application serves multiple user types via role-based routing and conditional UI. All users authenticate through [[directus]]; the SPA receives a JWT, reads role, and renders appropriate navigation/screens. Splitting into multiple apps is only justified when user populations are genuinely disjoint (public site vs. authenticated console) or when bundle size for one audience harms another.
|
|
|
|
## Data access pattern
|
|
|
|
The SPA talks **exclusively** to Directus:
|
|
|
|
- REST/GraphQL via `@directus/sdk`.
|
|
- WebSocket subscriptions via the same SDK.
|
|
- JWT auth managed by the SDK; refresh handled transparently.
|
|
|
|
**Never** talks to the [[processor]], [[tcp-ingestion]], [[redis-streams]], or [[postgres-timescaledb]] directly. This boundary lets the back-end evolve internally and keeps the security model coherent — every request goes through Directus's permission system.
|
|
|
|
## Recommended stack
|
|
|
|
- **Vite + React + TypeScript**
|
|
- **TanStack Router** — better TS support than React Router; optional file-based routing
|
|
- **TanStack Query** — server state, caching, invalidation, optimistic updates
|
|
- **@directus/sdk** — typed access + real-time
|
|
- **MapLibre GL + react-map-gl** — open-source WebGL maps, no token needed
|
|
- **shadcn/ui + Tailwind** — UI primitives
|
|
- **Zustand** — client-only state (filters, UI prefs)
|
|
- **react-hook-form + Zod** — forms and validation
|
|
|
|
Covers the spectrum from form-heavy admin screens to real-time map dashboards without architectural changes between them.
|
|
|
|
## Real-time rendering
|
|
|
|
- **Live maps with many markers**: React reconciler is not the bottleneck — drawing happens in WebGL via MapLibre, which manages features outside React's tree. The React layer manages subscriptions and feeds the map updates.
|
|
- **High-frequency tabular updates** (live leaderboards, event feeds): split components so high-update areas re-render in isolation; use TanStack Query for live data; memoize at component boundaries that receive frequent updates.
|
|
|
|
## Failure mode
|
|
|
|
UI unavailable → back-end unaffected. See [[failure-domains]].
|