@nzila/sdk 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -67,4 +67,15 @@ const nzila = traceNzilaFeature("Checkout");
67
67
  await nzila.runApi("charge", () => charge());
68
68
  ```
69
69
 
70
- See JSDoc on each export in `src/` and the monorepo guide [examples/COMPLEX-USAGE.md](../../examples/COMPLEX-USAGE.md).
70
+ ## Examples (included in this package)
71
+
72
+ After install, open **`node_modules/@nzila/sdk/examples/`**:
73
+
74
+ - **[INDEX.md](./examples/INDEX.md)** — map of all samples
75
+ - **[COMPLEX-USAGE.md](./examples/COMPLEX-USAGE.md)** — every feature (Vitest, runtime, `mapFeature`, webhooks)
76
+ - **[RUNTIME-TRACE.md](./examples/RUNTIME-TRACE.md)** — React + backend live tracing
77
+ - **[TRACING-FAILURES.md](./examples/TRACING-FAILURES.md)** — tests → dashboard
78
+ - Config: `vitest.config.example.ts`, `jest.config.example.cjs`, `mocharc.nzila.example.cjs`
79
+ - Code: `backend/`, `frontend/`, `complex/`, `react/checkout-feature.example.tsx`
80
+
81
+ All example imports use `@nzila/sdk` (same as your app).
@@ -0,0 +1,113 @@
1
+ # Complex usage — all Nzila SDK features
2
+
3
+ This guide ties together **test webhooks**, **runtime signals**, **mapFeature**, and **manual error reporting** in one flow. Use it after the quick starts in [README.md](README.md), [TRACING-FAILURES.md](TRACING-FAILURES.md), and [RUNTIME-TRACE.md](RUNTIME-TRACE.md).
4
+
5
+ ## Feature matrix
6
+
7
+ | Capability | API | When to use |
8
+ |------------|-----|-------------|
9
+ | CI test run | `NzilaVitestReporter` / `NzilaJestReporter` / Mocha | Every `vitest run` / Jest / Mocha finish |
10
+ | Manual run POST | `sendNzilaRun(payload, { webhookUrl, apiKey })` | Custom runners, replay payloads |
11
+ | Feature naming | `mapFeature(describePath, testName)` | Suite title ≠ dashboard feature |
12
+ | Backend handler | `traceNzilaFeature("Checkout")` | First line of route/service |
13
+ | React screen | `useNzilaFeature("Checkout")` | Top of component matching tests |
14
+ | HTTP wrapper | `nzila.runApi("label", () => fetch…)` | Auto `api` success/failure |
15
+ | Handled errors | `nzila.captureError(err, { … })` | `catch`, validation, business rules |
16
+ | No handle in scope | `reportFeatureError("Checkout", err)` | Deep helper, fire-and-forget |
17
+ | API failure label | `nzila.captureApiError(err, "payment.charge")` | After failed call outside `runApi` |
18
+ | UI issues | `nzila.reportUi("custom_banner", { … })` | Non-throwing UX problems |
19
+ | Render errors | `NzilaFeatureBoundary` + `useNzilaFeature` | Child tree throws |
20
+ | Static demo payload | `shared/send-webhook.mjs` | No Vitest installed |
21
+
22
+ Use the **same feature strings** everywhere (e.g. `"Checkout"`, `"Inventory"`) so test failures and runtime signals land on one dashboard row.
23
+
24
+ ## 1. Complex Vitest run (multi-feature, pass + fail)
25
+
26
+ **Files:** `complex/full-platform.demo.test.ts`, `vitest.complex.config.ts`, `shared/feature-map.ts`
27
+
28
+ - Three describe roots: `Checkout UI`, `Inventory`, `Authentication`
29
+ - `mapFeature` maps UI vs API names via `resolveFrontendFeature` / `resolveBackendFeature`
30
+ - Several tests **fail on purpose** so Nzila shows failure analysis
31
+
32
+ ```bash
33
+ # .env.local: NZILA_API_KEY, NZILA_WEBHOOK_URL
34
+ # Optional: NZILA_COMPLEX_APP_NAME=checkout-api (must exist in dashboard)
35
+ npm run example:test:complex
36
+ ```
37
+
38
+ Open **Runs** → latest run → failures grouped by feature.
39
+
40
+ ## 2. Complex backend runtime (runApi + capture + reportFeatureError)
41
+
42
+ **File:** `complex/api-services.demo.ts`
43
+
44
+ Demonstrates:
45
+
46
+ 1. `initNzilaRuntime({ signalsUrl, apiKey })`
47
+ 2. `traceNzilaFeature("Checkout")` with `runApi` for inventory + payment
48
+ 3. `captureError` for handled business failure (409)
49
+ 4. `captureApiError` for pipeline failure
50
+ 5. Second feature `Inventory` with `reportFeatureError` in a job
51
+
52
+ ```bash
53
+ npm run example:runtime:complex
54
+ ```
55
+
56
+ Wait ~1s for batched flush, then check **Feature health** / runtime signals for `Checkout` and `Inventory`.
57
+
58
+ ## 3. Tracing-only Vitest (focused failure fingerprints)
59
+
60
+ ```bash
61
+ npm run example:test:tracing:all
62
+ npm run example:webhook:tracing
63
+ npm run example:webhook:tracing:frontend
64
+ ```
65
+
66
+ ## 4. React runtime (monorepo)
67
+
68
+ See [RUNTIME-TRACE.md](RUNTIME-TRACE.md). Pattern:
69
+
70
+ ```tsx
71
+ initNzilaRuntime({ signalsUrl, apiKey });
72
+
73
+ function CheckoutPage() {
74
+ const nzila = useNzilaFeature("Checkout");
75
+ async function pay() {
76
+ try {
77
+ await nzila.runApi("checkout.submit", () =>
78
+ fetch("/api/checkout", { method: "POST" }),
79
+ );
80
+ } catch (e) {
81
+ nzila.captureError(e, { step: "submit" });
82
+ }
83
+ }
84
+ return (
85
+ <NzilaFeatureBoundary feature="Checkout" nzila={nzila}>
86
+ {/* children */}
87
+ </NzilaFeatureBoundary>
88
+ );
89
+ }
90
+ ```
91
+
92
+ ## 5. Jest and Mocha
93
+
94
+ - Jest: copy `jest.config.example.cjs` → wire `NzilaJestReporter` with same env vars as Vitest.
95
+ - Mocha: `mocharc.nzila.example.cjs` — register reporter, call `sendNzilaRun` on `end` if you roll your own.
96
+
97
+ ## 6. End-to-end local checklist
98
+
99
+ 1. `npm run dev` + `npm run worker`
100
+ 2. Create app(s): `checkout-api`, `checkout-web` (or your `NZILA_COMPLEX_APP_NAME`)
101
+ 3. API key in `.env.local`
102
+ 4. `npm run example:test:complex` → webhook run
103
+ 5. `npm run example:runtime:complex` → runtime signals
104
+ 6. Dashboard: **Runs**, **Failures**, **Feature health** — same feature names
105
+
106
+ ## Environment reference
107
+
108
+ | Variable | Used by |
109
+ |----------|---------|
110
+ | `NZILA_API_KEY` | Webhook + runtime |
111
+ | `NZILA_WEBHOOK_URL` | Vitest/Jest reporters, `sendNzilaRun` |
112
+ | `NZILA_SIGNALS_URL` | `initNzilaRuntime` (default `http://localhost:3000/api/signals/runtime`) |
113
+ | `NZILA_COMPLEX_APP_NAME` | Complex Vitest config only |
@@ -0,0 +1,27 @@
1
+ # @nzila/sdk examples
2
+
3
+ These files ship inside the npm package under `node_modules/@nzila/sdk/examples/`.
4
+
5
+ | Topic | Files |
6
+ |-------|--------|
7
+ | Overview | [README from monorepo](./README.md) |
8
+ | All features walkthrough | [COMPLEX-USAGE.md](./COMPLEX-USAGE.md) |
9
+ | Live app tracing | [RUNTIME-TRACE.md](./RUNTIME-TRACE.md) |
10
+ | Test → dashboard mapping | [TRACING-FAILURES.md](./TRACING-FAILURES.md) |
11
+ | Vitest | [vitest.config.example.ts](./vitest.config.example.ts), [complex/](./complex/) |
12
+ | Jest | [jest.config.example.cjs](./jest.config.example.cjs) |
13
+ | Mocha | [mocharc.nzila.example.cjs](./mocharc.nzila.example.cjs) |
14
+ | Backend runtime | [backend/runtime-trace.example.ts](./backend/runtime-trace.example.ts), [complex/api-services.demo.ts](./complex/api-services.demo.ts) |
15
+ | React | [react/checkout-feature.example.tsx](./react/checkout-feature.example.tsx) |
16
+ | Manual webhook | [send-run-manual.mjs](./send-run-manual.mjs), [shared/send-webhook.mjs](./shared/send-webhook.mjs) |
17
+ | Sample payloads | [backend/sample-payload.json](./backend/sample-payload.json), [frontend/sample-payload.json](./frontend/sample-payload.json) |
18
+
19
+ ## Environment
20
+
21
+ ```env
22
+ NZILA_API_KEY=nzl_...
23
+ NZILA_WEBHOOK_URL=https://your-host/api/webhooks/tests
24
+ NZILA_SIGNALS_URL=https://your-host/api/signals/runtime
25
+ ```
26
+
27
+ Imports in these files use `@nzila/sdk` — the same as in your application after `npm install @nzila/sdk`.
@@ -0,0 +1,94 @@
1
+ > **npm:** Start with [INDEX.md](./INDEX.md). Imports use `@nzila/sdk`.
2
+
3
+ # Nzila integration examples
4
+
5
+ End-to-end samples for **backend (API)** and **frontend (UI)** test flows.
6
+
7
+ ## Prerequisites
8
+
9
+ 1. `npm run dev` and `npm run worker` (with `QUEUE_DRIVER` and DB migrated).
10
+ 2. Register, create an API key at `/en/keys`.
11
+ 3. In **`.env.local`**:
12
+
13
+ ```env
14
+ NZILA_API_KEY=nzl_...
15
+ NZILA_WEBHOOK_URL=http://localhost:3000/api/webhooks/tests
16
+ HF_API_TOKEN=hf_... # optional, for AI summaries
17
+ ```
18
+
19
+ The same examples are published inside **`@nzila/sdk`** at `node_modules/@nzila/sdk/examples/` (see `INDEX.md` there).
20
+
21
+ ## Layout
22
+
23
+ | Path | Purpose |
24
+ |------|---------|
25
+ | `backend/` | API-style unit tests (pricing, inventory, auth) |
26
+ | `frontend/` | UI logic tests (checkout form, product card) |
27
+ | `shared/send-webhook.mjs` | POST static JSON payloads (CI / manual) |
28
+ | `vitest.config.ts` | Vitest + Nzila reporter (fires webhook on finish) |
29
+ | `jest.config.example.cjs` | Jest + NzilaJestReporter |
30
+ | `mocharc.nzila.example.cjs` | Mocha reporter setup notes |
31
+ | `@nzila/sdk` | Installed npm package (you are reading its `examples/` folder) |
32
+
33
+ Each suite includes **passing and failing** tests so the dashboard shows real failure analysis.
34
+
35
+ ## Trace failures (tests → dashboard)
36
+
37
+ See **[TRACING-FAILURES.md](TRACING-FAILURES.md)** for how `describe()` paths, fingerprints, and `errors[]` map to **Runs**, **Failures**, and **Feature health**.
38
+
39
+ ## Complex usage (all features)
40
+
41
+ See **[COMPLEX-USAGE.md](COMPLEX-USAGE.md)** for a single walkthrough: multi-feature Vitest, `mapFeature`, runtime `runApi` / `captureError`, Jest/Mocha, and env vars.
42
+
43
+ ```bash
44
+ npm run example:test:complex # Vitest: Checkout UI + Inventory + Auth (pass/fail)
45
+ npm run example:runtime:complex # Backend: traceNzilaFeature + reportFeatureError
46
+ ```
47
+
48
+ ## Runtime trace (live app → Feature health)
49
+
50
+ See **[RUNTIME-TRACE.md](RUNTIME-TRACE.md)** for `useNzilaFeature` (React), `traceNzilaFeature` (backend), and **`captureError` / `reportFeatureError`** when you handle errors yourself.
51
+
52
+ Example backend handler: `backend/runtime-trace.example.ts`. Heavier demo: `complex/api-services.demo.ts`.
53
+
54
+ Quick demo (Vitest only):
55
+
56
+ ```bash
57
+ npm run example:test:tracing # Vitest → webhook
58
+ npm run example:webhook:tracing # static JSON payload
59
+ ```
60
+
61
+ ## Run Vitest (sends one webhook per run)
62
+
63
+ ```bash
64
+ # All examples (mixed app name: nzila-demo)
65
+ npm run example:test
66
+
67
+ # Backend only → app name checkout-api
68
+ npm run example:test:backend
69
+
70
+ # Frontend only → app name checkout-web
71
+ npm run example:test:frontend
72
+ ```
73
+
74
+ ## Send sample payloads (no Vitest)
75
+
76
+ ```bash
77
+ npm run example:webhook:backend
78
+ npm run example:webhook:frontend
79
+ npm run example:webhook # both
80
+ ```
81
+
82
+ ## Full local demo
83
+
84
+ ```bash
85
+ npm run example:all # vitest + both webhooks (needs dev + worker up)
86
+ ```
87
+
88
+ ## Server-side client
89
+
90
+ Use `frontend-webhook-client.ts` from a Route Handler or CI job — not from browser bundles.
91
+
92
+ ## Payload contract
93
+
94
+ See `backend/sample-payload.json`, `frontend/sample-payload.json`, and `src/lib/webhook-schema.ts`.
@@ -0,0 +1,222 @@
1
+ # Runtime feature tracing (`traceNzilaFeature` / `useNzilaFeature`)
2
+
3
+ Pair **Vitest** failures (webhook) with **live** signals on the same **feature** name (e.g. `Checkout`). Call one function at the top of the UI component or backend handler that owns that feature; use **`captureError`** when you already handle errors.
4
+
5
+ ## SDK package exports
6
+
7
+ | Import path | Use for |
8
+ |-------------|---------|
9
+ | `@nzila/sdk` | `initNzilaRuntime`, `traceNzilaFeature`, `reportFeatureError`, Vitest/Jest reporters |
10
+ | `@nzila/sdk/react` | `useNzilaFeature`, `NzilaFeatureBoundary`, `reportFeatureError` |
11
+ | `@nzila/sdk/runtime` | Low-level runtime client only |
12
+ | `@nzila/sdk/vitest` | `NzilaVitestReporter` |
13
+
14
+ ---
15
+
16
+ ## Setup (once per app)
17
+
18
+ ```ts
19
+ import { initNzilaRuntime } from "@nzila/sdk/runtime";
20
+ // or: import { initNzilaRuntime } from "@nzila/sdk";
21
+
22
+ initNzilaRuntime({
23
+ signalsUrl: process.env.NZILA_SIGNALS_URL!, // https://your-app.vercel.app/api/signals/runtime
24
+ apiKey: process.env.NZILA_API_KEY!,
25
+ locale: "en",
26
+ renderLoopThreshold: 40, // optional — React render-loop detection
27
+ });
28
+ ```
29
+
30
+ | Variable | Where |
31
+ |----------|--------|
32
+ | `NZILA_SIGNALS_URL` | Node / Route Handlers |
33
+ | `NEXT_PUBLIC_NZILA_SIGNALS_URL` | Browser (Next.js) |
34
+ | `NZILA_API_KEY` / `NEXT_PUBLIC_NZILA_API_KEY` | Same project key as test webhooks |
35
+
36
+ Requires DB migration `0003_feature_intelligence.sql` (`npm run db:migrate`).
37
+
38
+ ---
39
+
40
+ ## API reference
41
+
42
+ | Function | Signature | When to use |
43
+ |----------|-----------|-------------|
44
+ | `initNzilaRuntime` | `(config)` once | Before any trace calls |
45
+ | `useNzilaFeature` | `(feature, options?)` | **Top of React component** |
46
+ | `traceNzilaFeature` | `(feature)` | **Top of backend handler** |
47
+ | `handle.captureError` | `(error, detail?)` | Your `try/catch`, toasts, form errors |
48
+ | `handle.captureApiError` | `(error, label, detail?)` | Caught fetch/HTTP without `runApi` |
49
+ | `handle.runApi` | `(label, fn)` | Wrap async API calls |
50
+ | `handle.reportError` | same as `captureError` | Alias |
51
+ | `reportFeatureError` | `(feature, error, detail?)` | Shared util; pass feature + error |
52
+ | `captureFeatureError` | alias of `reportFeatureError` | |
53
+ | `extractErrorFields` | `(error)` | `message`, `name`, `stack` normalization |
54
+
55
+ Returned **handle** (from hook or `traceNzilaFeature`): `{ feature, runApi, captureError, captureApiError, reportError, reportUi }`.
56
+
57
+ ---
58
+
59
+ ## React — `useNzilaFeature` at the top of the component
60
+
61
+ ```tsx
62
+ "use client";
63
+
64
+ import { useNzilaFeature } from "@nzila/sdk/react";
65
+ import { initNzilaRuntime } from "@nzila/sdk/react";
66
+
67
+ // e.g. app/layout.tsx or instrumentation.ts (once)
68
+ initNzilaRuntime({
69
+ signalsUrl: process.env.NEXT_PUBLIC_NZILA_SIGNALS_URL!,
70
+ apiKey: process.env.NEXT_PUBLIC_NZILA_API_KEY!,
71
+ });
72
+
73
+ export function CheckoutPage() {
74
+ const nzila = useNzilaFeature("Checkout"); // same feature as Vitest mapFeature
75
+
76
+ async function pay() {
77
+ await nzila.runApi("POST /api/checkout", () =>
78
+ fetch("/api/checkout", { method: "POST", body: "{}" }),
79
+ );
80
+ }
81
+
82
+ return <button onClick={() => void pay()}>Pay</button>;
83
+ }
84
+ ```
85
+
86
+ ### Manual error handling (your `try/catch`)
87
+
88
+ Use the handle from the hook (feature is already bound):
89
+
90
+ ```tsx
91
+ export function CheckoutPage() {
92
+ const nzila = useNzilaFeature("Checkout");
93
+
94
+ async function pay() {
95
+ try {
96
+ await nzila.runApi("POST /api/checkout", () =>
97
+ fetch("/api/checkout", { method: "POST" }),
98
+ );
99
+ } catch (err) {
100
+ nzila.captureError(err, { step: "pay", handled: true });
101
+ // your toast / form error state
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ Or pass **feature + error** from anywhere (e.g. shared error util):
108
+
109
+ ```ts
110
+ import { reportFeatureError } from "@nzila/sdk/react";
111
+
112
+ reportFeatureError("Checkout", error, { step: "validation" });
113
+ ```
114
+
115
+ `captureError` uses `extractErrorFields` — works with `Error`, strings, and unknown values.
116
+
117
+ ### What is reported automatically
118
+
119
+ | Issue | Signal `type` | `payload` notes |
120
+ |-------|---------------|-----------------|
121
+ | Too many re-renders in ~1s | `ui` | `kind: "render_loop"`, `renderCount` |
122
+ | `window.onerror` | `error` | while component mounted |
123
+ | Unhandled promise rejection | `error` | while mounted |
124
+ | `runApi` failure | `api` | `success: false`, message |
125
+ | `runApi` success | `api` | `success: true`, `label` |
126
+
127
+ Optional error boundary:
128
+
129
+ ```tsx
130
+ import { NzilaFeatureBoundary } from "@nzila/sdk/react";
131
+
132
+ <NzilaFeatureBoundary feature="Checkout" nzila={nzila}>
133
+ <CheckoutForm />
134
+ </NzilaFeatureBoundary>
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Backend — `traceNzilaFeature` at the top of the handler
140
+
141
+ ```ts
142
+ import { initNzilaRuntime, traceNzilaFeature } from "@nzila/sdk";
143
+
144
+ initNzilaRuntime({
145
+ signalsUrl: process.env.NZILA_SIGNALS_URL!,
146
+ apiKey: process.env.NZILA_API_KEY!,
147
+ });
148
+
149
+ export async function postCheckout(req: Request) {
150
+ const nzila = traceNzilaFeature("Checkout");
151
+
152
+ try {
153
+ const upstream = await nzila.runApi("payment-gateway", () =>
154
+ fetch("https://api.example.com/charge", { method: "POST" }),
155
+ );
156
+ if (!upstream.ok) throw new Error(`charge failed: ${upstream.status}`);
157
+ return Response.json({ ok: true });
158
+ } catch (err) {
159
+ nzila.captureError(err, { route: "POST /checkout", handled: true });
160
+ return Response.json({ error: "payment_failed" }, { status: 502 });
161
+ }
162
+ }
163
+ ```
164
+
165
+ Caught an API error without `runApi`?
166
+
167
+ ```ts
168
+ nzila.captureApiError(err, "payment-gateway", { status: 502 });
169
+ ```
170
+
171
+ From a nested helper without the handle:
172
+
173
+ ```ts
174
+ import { reportFeatureError } from "@nzila/sdk";
175
+
176
+ reportFeatureError("Checkout", err, { layer: "inventory-service" });
177
+ ```
178
+
179
+ Call **`traceNzilaFeature("Checkout")` as the first line** of the route/service that matches your tested feature.
180
+
181
+ Repo example: [backend/runtime-trace.example.ts](./backend/runtime-trace.example.ts).
182
+
183
+ ---
184
+
185
+ ## Dashboard
186
+
187
+ Open **Feature health** for the project — compare **tests** (from webhooks) with **runtime** (`api` / `ui` / `error` signals).
188
+
189
+ Use the **same feature string** everywhere:
190
+
191
+ | Source | Example |
192
+ |--------|---------|
193
+ | Vitest `describe` / `mapFeature` | `"Checkout"` |
194
+ | `useNzilaFeature("…")` | `"Checkout"` |
195
+ | `traceNzilaFeature("…")` | `"Checkout"` |
196
+ | `reportFeatureError("…", err)` | `"Checkout"` |
197
+ | Manual HTTP (advanced) | `POST /api/signals/runtime` |
198
+
199
+ Test-side tracing: [TRACING-FAILURES.md](./TRACING-FAILURES.md).
200
+ Deploy (Vercel + Render): [../docs/DEPLOY-VERCEL-RENDER.md](../docs/DEPLOY-VERCEL-RENDER.md).
201
+
202
+ ---
203
+
204
+ ## Manual HTTP (optional)
205
+
206
+ Same payload the SDK sends:
207
+
208
+ ```json
209
+ {
210
+ "locale": "en",
211
+ "signals": [
212
+ {
213
+ "feature": "Checkout",
214
+ "type": "error",
215
+ "success": false,
216
+ "payload": { "message": "card declined", "handled": true }
217
+ }
218
+ ]
219
+ }
220
+ ```
221
+
222
+ Types: `navigation`, `api`, `ui`, `error`, `custom`.
@@ -0,0 +1,186 @@
1
+ # Tracing test failures in Nzila
2
+
3
+ How failures move from **backend** and **frontend** test runs into the dashboard, how to **attach tests to a feature**, and how to trace an error even when the test was already in your suite.
4
+
5
+ ## Mental model
6
+
7
+ ```text
8
+ describe() tree → describePath + fingerprint
9
+ mapFeature / feature field → dashboard "Feature" column
10
+ test name → human label
11
+ errors[] → processed into Failure analysis (not raw stacks in UI)
12
+ worker → summaries + feature health
13
+ ```
14
+
15
+ 1. Vitest finishes one run → reporter sends **one** webhook (`runId` is idempotent).
16
+ 2. Each test becomes a row with `describePath`, `feature`, `testName`, `status`, `errors`.
17
+ 3. The worker enriches failures and updates **Stability**, **Failures**, and **Feature health**.
18
+
19
+ ## Developer setup (one-time)
20
+
21
+ ### 1. Run Nzila locally
22
+
23
+ From the repo root (see [README](../README.md)):
24
+
25
+ ```bash
26
+ npm install
27
+ cp .env.example .env.local # fill DATABASE_URL, AUTH_SECRET, etc.
28
+ npm run db:migrate
29
+ npm run dev # http://localhost:3000
30
+ npm run worker # second terminal — processes webhooks
31
+ ```
32
+
33
+ ### 2. Create two projects (API + web)
34
+
35
+ In the dashboard, create **two** projects so backend and frontend keys do not mix:
36
+
37
+ | Project display name | **App name** (must match Vitest `appName`) | Example tests |
38
+ |----------------------|------------------------------------------|---------------|
39
+ | Checkout API | `checkout-api` | `examples/backend/` |
40
+ | Checkout Web | `checkout-web` | `examples/frontend/` |
41
+
42
+ For each project: **Settings → API keys** → create a key. You can use one key for both demos if both projects belong to your org and you switch `NZILA_API_KEY` when running each suite — separate keys are clearer.
43
+
44
+ ### 3. Configure `.env.local`
45
+
46
+ ```bash
47
+ NZILA_WEBHOOK_URL=http://localhost:3000/api/webhooks/tests
48
+ NZILA_API_KEY=nzl_your_key_for_checkout_api
49
+ ```
50
+
51
+ For frontend tracing, use the **checkout-web** key (or change the key before `example:test:tracing:frontend`).
52
+
53
+ ### 4. Run tracing demos
54
+
55
+ ```bash
56
+ npm run example:test:tracing:backend # failures → checkout-api
57
+ npm run example:test:tracing:frontend # failures → checkout-web
58
+ npm run example:test:tracing:all # both
59
+ ```
60
+
61
+ Tracing-only Vitest configs (reporter + `mapFeature`):
62
+
63
+ - `examples/vitest.tracing.backend.config.ts`
64
+ - `examples/vitest.tracing.frontend.config.ts`
65
+
66
+ ## Attach tests to a feature
67
+
68
+ Nzila groups failures and health by **feature** string. You have three ways to set it:
69
+
70
+ ### A. Top-level `describe` name (default)
71
+
72
+ The Vitest reporter uses the **first** `describe()` segment as `feature` unless you override with `mapFeature`.
73
+
74
+ ```ts
75
+ describe("Checkout", () => {
76
+ it("should reject expired cards", () => { /* ... */ });
77
+ });
78
+ ```
79
+
80
+ → `feature: "Checkout"`, fingerprint includes full `describePath`.
81
+
82
+ ### B. `mapFeature` in the reporter (recommended for UI vs product names)
83
+
84
+ When suite titles are long (e.g. `"Checkout UI"`) but the product feature is `"Checkout"`, map them in config:
85
+
86
+ ```ts
87
+ // examples/shared/feature-map.ts
88
+ export function resolveFrontendFeature(describePath: string[], _testName: string) {
89
+ if (describePath[0] === "Checkout UI") return "Checkout";
90
+ return describePath[0] ?? "general";
91
+ }
92
+ ```
93
+
94
+ Wire it in `NzilaVitestReporter({ mapFeature: resolveFrontendFeature, ... })`.
95
+
96
+ ### C. Explicit `feature` in webhook JSON
97
+
98
+ For manual/CI payloads, set `feature` on each test (see `examples/backend/sample-tracing-payload.json` and `examples/frontend/sample-tracing-payload.json`):
99
+
100
+ ```json
101
+ {
102
+ "describePath": ["Checkout UI", "email field"],
103
+ "feature": "Checkout",
104
+ "testName": "should reject malformed email addresses",
105
+ "status": "failed",
106
+ "errors": [{ "message": "...", "stack": "..." }]
107
+ }
108
+ ```
109
+
110
+ Server fallback: `feature ?? describePath[0] ?? "general"` (`ensureTestCase`).
111
+
112
+ **Runtime signals** should use the **same** feature string so **Feature health** lines up tests and production.
113
+
114
+ **Recommended (live app):** use the SDK so production matches tests:
115
+
116
+ | Layer | Call at top of unit | Manual `catch` |
117
+ |-------|---------------------|----------------|
118
+ | React | `const nzila = useNzilaFeature("Checkout")` | `nzila.captureError(err, { … })` |
119
+ | Backend | `const nzila = traceNzilaFeature("Checkout")` | `nzila.captureError(err, { … })` |
120
+ | Either | — | `reportFeatureError("Checkout", err, { … })` |
121
+
122
+ Auto-reported: render loops (`ui`), `runApi` failures (`api`), unhandled window errors. Full API: **[RUNTIME-TRACE.md](./RUNTIME-TRACE.md)**.
123
+
124
+ ## Example suites
125
+
126
+ | Layer | File | App name | Script |
127
+ |-------|------|----------|--------|
128
+ | Backend | `examples/backend/error-tracing.test.ts` | `checkout-api` | `npm run example:test:tracing:backend` |
129
+ | Frontend | `examples/frontend/error-tracing.test.ts` | `checkout-web` | `npm run example:test:tracing:frontend` |
130
+
131
+ Failures are intentional so you can practice tracing without breaking production code paths.
132
+
133
+ ## Trace a failure after tests ran (even with tests in CI)
134
+
135
+ Tests passing or failing does not block tracing: each **run** is stored with per-test `errors`. When a test **fails** (or starts failing in a new run):
136
+
137
+ 1. **Test runs** (`/en/runs`) — open the latest run for `checkout-api` or `checkout-web`.
138
+ 2. **Failure analysis** (`/en/failures`) — read processed summaries (from `errors[].message`, not raw stacks).
139
+ 3. **Feature insights** / **Feature health** — filter by the same `feature` you attached in the suite or payload.
140
+ 4. **Code** — match **fingerprint**: `describePath[0] › … › testName` (same `describe` + `it` names as in repo).
141
+
142
+ Optional: send runtime signals for the same feature and compare on **Feature health**.
143
+
144
+ ## Manual webhook (no Vitest)
145
+
146
+ ```bash
147
+ npm run example:webhook:tracing # backend sample
148
+ npm run example:webhook:tracing:frontend # frontend sample
149
+ ```
150
+
151
+ Requires `NZILA_API_KEY` and `NZILA_WEBHOOK_URL` in `.env.local` (script loads env via `send-webhook.mjs`).
152
+
153
+ ## Webhook error fields
154
+
155
+ Per test in `tests[]`:
156
+
157
+ ```json
158
+ {
159
+ "describePath": ["Checkout", "Payment"],
160
+ "feature": "Checkout",
161
+ "testName": "should reject expired cards",
162
+ "status": "failed",
163
+ "duration": 42,
164
+ "errors": [
165
+ { "message": "expected false to be true", "stack": "AssertionError: ..." }
166
+ ]
167
+ }
168
+ ```
169
+
170
+ - **message** — drives operator-facing copy after processing.
171
+ - **stack** — optional; used server-side, not shown as-is on **Failures**.
172
+
173
+ ## Related files
174
+
175
+ | File | Role |
176
+ |------|------|
177
+ | `examples/shared/feature-map.ts` | Backend/frontend feature mapping |
178
+ | `@nzila/sdk/vitest-reporter.ts` | Vitest → webhook + `mapFeature` |
179
+ | `src/lib/webhook-schema.ts` | Payload validation |
180
+ | `src/server/test-cases.ts` | `feature` resolution |
181
+ | `src/server/process-run.ts` | Worker enrichment |
182
+ | `examples/TRACING-FAILURES.md` | This guide (tests) |
183
+ | `examples/RUNTIME-TRACE.md` | Live `useNzilaFeature`, `captureError` |
184
+ | `examples/backend/runtime-trace.example.ts` | Backend handler sample |
185
+ | `@nzila/sdk/runtime/` | Runtime client |
186
+ | `@nzila/sdk/react/` | React hook + boundary |