This is the application frontend for dev-health-ops.
- Node.js 18+ (recommended: 20+)
- npm, yarn, pnpm, or bun
- Install dependencies:
npm install- Start ClickHouse (from
dev-health-ops):
dev-hops grafana up- Run the API:
dev-hops api --db "clickhouse://localhost:8123/default" --reload- Run the web app:
BACKEND_URL="http://127.0.0.1:8000" npm run devOpen http://localhost:3000 with your browser.
First checkout? The GraphQL schema file (
src/lib/graphql/schema.graphql) is exported from thedev-health-opsbackend and is not generated locally. If it is missing,npm run codegenwill fail. To obtain it, start the backend API and run:PYTHONPATH=../dev-health-ops/src python3 -m dev_health_ops.api.graphql.export_schema --out src/lib/graphql/schema.graphql npm run codegenSee Schema Contract Enforcement for details.
You can run the frontend with sample data (no backend required):
npm install
npm run devThis will serve the app at http://localhost:3000 using static sample data.
| Variable | Required | Purpose | Default / Notes |
|---|---|---|---|
BACKEND_URL |
No | Backend API base URL | http://127.0.0.1:8000 |
AUTH_SECRET |
Prod: Yes, Dev: No | Auth.js signing/encryption secret | Falls back to a dev-only in-code value |
LINEAR_API_KEY |
Optional feature | Enables POST /api/feedback Linear issue creation |
Must be set with LINEAR_TEAM_ID; route returns 503 if missing |
LINEAR_TEAM_ID |
Optional feature | Linear team target for feedback issues | Must be set with LINEAR_API_KEY |
NEXT_PUBLIC_USE_GRAPHQL_ANALYTICS |
No | GraphQL analytics toggle (default: enabled). GraphQL is the default data layer; set to false to fall back to REST. |
true |
USE_GRAPHQL_ANALYTICS |
No | Server-side runtime fallback for GraphQL toggle | Used when the public flag is absent |
NEXT_PUBLIC_DOCS_URL |
No | Docs/help link URL in UI | /docs |
NEXT_PUBLIC_DEV_HEALTH_TEST_MODE |
No | Use sample data in test/demo paths | false |
NEXT_PUBLIC_DEMO_MODE |
No | Show demo-only UI tabs and sample-data panels (e.g., Code Hotspots, Investment Expense in the Flow view). Backed by static data, not live APIs | false |
DEMO_EXPORT |
No | Enable static export build mode | false |
BASE_PATH |
No | Subpath hosting prefix (example: /app) |
Empty (root) |
NEXT_PUBLIC_SENTRY_DSN |
No | Sentry DSN for client + server + edge error reporting | Empty (Sentry still initializes but events go nowhere) |
NEXT_PUBLIC_SENTRY_REPLAY_ROUTES |
No | Comma-separated path prefixes that activate Sentry Session Replay. Replay is lazy-loaded on-demand so it stays out of the initial client bundle on non-matching routes. Set to an empty string to disable Replay entirely | /admin,/superadmin |
ACR_API_ORIGIN |
ACR runtime | Fixed HTTP(S) origin for server-to-server ACR reads; private service traffic normally uses HTTP and externally exposed traffic terminates TLS at the edge | Must be an HTTP(S) origin without a path or query |
ACR_WEB_ASSERTION_KEY_FILE |
ACR runtime | Path to the server-only Ed25519 assertion private key | Regular mode-0600 file; never a NEXT_PUBLIC_* variable |
ACR_WEB_ASSERTION_KID |
ACR runtime | JWKS key ID for signed web assertions | Must match the ACR JWKS configuration |
ACR_WEB_ASSERTION_ISSUER |
ACR runtime | Fixed web assertion issuer | Must match ACR configuration |
ACR_WEB_ASSERTION_AUDIENCE |
ACR runtime | Fixed web assertion audience | Must match ACR configuration |
ACR_REQUEST_TIMEOUT_MS |
No | Bound for each server-to-server ACR request | 5000, minimum 100, maximum 30000 |
Deprecated (still read for compatibility):
NEXTAUTH_SECRET-> useAUTH_SECRET.
Copy .env.example to .env.local and configure as needed.
| Script | Description |
|---|---|
npm run dev |
Start development server |
npm run build |
Build for production |
npm run start |
Start production server |
npm run lint |
Run ESLint |
npm run typecheck |
Run TypeScript checks |
npm run test:unit |
Run unit tests (Vitest) |
npm run test:e2e |
Run e2e tests (Playwright) |
npm run test:e2e:live |
Run live-backend e2e smoke tests (Playwright) |
npm run test:ci |
Run CI gates (lint, typecheck, build, unit, e2e) |
Use the runner-agnostic entrypoint:
bash ci/run_tests.sh <unit|e2e|live-e2e|ci>Examples:
# Local quick checks
bash ci/run_tests.sh unit
bash ci/run_tests.sh e2e
bash ci/run_tests.sh live-e2e
# Full CI-equivalent gate locally
npm run test:ciUse this tier when validating against a real dev-health-ops backend (no mock server).
Requirements:
- A running
dev-health-opsAPI with healthy/healthand seeded data (fixtures recommended). PLAYWRIGHT_LIVE_BACKEND_URLpointing at that API (defaults toBACKEND_URL, thenhttp://127.0.0.1:8000).
Test suites in tests/live/:
journey.spec.ts— 10 API-level tests: registration, login, onboarding, credentials CRUD, sync config CRUD. Self-bootstrapping (creates users via POST /register).onboarding-ui.spec.ts— 3 browser-level tests: signup form, login→onboard redirect, onboard→dashboard.impersonation.spec.ts— superuser impersonation flows (requiresTEST_SUPERUSER_*env vars).backend-api.spec.ts/pages.spec.ts— API health and page-level smoke tests.
Shared utilities in tests/live/helpers.ts: testEmail(), registerUser(), loginUser(), authHeaders().
Example:
PLAYWRIGHT_LIVE_BACKEND_URL="http://127.0.0.1:8000" bash ci/run_tests.sh live-e2eIn GitHub Actions, the live-e2e.yml workflow starts a real dev-health-ops API, runs Alembic migrations, seeds fixtures, and validates GraphQL schema drift before executing tests.
Component tests run under the Vitest components project (jsdom environment). Files live alongside components at src/components/**/*.test.tsx.
npm run test:unit # runs both unit and component Vitest projectsKey patterns:
src/test/utils.tsxprovidesrenderWithToaster()for components that emit toasts.- Server actions (
"use server") are mocked at module level viavi.mock(). - Common mocks:
next/navigation,next-auth/react,global.fetch.
The live-e2e.yml CI workflow includes a GraphQL schema drift detection step that exports the backend Strawberry schema and diffs it against src/lib/graphql/schema.graphql. If the schemas diverge:
- Start the
dev-health-opsAPI locally. - Re-export:
PYTHONPATH=../dev-health-ops/src python3 -m dev_health_ops.api.graphql.export_schema --out src/lib/graphql/schema.graphql - Regenerate types:
npm run codegen - Commit
schema.graphql+__generated__/together.
MSW mock handlers in tests/mocks/handlers.ts are typed with interfaces from tests/mocks/types.ts and generated GraphQL types, so TypeScript catches response shape mismatches at compile time.
- CI runs with Playwright retries enabled (
retries=2whenCI=true). - Failure artifacts are always retained: video (
video: retain-on-failure) and screenshots (screenshot: only-on-failure). The default E2E suite retains traces only on failure; Context Fabric persists traces on successful CI runs and writes named 1280/768/375 screenshots. - Every suite writes its JUnit output beneath
test-results/playwright/<suite>/junit.xml. - Every suite writes its HTML report beneath
test-results/playwright-html/<suite>/; CI uploads both roots, while certificates and auth state remain outside them. ci/run_tests.sh e2eclears and recreates artifact directories before each run and prints diagnostic context (Node/npm/Playwright versions + artifact paths).
These paths can be overridden with:
PLAYWRIGHT_REPORT_DIR=<dir> PLAYWRIGHT_RESULTS_DIR=<dir> bash ci/run_tests.sh e2edocs/visualizations.md— Chart selection guide (heatmaps, quadrants, flame diagrams)docs/graphql-client.md— urql GraphQL client usagedocs/graphql-investment.md— Investment View GraphQL APIdocs/hosting.md— Demo exports, GitHub Pages, CDN hostingdocs/migration-guide.md— REST to GraphQL migration
- Framework: Next.js 16+ with App Router
- Components: React Server Components + Client Components
- Styling: Tailwind CSS v4
- Data: urql GraphQL client (default), REST fallback, static sample data for demos
- Testing: Vitest (unit + component), Playwright (E2E + live backend), MSW v2 (API mocking)
