Frontend application for Insight — a decision intelligence platform for engineering analytics, productivity insights, bottleneck detection, AI adoption tracking, and team health visibility.
Single-page application built on React 19 + TanStack Router + TanStack Query + shadcn/ui. Uses MSW for offline / demo mocking; talks to the Insight backend in production.
- Insight monorepo (backend, infra, Helm charts)
- Insight spec (connector specs, API contracts)
| Layer | Technology |
|---|---|
| Routing | TanStack Router (file-based, auto-generated route tree) |
| Data | TanStack Query (per-query hooks under src/queries/) |
| Build | Vite 8 |
| Language | TypeScript 6 (strict) |
| Styling | Tailwind CSS 4 + shadcn/ui (base-vega style, CSS variables) |
| Charts | Recharts 3 |
| Auth | OIDC via oidc-client-ts (Authorization Code + PKCE) |
| i18n | i18next + react-i18next (English only today) |
| Mocks | MSW (Mock Service Worker) |
| Linting | ESLint (flat config) |
| Package manager | pnpm 10 |
| Node | 24 (see .nvmrc) |
- Node.js 24 (
nvm usepicks up.nvmrc) - pnpm 10+
- Docker (for container builds)
git clone https://github.com/constructorfabric/insight-front.git
cd insight-front
pnpm install
pnpm devOpen http://localhost:5173.
Mocks are OFF by default — pnpm dev talks to the Vite proxy (see VITE_API_PROXY_TARGET).
To enable synthetic data for an offline / demo session, copy .env.example to .env.local and set:
VITE_ENABLE_MOCKS=true
VITE_DEV_USER_EMAIL=bob.park@example.com
A yellow warning strip renders at the top of the page whenever mocks are active so synthetic values cannot be mistaken for real ones. Set VITE_HIDE_MOCK_BANNER=true to hide the strip during screenshots — mocks remain active. Prod builds (pnpm build) drop the mock subtree entirely.
Seeded mock people: bob.park@example.com, carol.chen@example.com, alice.kim@example.com, frank.moss@example.com (see src/mocks/registry.ts).
| Script | Description |
|---|---|
pnpm dev |
Start Vite dev server |
pnpm build |
Production build (tsc -b && vite build) |
pnpm preview |
Serve production build locally |
pnpm typecheck |
TypeScript strict check (tsc --noEmit) |
pnpm lint |
ESLint (zero warnings) |
pnpm format |
Prettier write |
src/
auth/ # OIDC manager singleton, useAuth hook, start-url capture
api/ # Fetch clients (analytics, identity, accounts) + fetchWithAuth wrapper
queries/ # React Query hooks per screen (ic-dashboard, team-view, executive-view)
routes/ # TanStack Router file-based routes (auto-discovered)
routeTree.gen.ts # ← auto-generated, do not edit
screens/ # Page components composed by routes
components/
ui/ # shadcn/ui primitives (button, card, dialog, alert, …)
widgets/ # Feature widgets (metric-card, bullet-chart, drill-modal, …)
app-sidebar.tsx # Org-tree sidebar (recursive nav)
theme-provider.tsx # Light/dark/system theme (localStorage-backed)
mock-banner.tsx # Warning strip when mocks are on
app-error-boundary.tsx
error-fallback.tsx
hooks/ # Shared hooks (use-period, use-mobile)
lib/ # Domain helpers (format, status, scoring, peers, …)
mocks/ # MSW handlers, factories, registry (dev-only, tree-shaken in prod)
locales/en/ # i18next translation files
i18n/ # i18next setup
types/ # Shared TypeScript types
index.css # Tailwind v4 inline config + theme tokens (light + dark)
main.tsx # Entry: storeStartUrl → enableMocking → OidcManager.init → render
router.ts # createRouter(routeTree)
Authorization Code + PKCE via oidc-client-ts. The OIDC issuer/client are not baked into the build — they're injected at container start.
- src/main.tsx calls
storeStartUrl()(captures the full URL with any?code=…&state=…before the router strips it), thenOidcManager.init()readswindow.__OIDC_CONFIG__and restores a session fromsessionStorageif one exists. - Root route's
beforeLoad(src/routes/__root.tsx) inspectsauthStore.authenticated→ render;idle/expired→OidcManager.signIn()(redirects to the IdP)./callbackis whitelisted. - src/routes/callback.tsx calls
OidcManager.handleCallback(startUrl)to exchange the code for tokens, thenwindow.location.replace(state.returnUrl). - src/api/fetch-with-auth.ts injects
Authorization: Bearer <token>on every request.X-Tenant-IDis reserved for future use (current backend doesn't require it); whenauthStore.tenantIdis populated by something downstream, the header fires automatically. On 401, it callsOidcManager.refresh()once and retries — concurrent in-flight refreshes are deduplicated insideOidcManager.refresh(). - Viewer identity is sourced directly from JWT claims via
oidc-client-ts(user.profile.email/user.profile.sub) — no extra/api/accounts/user/currentround-trip. The auth module'suseViewer()hook is the single source of truth: it prefers the OIDC-authenticated user's email and falls back toVITE_DEV_USER_EMAILin dev.
When window.__OIDC_CONFIG__ is absent (typical for local dev) and import.meta.env.DEV is true, OidcManager.init() sets status to authenticated and resolves with no user. Combine with VITE_DEV_USER_EMAIL to impersonate a person from the identity service.
The container's docker-entrypoint.sh writes /oidc-config.js from env vars and injects a <script src="/oidc-config.js"> tag into index.html. The script sets window.__OIDC_CONFIG__ = { issuer_url, client_id, scopes }.
| Variable | Description | Example |
|---|---|---|
OIDC_ISSUER |
OIDC issuer URL | https://auth.example.com/application/o/insight/ |
OIDC_CLIENT_ID |
OAuth2 public client ID | C6YjC67CCDBUMygEeoBIlSX3mhRkNpCPxQxa2zaT |
OIDC_SCOPES |
Space-separated scopes | openid profile email api://insight/Access.Default |
Build-time (Vite, .env.local):
| Variable | Description |
|---|---|
VITE_ENABLE_MOCKS |
"true" to enable MSW (dev only; stripped from prod). |
VITE_HIDE_MOCK_BANNER |
"true" to hide the warning strip while mocks are on (for screenshots). |
VITE_DEV_USER_EMAIL |
Impersonate a person by email when no OIDC session is present. |
VITE_API_PROXY_TARGET |
Dev-only /api proxy target (e.g. http://localhost:8080). |
VITE_API_BASE |
Override analytics API base URL (default /api/analytics/v1). |
VITE_IDENTITY_BASE |
Override identity API base URL (default /api/identity/v1). |
VITE_ACCOUNTS_BASE |
Override accounts API base URL (default /api/accounts). |
Runtime (container only, no VITE_ prefix): OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_SCOPES.
| Path | Screen | Notes |
|---|---|---|
/ |
IC dashboard (or impersonation prompt) | Resolves viewer via OIDC user or VITE_DEV_USER_EMAIL. |
/ic/$person |
(redirects to /ic/$person/personal) |
|
/ic/$person/personal |
IC dashboard | Branches on viewer department (engineering vs sales). |
/ic/$person/team |
Team view | Members table, bullet sections, drill modals. |
/ic/$person/exec |
Executive view | Org KPIs, health radar, teams table. |
/callback |
OIDC callback handler | Exchanges code for tokens, redirects to original URL. |
light / dark / system. Theme tokens are CSS variables defined in src/index.css; use the semantic Tailwind utilities (bg-background, text-muted-foreground, border-border, text-destructive, bg-warning/10, etc.). The shadcn theme is base-vega with cssVariables: true (see components.json).
i18next + react-i18next. English-only today (supportedLngs: ["en"]). Translations live in src/locales/en/translation.json; component code uses const { t } = useTranslation() + t("key").
docker build -t insight-frontend:local .docker run -d -p 8080:80 \
-e OIDC_ISSUER=https://auth.example.com/application/o/insight/ \
-e OIDC_CLIENT_ID=your-client-id \
-e OIDC_SCOPES="openid profile email" \
insight-frontend:localVITE_ENABLE_MOCKS=true pnpm build
docker run -d -p 8080:80 insight-frontend:localAll screens render synthetic data and the warning strip stays visible.
cp docker-compose.yml docker-compose.override.yml
# Edit OIDC_ISSUER / OIDC_CLIENT_ID / OIDC_SCOPES in the override
docker compose up -d --buildFrom the insight monorepo:
./up.sh frontend # builds image + deploys to Kind via Helm
./up.sh app # backend + frontend together
./up.sh # full stack (ingestion + backend + frontend)Helm chart supports OIDC config via --set oidc.issuer=… --set oidc.clientId=… --set oidc.scopes=….