3.6 KiB
3.6 KiB
HOALedgerIQ – Load Test Improvement Report
Cycle: 001
Date: YYYY-MM-DD
Test window: HH:MM – HH:MM UTC
Environments: Staging (staging.hoaledgeriq.com)
Scenarios run: auth-dashboard-flow.js + crud-flow.js
Peak VUs: 200 (dashboard) / 100 (CRUD)
New Relic app: HOALedgerIQ_App
Executive Summary
[One paragraph: what load the system handled, what broke first, at what VU threshold, and the estimated user-facing impact. Written by Claude Code from New Relic data.]
Threshold breaches this cycle:
| Metric | Target | Actual | Status |
|---|---|---|---|
| login p95 | < 300ms | — | 🔴 / 🟢 |
| dashboard p95 | < 1000ms | — | 🔴 / 🟢 |
| budget vs-actual p95 | < 1000ms | — | 🔴 / 🟢 |
| journal entry write p95 | < 1200ms | — | 🔴 / 🟢 |
| error rate | < 1% | — | 🔴 / 🟢 |
Findings
🔴 P0 – Fix Before Next Deploy
Finding 001 – [Short title]
- Symptom: e.g.,
GET /api/reports/cash-flow-forecastp95 = 3,400ms at 100 VUs - New Relic evidence: e.g., DatastoreSegment shows 47 sequential DB calls per request
- Root cause hypothesis: e.g., N+1 on
reserve_components— each component triggers a separateSELECTformonthly_actuals - File:
backend/src/modules/reports/cash-flow.service.ts:83 - Recommended fix:
// BEFORE – N+1: one query per component for (const component of components) { const actuals = await this.actualsRepo.findBy({ componentId: component.id }); } // AFTER – batch load with WHERE IN const actuals = await this.actualsRepo.findBy({ componentId: In(components.map(c => c.id)) }); - Expected improvement: ~70% latency reduction on this endpoint
- Effort: Low (1–2 hours)
🟠 P1 – Fix Within This Sprint
Finding 002 – [Short title]
- Symptom:
- New Relic evidence:
- Root cause hypothesis:
- File:
- Recommended fix:
- Expected improvement:
- Effort:
Finding 003 – [Short title]
- (same structure)
🟡 P2 – Backlog
Finding 004 – [Short title]
- Symptom:
- Root cause hypothesis:
- Recommended fix:
- Effort:
Regression Net — Re-Test Criteria
After implementing P0 + P1 fixes, the next BlazeMeter run must pass these gates before merging to staging:
| Endpoint | Previous p95 | Target p95 | k6 Threshold |
|---|---|---|---|
GET /api/reports/cash-flow-forecast |
— | — | p(95)<XXX |
POST /api/journal-entries |
— | — | p(95)<XXX |
GET /api/budgets/:year/vs-actual |
— | — | p(95)<XXX |
Claude Code update command (run after confirming fixes):
claude "Update load-tests/analysis/baseline.json with the p95 values from load-tests/reports/cycle-001.md findings. Tighten the k6 thresholds in load-tests/config/environments.json staging block to match. Do not loosen any threshold that already passes."
Baseline Delta
| Endpoint | Cycle 000 p95 | Cycle 001 p95 | Δ |
|---|---|---|---|
| (populated after first run) | — | — | — |
Notes & Observations
- Any anomalies, flaky tests, or infrastructure events during the run
- Redis / BullMQ queue depth observations
- Rate limiter (Throttler) trip count — if >0, note which endpoints and at what VU count
- TenantMiddleware cache hit rate (if observable via New Relic custom attributes)
Generated by Claude Code. Source data in load-tests/analysis/raw/. Next cycle target: implement P0+P1, re-run at same peak VUs, update baselines.