Frontend application for Insight — a decision intelligence platform for engineering analytics, productivity insights, bottleneck detection, AI adoption tracking, and team health visibility.
Built with HAI3 framework as a single-page application. Uses mock API layer for development; switches to real backend automatically in production.
- Insight monorepo (backend, infra, Helm charts)
- Insight spec (connector specs, API contracts)
| Layer | Technology |
|---|---|
| Framework | HAI3 (React 19 + Redux + event-driven architecture) |
| Build | Vite 6 |
| Language | TypeScript 5 (strict) |
| Styling | Tailwind CSS 3 + HAI3 UIKit (Radix primitives) |
| Charts | Recharts 3 |
| Auth | OIDC via oidc-client-ts (Okta, Authentik, any OIDC provider) |
| Linting | ESLint + custom architecture rules |
| Package manager | npm 11 |
| Node | >= 25.1.0 (see .nvmrc) |
- Node.js >= 25.1.0 (
nvm usewill pick up.nvmrc) - npm >= 11.6.0
- Docker (for container builds)
- Chrome (for browser-based dev tools via MCP)
git clone https://github.com/cyberfabric/insight-front.git
cd insight-front
npm install
npm run devOpen http://localhost:5173. HAI3 Studio panel (bottom-right) controls screenset, theme, and language.
Mocks are OFF by default — npm run dev talks to whatever your Vite proxy is pointed at (/api/* → http://localhost:8080 by default, i.e. the real backend gateway port-forwarded from k8s).
To opt in to synthetic data for a demo / offline session, copy .env.example to .env.local and set:
VITE_ENABLE_MOCKS=true
Restart npm run dev. A yellow warning strip renders at the top of the page whenever mocks are active so you cannot mistake synthetic values for real ones. Prod builds (npm run build) drop the flag's branch entirely — there is no way for fake analytics data to leak into a deployed bundle.
| Script | Description |
|---|---|
npm run dev |
Start Vite dev server with HMR |
npm run build |
Production build (generate colors + Vite) |
npm run preview |
Serve production build locally |
npm run type-check |
TypeScript strict check (tsc --noEmit) |
npm run lint |
ESLint with zero warnings policy |
npm run arch:check |
Architecture compliance (type-check + lint + dependency rules) |
npm run arch:deps |
Dependency graph validation via dependency-cruiser |
src/
app/ # Application shell (shared across screensets)
auth/ # OIDC manager, withAuth HOC, startUrl capture
api/ # App-level API services (Auth, Identity, Accounts)
layout/ # Layout component (sidebar, mobile nav)
plugins/ # REST plugins (AuthPlugin — token injection)
slices/ # App-level Redux slices (auth state)
effects/ # App-level effects (auth lifecycle)
events/ # App-level events (bootstrap, auth)
themes/ # Theme definitions (default, dark, light, dracula)
main.tsx # Entry point — HAI3 app init, theme registration
App.tsx # Root component — Layout + AppRouter + StudioOverlay
screensets/
insight/ # Main product screenset
screens/
executive-view/ # Org-level KPIs, team health radar, metrics table
team-view/ # Per-team member table, bullet sections, drill modals
ic-dashboard/ # Individual contributor dashboard (KPIs, charts, AI tools)
dashboard/ # Legacy dashboard (dev)
speed/ # Speed gauge (dev)
api/ # InsightApiService + ConnectorManager + IdentityResolution
api/mocks/ # Mock data fixtures (team members, IC data, drills)
slices/ # Redux state per domain (executive, team, IC, period)
actions/ # Flux actions (emit events, call API services)
effects/ # Event listeners → slice updates
events/ # Typed event enums per domain
uikit/ # Screenset-local UI components (base + composite)
i18n/ # 36 language files (screenset-level)
auth/ # OIDC callback screenset
screens/callback/ # Handles /callback route after OIDC redirect
All state flows through: Component -> Action -> Event -> Effect -> Slice -> Store
- Actions — pure functions that emit events and call API services. No
getState, no direct dispatch. - Effects — subscribe to events, update only their own slice. Registered via
registerSlice(slice, initEffects). - Events — past-tense named, scoped to
screensetId/domainId/eventName. Type-safe payloads via module augmentation.
Each service extends BaseApiService, self-registers via apiRegistry.register(), and conditionally registers a RestMockPlugin when VITE_ENABLE_MOCKS=true (see src/app/config/mocksEnabled.ts — the single gate consulted by every service). Mock modules are import()ed lazily, so prod builds tree-shake the entire mocks subtree and the bundle never includes synthetic fixtures.
| Screen | Path | Description |
|---|---|---|
| Executive View | /executive-view |
Org KPIs, team health radar, team metrics table |
| Team View | /team-view |
Per-team member metrics, bullet sections, drills |
| IC Dashboard | /ic-dashboard |
Individual contributor KPIs, LOC charts, delivery trends |
| My Dashboard | /my-dashboard |
Same as IC Dashboard, scoped to current user |
The app uses OpenID Connect (Authorization Code + PKCE) for authentication.
main.tsx— captures start URL, initializesOidcManagerwithAuthHOC — wraps protected screens, redirects to OIDC provider if no session/callbackscreen — exchanges authorization code for tokensAuthPlugin— injectsBearertoken into all API requestsauthEffects— listens for token/expiry events, updatesauthSlice
OIDC config is provided at runtime (not build time) via environment variables:
| Variable | Description | Example |
|---|---|---|
OIDC_ISSUER |
OIDC provider issuer URL | https://auth.example.com/application/o/insight/ |
OIDC_CLIENT_ID |
OAuth2 client ID (public client) | C6YjC67CCDBUMygEeoBIlSX3mhRkNpCPxQxa2zaT |
The Docker entrypoint injects these into index.html as window.__OIDC_CONFIG__ at container start. Without these variables, the app falls back to empty config (OIDC disabled).
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 \
insight-frontend:local- Create a GitHub Personal Access Token (classic) with
write:packagesscope - If the repo is in an org, authorize the token for SSO (Settings → Developer settings → PAT → Configure SSO)
- Log in to GHCR:
echo "YOUR_TOKEN" | docker login ghcr.io -u YOUR_USERNAME --password-stdin
./scripts/ghcr-push.sh # pushes as :latest
./scripts/ghcr-push.sh 0.1.0 # pushes as :0.1.0Image: ghcr.io/cyberfabric/insight-front
docker pull ghcr.io/cyberfabric/insight-front:latestFor a self-contained demo with no backend, build with mocks enabled:
VITE_ENABLE_MOCKS=true npm run build
docker run -d -p 8080:80 insight-frontend:localAll screens render synthetic data and the yellow "MOCK DATA" strip stays
visible at the top of every page. Without VITE_ENABLE_MOCKS=true, builds
drop the mock plugins entirely and the UI tries to talk to a real backend.
# Copy and edit env vars
cp docker-compose.yml docker-compose.override.yml
# Edit OIDC_ISSUER and OIDC_CLIENT_ID in the override
docker compose up -d --buildOpen http://localhost:8080.
From 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)Frontend is available at http://localhost:8000. Helm chart supports OIDC config via --set oidc.issuer=... --set oidc.clientId=....
This project uses HAI3 development guidelines. Before making changes:
- Read
.ai/GUIDELINES.md— routing table, import rules, type rules, blocklist - Route to the correct target file (SCREENSETS.md, EVENTS.md, API.md, STYLING.md)
- Run checks before submitting:
npm run type-check # TypeScript
npm run lint # ESLint (zero warnings)
npm run arch:check # Full architecture compliance- Event-driven only — no direct dispatch, no prop drilling
- Self-registration — services, screensets, slices register themselves
- No
any— noas unknown as, noeslint-disable - No inline styles outside
uikit/base/— use theme tokens - lodash for non-trivial array/object operations
- Constants/enums for all string IDs
The project supports AI-assisted workflows via HAI3 CLI:
| Command | Description |
|---|---|
/hai3-new-screenset |
Scaffold a new screenset |
/hai3-new-screen |
Add a screen to existing screenset |
/hai3-validate |
Run architecture validation |
/hai3-quick-ref |
Common patterns reference |
/hai3-rules |
Show guidelines for a topic |
This repo ships with Cypilot v3.7.0-beta for artifact traceability and validation. Usage and workflows are covered by the upstream project README — this section only covers what you need to set it up locally.
- Python 3.11+
- pipx for the global CLI
gh(optional — needed by kit workflowspr-review/pr-status)- Clone cyberfabric/insight at
../insight—cypilot/config/core.tomldeclares a workspace source that resolves cross-repo artifacts from the backend monorepo; without it, workspace-scoped validation skips that source.
Install the CLI globally:
pipx install git+https://github.com/cyberfabric/cyber-pilot.git
cpt --version # cypilot-proxy 3.7.0b0 or newer
cpt info # should list InsightFront system + SDLC kit v1.3.0When a new release comes out:
pipx upgrade cypilot # upgrade the global CLI
cpt init --force --yes # refresh cypilot/.core and cypilot/.gen
cpt generate-agents -y # regenerate host integrations (.claude, .cursor, …)
cpt validate --local-only # smoke testDo a git diff before committing — cpt init --force:
- Overwrites
cypilot/config/artifacts.tomlto an empty template. Restore withgit restore cypilot/config/artifacts.tomland re-apply any local additions. - Rewrites
cypilot/config/core.tomlin the new expanded format and drops the[workspace]section. Merge the workspace block back by hand. - Leaves a backup at
cypilot.<timestamp>.backup/(gitignored). Delete once the diff is clean.
cpt validate --local-onlyreports 46 errors of kindid-system-unrecognized: artifact IDs use prefixes likecpt-auth-*,cpt-layout-*,cpt-*-view-*while onlyinsightfrontis registered inartifacts.toml. Tracked separately; not blocking.
Built-in themes: Default, Light, Dark, Dracula, Dracula Large.
Switch via HAI3 Studio panel or programmatically:
app.themeRegistry.apply(DARK_THEME_ID);36 languages supported. Two-tier system:
- Screenset-level — shared keys (menu labels, common terms)
- Screen-level — screen-specific translations
Translations use I18nRegistry.createLoader with lazy-loaded JSON files per language.