ADR-0009: Web frontend as a React/Vite app (apps/web)
Status: AcceptedDate: 2026-06-07Owner: @satyaSupersedes: (none)Superseded-by:(none)Context
Section titled “Context”Treeper is mobile-only at v0 (ADR-0001); PRODUCT.md lists “desktop / web app” as out of scope for v0. Separately, TripViz — a polished React/Vite map UI (animated MapLibre map, swipeable day cards, media carousels, multi-trip compare, color-coded trips) — already exists and reimplemented, more crudely, much of what treeper’s backend + workers already do (reel/PDF parsing, geocoding, itinerary search, media enrichment). We want a web surface for treeper without rebuilding the UI, and without forking the data model.
Decision
Section titled “Decision”Adopt TripViz as treeper’s web frontend, brought into the monorepo as apps/web
(Vite + React + TypeScript), authenticating via Supabase and talking only to the existing
NestJS API (/v1) — never to the workers directly (ADR-0002/0003 boundaries hold). It
adopts treeper’s data model natively (trip → destinations/days → activities); TripViz’s
standalone schema and its throwaway Express server are dropped. Shared types live in a new
packages/contracts consumed by apps/web (the backend may adopt it later).
Alternatives considered
Section titled “Alternatives considered”| Option | Why not |
|---|---|
| Keep TripViz standalone, call treeper APIs over HTTP from a separate repo | Looser cohesion, duplicated deploy/auth/types; not a true “v2 of treeper”. |
| Build a fresh web app from scratch on treeper’s model | Throws away TripViz’s mature, distinctive map/compare UI for no benefit. |
Adapter layer (keep TripViz’s Trip/Spot schema, translate at the edge) | Two models to maintain; native adoption keeps one source of truth (the backend). |
| Next.js instead of Vite SPA | No SSR/SEO need for an authed app; Vite reuses TripViz as-is and ships static for Coolify. |
Consequences
Section titled “Consequences”Positive
Section titled “Positive”- A capable web client with zero new backend AI/scraping code — reuses NestJS + workers.
- One data model (the backend’s);
packages/contractsstarts the long-planned shared-types layer. - TripViz’s map/carousel/compare UX becomes a treeper differentiator on the web.
Negative / risks
Section titled “Negative / risks”- CORS must be enabled on the backend (done, gated by
CORS_ORIGINS). apps/webis a self-contained npm app (no JS workspace root yet);packages/contractsis shared via a tsconfig/vite path alias rather than a workspace dependency.- Activities carry no route geometry and some lack coords — the web renders an order-curve and skips null-coord activities on the map (still lists them in cards).
Follow-ups
Section titled “Follow-ups”- Extract more of the backend’s DTOs into
packages/contracts; have the backend consume it. - Consider code-splitting the MapLibre chunk.
- Deploy
apps/webon Coolify (app.itssatya.in) alongside backend/workers.