# Performance Baseline — Phase 02 Quickwins (Task #36) This document tracks the expected and observed effect of the 8 quickwin optimizations shipped under task #36 (`docs/improvement-plan/02-observability/performance-quickwins.md`). ## Status - **Code-level changes:** shipped to `main` 2026-05-17 (8 atomic commits + this baseline doc). - **`/metrics` endpoint status:** code shipped for API and worker runtimes. The API exposes token-protected `GET /metrics` when `METRICS_ENABLED=true`; worker admin servers expose token-protected `/metrics` when enabled and keep health probes on a separate port. - **Live `/metrics` baseline:** operator-owned. The endpoint code exists, but the live before/after numbers still require an environment with `METRICS_ENABLED=true`, `METRICS_TOKEN`, scrape access and a controlled load run. ## Per-item expected gains (code-level reasoning) | Item | File | Mechanism | Expected gain | | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 1. N+1 in admin users list | `apps/web/app/routes/admin/accounts/users.tsx` + `apps/web/app/utils/db/logs.db.server.ts` | Replace N `findFirst` calls with 1 `groupBy` + 1 `findMany` | DB queries on the admin users-list loader: `O(N)` → `O(1)` (101→2 for a 100-user page). Largest practical win on this route. | | 2. Duplicate tenant fetch | `apps/web/app/utils/session.server.ts` + `apps/web/app/routes/admin/accounts/users.tsx` + `apps/web/app/routes/oauth/github/callback.tsx` | `setLoggedUser` now returns `defaultTenant`; callers reuse it instead of fetching again | One fewer `getTenant()` round-trip per sign-in / impersonation start (≈ 1 DB query/login). | | 3. S3 client + signer caching | `apps/api/src/storage.ts` | Memoize S3 storage adapter, signed-URL adapter and per-day SigV4 signing key by SHA256-of-config | Eliminates per-call adapter construction + HMAC chain (4 HMAC-SHA256 ops) on every signed URL. Per-request CPU win in hot upload/download paths. | | 4. clearSubscriptionsCache thrash | `apps/web/app/utils/services/.server/subscriptionService.ts` + `apps/web/app/utils/db/subscriptions/tenantSubscriptionProducts.db.server.ts` | New `clearTenantSubscriptionCache(tenantId)` replaces a global wipe in `cancelTenantSubscriptionProduct` | Subscription-change webhooks no longer evict every tenant's cached subscription. Tenant N=1000 → only 1 eviction per event instead of 1000. | | 5. CSRF header-first check | `apps/web/app/utils/session.server.ts` | Already-resolved in commit `83a57f1c`; regression test added | No additional perf change in #36; documents the historical fix and now-enforced contract: 0 body-clones when the header carries the token. | | 6. Recovery-code rejection sampling | `apps/web/app/utils/auth/mfa/recovery-codes.server.ts` | Drop `while(set.size < n)` loop; generate batch + max 2 retries | Generates 10 codes in one batch (≥99.999% of calls); throws on systemic failure instead of looping forever. Bounds wall-clock generation cost. | | 7. UUID collision loop | `apps/api/src/auth/session/session-store.ts` | `while (sessions.has(sessionId))` → single insert; throw on collision | 1 ID generation per `createSession` instead of unbounded retry. UUID-v4 has 122 bits of entropy, so a collision is a systemic error to surface, not mask. | | 8. CSRF token size | `apps/web/app/utils/session.server.ts` | `randomBytes(100).toString("base64")` → `randomBytes(32).toString("hex")` | Token shrinks ~136 chars → 64 chars. Saves ~70 bytes/cookie and ~70 bytes/response per CSRF-bearing endpoint. Aggregate response-body reduction across the cluster. | ## Test coverage added - `apps/web/app/utils/db/logs.db.server.test.ts` — `getLastUserLogsByUserIds` uses exactly 1 `groupBy` + 1 `findMany`. - `apps/web/app/utils/session.server.test.ts` — `setLoggedUser` returns `defaultTenant`; `validateCSRFToken` never clones the request body when the header carries the token; `generateCSRFToken` emits 64 hex chars. - `apps/api/src/storage.test.ts` — repeated config hits the adapter cache; bucket change misses; secret rotation misses. - `apps/web/app/utils/services/.server/subscriptionService.test.ts` — `clearTenantSubscriptionCache` does not enumerate other tenants; `clearAllSubscriptionsCache` invalidates all tenant entries. - `apps/web/app/utils/auth/mfa/recovery-codes.server.test.ts` — generation completes under a strict wall-clock bound (regression guard against unbounded rejection sampling). - `apps/api/src/auth/session/session-store.test.ts` — UUID collision now throws instead of silently retrying. ## Live baseline (operator-owned) Populate the table below by running `oha -n 5000 -c 50` against staging twice for a comparable before/after window and scraping API/worker `/metrics` snapshots with `Authorization: Bearer `. The code path is shipped; the live baseline values are operational evidence and should be recorded only from the target environment. | Metric | Before | After | Delta | | ----------------------------------------------- | --------------- | ----- | ----- | | p50 latency, GET `/admin/users` | TBD | TBD | TBD | | p95 latency, GET `/admin/users` | TBD | TBD | TBD | | Prisma query count / request (admin users list) | TBD | TBD | TBD | | p95 latency, signed-URL endpoint | TBD | TBD | TBD | | p95 latency, login flow | TBD | TBD | TBD | | Cache evictions per Stripe webhook | TBD | TBD | TBD | | CSRF cookie size (bytes) | ~136 hex equiv. | 64 | -53% | ## Notes - All eight items shipped as **atomic** commits; any single item can be reverted in isolation. - Item 5 was already in tree from `83a57f1c fix: enforce csrf on settings mutations`. It is recorded here for completeness and now carries an explicit no-body-read assertion. - Path corrections were necessary on items 2 and 6 — see the per-item Progress Log entries in `docs/improvement-plan/02-observability/performance-quickwins.md`. ## Footer - Date: 2026-05-17 - Owner: Phase-02 quickwins agent - Live-test hardware: operator-owned (fill with the target environment used for the controlled load run)