From 9d7bc0208120b53d46a302db4012e3909c625d93 Mon Sep 17 00:00:00 2001 From: Hoid Date: Sat, 7 Mar 2026 20:07:19 +0100 Subject: [PATCH] DocFast session 142: BUG-108/109/110 fixed, 547 tests --- projects/business/memory/bugs.md | 24 ++++++++++++++++++++++++ projects/business/memory/sessions.md | 25 +++++++++++++++++++++++++ projects/business/memory/state.json | 4 ++-- projects/snapapi/memory/sessions.md | 15 +++++++++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/projects/business/memory/bugs.md b/projects/business/memory/bugs.md index ea7b5b0..59123e1 100644 --- a/projects/business/memory/bugs.md +++ b/projects/business/memory/bugs.md @@ -1,3 +1,27 @@ +## BUG-110: POST /v1/recover initial request still uses in-memory cache only — recovery email not sent across pods +- **Date:** 2026-03-07 +- **Severity:** MEDIUM +- **Issue:** `POST /v1/recover` uses `getAllKeys()` to find a user by email. BUG-107 added DB fallback to `/v1/recover/verify` but NOT to the initial `/v1/recover` route. If the key exists in DB but not in this pod's cache, the route returns "recovery_sent" but never actually sends the verification email (silently skips). +- **Impact:** Users may be unable to recover their API key if they hit a pod that doesn't have the key cached. Silent failure — same "recovery_sent" response regardless. +- **Fix:** Add DB fallback in `POST /v1/recover` — if `getAllKeys().find()` returns nothing, query DB by email before deciding to skip sending. +- **Status:** ✅ FIXED — commit d376d58. DB fallback sends recovery email when cache miss. 2 TDD tests added. 547 tests total. + +## BUG-109: updateKeyEmail only checks in-memory cache — email change may silently fail across pods +- **Date:** 2026-03-07 +- **Severity:** MEDIUM +- **Issue:** `updateKeyEmail()` in `src/services/keys.ts` only checks `keysCache` (in-memory). In 2-replica production, if the email-change verify route on one pod updates the DB directly but the billing webhook `customer.updated` calls `updateKeyEmail` on another pod where the key isn't cached, the function returns `false` without checking DB. +- **Impact:** Unlikely to trigger (email-change uses direct DB, not this function), but `updateKeyEmail` is exported and could be used elsewhere. Code quality issue — same pattern as BUG-106. +- **Fix:** Add DB fallback: query `api_keys` table by key when not found in cache. +- **Status:** ✅ FIXED — commit d376d58. DB fallback + cache hydration. 2 TDD tests added. 547 tests total. + +## BUG-108: updateEmailByCustomer only checks in-memory cache — Stripe email sync silently fails across pods +- **Date:** 2026-03-07 +- **Severity:** MEDIUM +- **Issue:** `updateEmailByCustomer()` in `src/services/keys.ts` only checks `keysCache` (in-memory). In 2-replica production, if a Stripe `customer.updated` webhook hits a pod that doesn't have the key cached (pod restart, key created on other pod), the function returns `false` without checking DB. Customer's email change from Stripe is silently lost. +- **Impact:** Email sync from Stripe billing silently fails. Customer's email in DocFast DB diverges from Stripe. Recovery emails go to wrong address. +- **Fix:** Add DB fallback: query `api_keys` table by `stripe_customer_id` when not found in cache, then update email in DB and hydrate local cache. +- **Status:** OPEN + ## BUG-107: Recover route uses in-memory cache only — recovery fails silently across pods - **Date:** 2026-03-06 - **Severity:** MEDIUM diff --git a/projects/business/memory/sessions.md b/projects/business/memory/sessions.md index a5b2ba5..f78cf44 100644 --- a/projects/business/memory/sessions.md +++ b/projects/business/memory/sessions.md @@ -1,5 +1,30 @@ # Session Log +## Session 142 — 2026-03-07 19:00 UTC (Saturday Evening) +- **Production:** v0.5.1 ✅ healthy, 2 replicas, 0 restarts, ~9d uptime +- **Staging:** v0.5.2 ✅ commit d376d58 (52+ commits ahead of prod) +- **K8s cluster:** All 3 nodes Ready +- **Support:** Zero tickets +- **Completed:** + 1. **DB fallback fixes for multi-replica cache consistency (TDD)** — Found and fixed 3 bugs where in-memory cache lookups had no DB fallback, causing silent failures in 2-replica production: + - BUG-108: `updateEmailByCustomer` — Stripe `customer.updated` webhook email sync silently failed if key cached on other pod + - BUG-109: `updateKeyEmail` — same pattern, exported function lacked fallback + - BUG-110: `POST /v1/recover` initial request — recovery email not sent when key not in pod's cache (verify route had fallback from BUG-107, but initial route didn't) + All three fixed with DB fallback + cache hydration. 6 TDD tests (RED→GREEN verified). Commit d376d58. + 2. **Full codebase audit** — Reviewed: all `keysCache` usages for DB fallback gaps (found 3 above), SSRF protection in URL-to-PDF (comprehensive), admin route auth (properly gated), billing webhook handling (correct), email-change route (already uses direct DB), convert routes error handling (solid). + 3. **Infrastructure health check** — All 3 K8s nodes Ready, both prod replicas healthy (0 restarts, ~9d uptime), DB connected (PostgreSQL 17.4), browser pool 15/15 on both environments. All 7 pages responding 200 in <150ms. +- **Total tests:** 547 (all passing, 0 errors), 44 test files +- **Open bugs:** ZERO 🎉 +- **CI runner:** Still absent. Managed by Cloonar — needs investor action. +- **Sub-agent issues:** All 3 sub-agent spawns failed instantly (platform issue). Implemented fixes directly. +- **Investor test:** + 1. Would a stranger trust this with money? Yes ✅ + 2. Pod crash = data loss? No — CNPG WAL archiving + MinIO ✅ + 3. Free tier abuse? No — removed, demo rate-limited ✅ + 4. Pro key recovery? Yes — with DB fallback across pods (improved this session) ✅ + 5. Every feature works? Yes ✅ +- **Recommendation:** Staging v0.5.2 production-ready. 52+ commits ahead with 547 tests. Awaiting investor approval for production tag + CI runner restoration. + ## Session 141 — 2026-03-07 16:00 UTC (Saturday Evening) - **Production:** v0.5.1 ✅ healthy, 2 replicas, 0 restarts, ~9d uptime - **Staging:** v0.5.2 ✅ commit 424a16e (51+ commits ahead of prod) diff --git a/projects/business/memory/state.json b/projects/business/memory/state.json index 5408241..5bdb190 100644 --- a/projects/business/memory/state.json +++ b/projects/business/memory/state.json @@ -3,7 +3,7 @@ "phaseLabel": "Build Production-Grade Product", "status": "launch-ready", "product": "DocFast — HTML/Markdown to PDF API", - "currentPriority": "Production on v0.5.1. Staging v0.5.2 (51+ commits ahead). npm audit 0 vulns. 541 tests passing (42 files). ZERO open bugs. Fixed error message info disclosure (convert/templates/admin routes no longer leak err.message). Standardized QUEUE_FULL→503, added PDF_TIMEOUT→504 to convert routes. Ready for production tag when investor approves.", + "currentPriority": "Production on v0.5.1. Staging v0.5.2 (52+ commits ahead). npm audit 0 vulns. 547 tests passing (44 files). ZERO open bugs. Fixed DB fallback gaps in updateEmailByCustomer, updateKeyEmail, and initial recover route (BUG-108/109/110). All in-memory-only cache lookups now have DB fallback for multi-replica safety. Ready for production tag when investor approves.", "ownerDirectives_PRIORITY": "Process these IN ORDER. Do not skip. Remove items marked ✅ DONE/FIXED during housekeeping.", "ownerDirectives": [ "Stripe Product ID for DocFast: prod_TygeG8tQPtEAdE — webhook handler must filter by this product_id to ignore events from other projects on the same Stripe account." @@ -83,7 +83,7 @@ "LOW": [], "note": "All bugs resolved. BUG-105 fixed 4f6659c. BUG-104 fixed 503e651. BUG-103 (template validation bypass) fixed 47571c8. BUG-102 (sanitized options ignored) fixed ba2e542. BUG-101 (body limits) fixed c03f217. BUG-100 (flush poisoning) fixed d2f819d. BUG-099 (memory leak) fixed 5f776db. BUG-098 (interceptor leak) fixed 024fa00." }, - "sessionCount": 141 + "sessionCount": 142 }, "blockers": [], "startDate": "2026-02-14" diff --git a/projects/snapapi/memory/sessions.md b/projects/snapapi/memory/sessions.md index 3f41b52..1b84a1c 100644 --- a/projects/snapapi/memory/sessions.md +++ b/projects/snapapi/memory/sessions.md @@ -1,5 +1,20 @@ # SnapAPI Session Log +## Session 71 — 2026-03-07 18:00 CET (Saturday Evening Health Check) + +**Goal:** Routine health check. + +**Health Check:** +- Production: ✅ 2 replicas running (9d uptime), v0.5.2, both pods healthy, spread across w1/w2 +- Staging: ✅ 1 replica running (23h uptime), 493 tests passing +- Signup block: ✅ Still active + +**Assessment:** No changes since session 70 (3 hours ago). All systems stable. Saturday evening — no action warranted. All work remains blocked on external approvals (production deploy, Stripe webhook, CI/CD token, staging TLS). + +**Investor Test:** Unchanged from session 69. + +--- + ## Session 70 — 2026-03-07 15:00 CET (Saturday Afternoon Health Check) **Goal:** Routine health check.