Frontend Overview
The VibeXP frontend is a single-page application (SPA) that lives in the
frontend/ directory of
the vibexp/vibexp monorepo. In production
it is embedded into the Go backend and shipped as one combined
artifact/release — a single image serves the SPA and the API.
Tech stack
Section titled “Tech stack”- Vite — build tool and dev server.
- React 19 with TypeScript — UI layer.
- React Router — client-side routing.
Node.js >= 22.22.0 is required (enforced by the engines field in
package.json).
The two external @vibexp/* packages
Section titled “The two external @vibexp/* packages”The frontend consumes two npm packages that are not in this repo. Both are maintained in separate repositories and resolved from the public npm registry:
@vibexp/api-client— a typed API client generated from the backend’sopenapi.yaml. This is how the SPA calls the backend; you do not hand-write fetch calls against the REST API.@vibexp/design-system— the shared UI component library (design tokens, primitives, themed components).
Because both come from npm, the frontend build is fully standalone — no monorepo workspace context and no auth token are needed to build it.
src/ layout
Section titled “src/ layout”frontend/src/├── pages/ Route-level views (one per screen)├── components/ Reusable presentational components (layout/ holds the app header and its global project selector)├── features/ Feature modules (domain-grouped UI + logic)├── hooks/ Custom React hooks├── contexts/ React context providers (auth, theme, …)├── services/ API calls and side-effecting integrations├── lib/ Third-party wiring and shared setup├── utils/ Pure helpers and small utilities├── config/ App-level configuration├── constants/ Shared constants├── styles/ Global styles├── types/ Shared TypeScript types└── routes.tsx The route tableNotable UI surfaces
Section titled “Notable UI surfaces”- Instance-admin portal: the
/adminroutes behind aRequireInstanceAdminroute guard (routes.tsx), in their own shell (pages/admin/): a metrics dashboard plus users (filtering, suspension, guarded delete), teams, and projects management. - Metadata editor:
MetadataEditor(components/metadata/) for editable key-value metadata on Blueprint, Artifact, and Memory forms. - Resource comments:
components/comments/, a detail-page sidebar panel, an all-comments dialog, and a “Recent comments” card on the homepage. - Role management: controls in the team members page, gated by
can('member.role.update'). - Team information architecture: team pages live at top-level
/teams/**(pages/teams/TeamRoutes.tsx) with team-scoped settings under/teams/:id/settings/*(GitHub App, search ranking, email provider, model and embedding providers);/settingsis personal settings only. - Metadata filter:
MetadataFilter(components/metadata/), a key/value popover with value typeahead, on the Blueprint, Artifact, and Memory list pages. - Copyable invitation link:
components/invitations/.
How it talks to the backend
Section titled “How it talks to the backend”In production the frontend and the API share one origin: the backend serves
the embedded SPA and the API from the same port, so the image is built with a
relative API base URL (VITE_API_BASE_URL=/api/v1) and all requests are
same-origin. Deploy-time values (branding, MCP endpoint, analytics) are not
baked into the bundle either — the backend renders them at runtime as
/config.js (window.__VIBEXP_ENV__), loaded before the SPA bundle.
In local development the two run as separate processes: the Vite dev server on
:5173, the backend on :8080, and the SPA calls the backend directly —
the .env.example default is VITE_API_BASE_URL=http://localhost:8080/api/v1.
There is no backend-rendered /config.js in dev; the app falls back to the
build-time import.meta.env values.
See Frontend Configuration for the build-time vs runtime split, and Building & Serving for how the SPA is embedded and served.
Authentication flow (high level)
Section titled “Authentication flow (high level)”Authentication is handled by the backend’s provider registry (Google,
GitHub, generic OIDC — auth.providers in the backend config); the frontend
never holds OAuth secrets.
- The sign-in page fetches
GET /api/v1/auth/providersand renders a provider picker from whatever this deployment has enabled (src/services/authService.ts). - Picking a provider asks the backend for the identity-provider login URL
(
/auth/login?provider=…) and redirects the browser there. The backend completes the OAuth flow and returns to the SPA’s/auth/callbackroute. - The session is carried in an httpOnly session cookie set by the backend —
it is not readable by JavaScript, and is sent automatically on same-origin
/api/v1requests.
The SPA also hosts the OAuth consent page (/oauth/consent,
src/pages/auth/OAuthConsentPage.tsx) for the backend’s embedded MCP
Authorization Server: it gates on an app login (redirecting signed-out users to
/login with a return_to back to the same consent URL), then posts the
approve/deny decision.
Local dev loop
Section titled “Local dev loop”Local development uses the root Makefile, not Docker:
make frontend-run-devThis bootstraps frontend/.env via scripts/sync-env.sh frontend (copies
.env.example if .env is missing, and appends any newly-introduced keys after
a pull), installs dependencies if needed, and starts the Vite dev server at
http://localhost:5173.
Key checks
Section titled “Key checks”Run these before committing (CI runs the same targets):
make frontend-install # install dependenciesmake frontend-lint # eslintmake frontend-type-check # tscmake frontend-test # testsmake frontend-build # production build- Frontend Configuration — the full
VITE_*/ runtime/config.jsreference. - Building & Serving — the combined Docker image and how the backend embeds and serves the SPA.