DocFast session 96: 130 tests, security util extraction

This commit is contained in:
Hoid 2026-02-25 19:05:56 +00:00
parent 052bf8519f
commit 486f77557a
8 changed files with 135 additions and 26 deletions

View file

@ -1,7 +1,24 @@
{ {
"sent": [ "sent": [
{"event": "Marie besuchen", "date": "2026-02-07", "remindedAt": "2026-02-07T09:31:00Z"}, {
{"event": "StandUp Team", "date": "2026-02-24", "remindedAt": "2026-02-24T08:02:00Z"}, "event": "Marie besuchen",
{"event": "Friseur", "date": "2026-02-25", "remindedAt": "2026-02-25T08:08:00Z"} "date": "2026-02-07",
"remindedAt": "2026-02-07T09:31:00Z"
},
{
"event": "StandUp Team",
"date": "2026-02-24",
"remindedAt": "2026-02-24T08:02:00Z"
},
{
"event": "Friseur",
"date": "2026-02-25",
"remindedAt": "2026-02-25T08:08:00Z"
},
{
"event": "Friseur",
"date": "2026-02-25",
"remindedAt": "2026-02-25T11:01:00Z"
}
] ]
} }

View file

@ -52,14 +52,14 @@
], ],
"notes": "N26 uses Xetra tickers. Always provide ISIN for orders. Fractional shares by EUR amount supported.", "notes": "N26 uses Xetra tickers. Always provide ISIN for orders. Fractional shares by EUR amount supported.",
"created": "2026-02-12T20:00:00Z", "created": "2026-02-12T20:00:00Z",
"lastUpdated": "2026-02-24T16:15:00Z", "lastUpdated": "2026-02-25T16:15:00Z",
"closingSnapshot": { "closingSnapshot": {
"date": "2026-02-24", "date": "2026-02-25",
"DFNS": 59.25, "DFNS": 58.96,
"portfolioValue": 1053.70, "portfolioValue": 1048.55,
"dailyPL": 5.69, "dailyPL": -5.16,
"dailyPLpct": 0.54, "dailyPLpct": -0.49,
"totalReturn": 5.37 "totalReturn": 4.85
}, },
"pendingActions": [] "pendingActions": []
} }

View file

@ -1,16 +1,11 @@
{ {
"date": "2026-02-24", "date": "2026-02-25",
"events": [ "events": [
{"time": "19:27", "activity": "Wind-down check-in sent. Suggested Askir audiobook + Kinder der Zeit. Reminded about Friseur tomorrow.", "source": "heartbeat"}, {"time": "19:09", "activity": "Wind-down check-in sent. Suggested Conan (Moonlight Sonata Murder Case) or King of Queens.", "source": "heartbeat"},
{"time": "19:30", "activity": "Fixing one minor bug in workout app, then winding down. Plans to watch Detective Conan.", "source": "chat"}, {"time": "20:10", "activity": "Still working on something, finishing up. Plans to watch something after.", "source": "chat"}
{"time": "20:27", "activity": "Follow-up check-in: asked if bug is done, nudged toward Conan.", "source": "heartbeat"},
{"time": "21:30", "activity": "Nose shower done ✅. Watching Detective Conan.", "source": "chat"},
{"time": "21:30", "activity": "FEEDBACK: Don't narrate internal reasoning in messages — just talk naturally.", "source": "chat"},
{"time": "23:27", "activity": "No messages since ~21:30. Likely still watching Conan or heading to bed.", "source": "estimate"},
{"time": "~23:45", "activity": "Going to sleep. Wants to implement better sync status visibility in workout app tomorrow.", "source": "chat"}
], ],
"yesterday": { "yesterday": {
"sleep": "~midnight (estimated)", "sleep": "~23:45 (said going to sleep)",
"summary": "SSH tinkering, nose shower done, asleep ~midnight" "summary": "Bug fix in workout app, Detective Conan, nose shower done, asleep ~midnight"
} }
} }

View file

@ -1,3 +1,12 @@
## BUG-087: OpenAPI spec empty on staging — swagger-jsdoc 7.0.0-rc.6 regression
- **Date:** 2026-02-25
- **Severity:** HIGH
- **Issue:** Session 93 upgraded swagger-jsdoc from 6.2.8 to 7.0.0-rc.6 to fix a minimatch ReDoS vuln. The RC is broken — `swaggerJsdoc()` returns `{}` (empty object, 0 paths). The `/docs` page on staging shows no API endpoints. `/openapi.json` returns `{}`.
- **Root cause:** swagger-jsdoc 7.0.0-rc.6 does not parse `@openapi` JSDoc annotations from glob-matched files.
- **Impact:** Staging has no API documentation. Production (v0.4.5) is unaffected (still on 6.2.8 build).
- **Fix:** Reverted to swagger-jsdoc 6.2.8. Added 2 regression tests verifying OpenAPI spec has paths and includes key endpoints. npm audit still shows 0 vulnerabilities.
- **Status:** ✅ FIXED — commit 288d6c7, deploying to staging
## BUG-080: Landing page still shows Free tier after v0.4.0 "removal" ## BUG-080: Landing page still shows Free tier after v0.4.0 "removal"
- **Date:** 2026-02-20 - **Date:** 2026-02-20
- **Severity:** HIGH - **Severity:** HIGH

View file

@ -1,5 +1,63 @@
# Session Log # Session Log
## Session 96 — 2026-02-25 19:00 UTC (Wednesday Evening)
- **Production:** v0.4.5 ✅ healthy, 2 replicas, 0 restarts
- **Staging:** v0.5.1 ✅ healthy (new commit deploying)
- **K8s cluster:** All 3 nodes Ready
- **Support:** Zero tickets
- **Proactive improvements completed:**
1. **Extracted and unit-tested security-critical utility functions:**
- `isPrivateIP``src/utils/network.ts` (19 tests: IPv4 private/public ranges, IPv6 loopback/link-local/unique-local, IPv4-mapped IPv6, edge cases)
- `isTransientError``src/utils/errors.ts` (23 tests: all PG error codes, message-based matches, null/undefined, non-transient errors)
- `escapeHtml``src/utils/html.ts` (9 tests: all special chars, empty string, double-escaping, mixed content)
- `markdownToHtml` / `wrapHtml` (12 tests: headings, bold, italic, links, code blocks, custom/default CSS, empty input)
2. **Code quality:** Extracted inline functions to shared utils for testability and reuse. Original files import from new locations. Backward-compatible re-exports maintained.
3. **130 tests total** (up from 67), all passing in ~4s across 7 test files.
- **Commit:** 50a163b pushed to main → auto-deploys to staging
- **Investor test:** All 5 checks pass ✅
- **Budget:** €181.71 remaining, Revenue: €9
- **Pending for investor:**
- Production tag for latest staging (20+ commits ahead of prod v0.4.5)
- SDK tokens (npm/PyPI/Go/Packagist)
- Google Search Console verification
## Session 95 — 2026-02-25 16:00 UTC (Wednesday Late Afternoon)
- **Production:** v0.4.5 ✅ healthy, 2 replicas, 0 restarts
- **Staging:** v0.5.1 ✅ healthy, OpenAPI spec working (BUG-087 fix confirmed deployed)
- **K8s cluster:** All 3 nodes Ready
- **Support:** Zero tickets
- **Proactive improvements completed:**
1. **Deduplicated `sanitizeFilename`** — extracted to shared `src/utils/sanitize.ts`, removed duplicate implementations from convert.ts and templates.ts. Consistent behavior: replace dangerous chars with _, trim, limit 200 chars, default fallback.
2. **Fixed XSS vector in `esc()` function** — added single-quote escaping (`'``'`) in template rendering for attribute context safety.
3. **New test files**`src/__tests__/sanitize.test.ts` (6 tests) + `src/__tests__/templates.test.ts` (5 tests). Tests cover: filename sanitization edge cases, template rendering with correct totals, HTML entity escaping including XSS prevention, unknown template handling.
4. **67 tests total** (up from 57), all passing in 2.3s across 3 test files.
- **Commit:** 0a002f9 pushed to main → auto-deploys to staging
- **Investor test:** All 5 checks pass ✅
- **Budget:** €181.71 remaining, Revenue: €9
- **Note:** claude-sonnet-4-512k sub-agents failing instantly (model unavailability?). Used Opus for dev work.
- **Pending for investor:**
- Production tag for latest staging (20+ commits ahead of prod v0.4.5)
- SDK tokens (npm/PyPI/Go/Packagist)
- Google Search Console verification
## Session 94 — 2026-02-25 13:00 UTC (Wednesday Afternoon)
- **Production:** v0.4.5 ✅ healthy, 75k+ seconds uptime, 2 replicas, 0 restarts
- **Staging:** v0.5.1 ✅ healthy (but pending redeploy with new commits)
- **K8s cluster:** All 3 nodes Ready
- **Support:** Zero tickets
- **Proactive improvements completed:**
1. **BUG-087 FOUND & FIXED** — swagger-jsdoc 7.0.0-rc.6 (upgraded in session 93) broke OpenAPI spec generation. `/openapi.json` returns `{}` on staging. Reverted to 6.2.8 (0 vulns). Added 2 regression tests. Commit 288d6c7.
2. **Unhandled error handlers** — Added `process.on('uncaughtException')` and `process.on('unhandledRejection')` with fatal logging + exit. Previously a stray rejection could crash silently. Commit c4fea79.
3. **New tests** — SSRF blocks 0.0.0.0, Content-Disposition default/custom filename, OpenAPI spec validation. **56 tests total** (up from 52).
- **CI issue:** ARM64 cross-compile builds appear stuck/slow. Commits 288d6c7 and c4fea79 pushed but staging hasn't redeployed yet after 10+ minutes. May need CI runner check.
- **Investor test:** All 5 checks pass ✅ (production unaffected by staging regression)
- **Budget:** €181.71 remaining, Revenue: €9
- **Pending for investor:**
- CI runner may need restart (builds not deploying)
- Production tag for latest staging (20+ commits ahead of prod v0.4.5)
- SDK tokens (npm/PyPI/Go/Packagist)
- Google Search Console verification
## Session 93 — 2026-02-25 10:00 UTC (Wednesday Mid-Morning) ## Session 93 — 2026-02-25 10:00 UTC (Wednesday Mid-Morning)
- **Production:** v0.4.5 ✅ healthy, 64k+ seconds uptime, 2 replicas, 0 restarts - **Production:** v0.4.5 ✅ healthy, 64k+ seconds uptime, 2 replicas, 0 restarts
- **Staging:** v0.5.1 ✅ healthy, pod running on w1 - **Staging:** v0.5.1 ✅ healthy, pod running on w1

View file

@ -3,7 +3,7 @@
"phaseLabel": "Build Production-Grade Product", "phaseLabel": "Build Production-Grade Product",
"status": "launch-ready", "status": "launch-ready",
"product": "DocFast — HTML/Markdown to PDF API", "product": "DocFast — HTML/Markdown to PDF API",
"currentPriority": "Staging ready for prod tag (18 commits ahead). Still need SDK tokens + GSC verification. Test suite: 52 tests passing, 0 npm vulnerabilities.", "currentPriority": "Staging ready for prod tag (20+ commits ahead). Test suite: 130 tests passing (7 test files), 0 npm vulnerabilities. Still need SDK tokens + GSC verification.",
"ownerDirectives_PRIORITY": "Process these IN ORDER. Do not skip. Remove items marked ✅ DONE/FIXED during housekeeping.", "ownerDirectives_PRIORITY": "Process these IN ORDER. Do not skip. Remove items marked ✅ DONE/FIXED during housekeeping.",
"ownerDirectives": [ "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." "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."
@ -85,5 +85,5 @@
}, },
"blockers": [], "blockers": [],
"startDate": "2026-02-14", "startDate": "2026-02-14",
"sessionCount": 93 "sessionCount": 96
} }

View file

@ -1,5 +1,32 @@
# SnapAPI Session Log # SnapAPI Session Log
## Session 24 — 2026-02-25 14:00 UTC (Usage Dashboard Feature)
**Goal:** Build customer-facing usage dashboard — a real gap where customers had no way to check their API usage.
**Built:**
- `GET /v1/usage` API endpoint — authenticated, returns used/limit/plan/month/remaining/percentUsed
- `usage.html` page — dark-themed, input API key, visual progress bar, warning (>80%) and danger (>95%) states
- 4 new tests (TDD: failing first → implementation → green)
- Updated landing page nav + footer with "Check Usage" links
- OpenAPI/Swagger docs updated
**Results:**
- Tests: 133 passing (up from 129), all green
- Code pushed to main, deployed to staging
- Commit: 5b59a7a
**Investor Test:**
1. Trust with money? Mostly — checkout works, Stripe webhook unregistered
2. Data loss on crash? No — PostgreSQL
3. Free tier abuse? Low risk — IP-limited, watermarked, URL length capped
4. Key recovery? Yes on staging
5. Website features? All working
**Still blocked:** Stripe webhook registration, CI/CD (Forgejo runner), staging TLS (DNS), production deploy (needs approval)
---
## Session 23 — 2026-02-25 11:00 UTC (Health Check + Production Deploy Request) ## Session 23 — 2026-02-25 11:00 UTC (Health Check + Production Deploy Request)
**Goal:** Verify system health, run investor test, request production deployment. **Goal:** Verify system health, run investor test, request production deployment.

View file

@ -1,6 +1,6 @@
{ {
"phase": "production-live", "phase": "production-live",
"version": "0.4.3-prod / 0.5.1-staging", "version": "0.4.3-prod / 0.5.2-staging",
"staging": { "staging": {
"status": "running", "status": "running",
"namespace": "snapapi-staging", "namespace": "snapapi-staging",
@ -57,7 +57,10 @@
"Stripe Customer Portal endpoint (POST /v1/billing/portal) — subscription management + key recovery (staging)", "Stripe Customer Portal endpoint (POST /v1/billing/portal) — subscription management + key recovery (staging)",
"API Key Recovery endpoint (GET /v1/billing/recover) — secure masked key lookup (staging)", "API Key Recovery endpoint (GET /v1/billing/recover) — secure masked key lookup (staging)",
"Recovery page at /recovery.html — user-facing key recovery form (staging)", "Recovery page at /recovery.html — user-facing key recovery form (staging)",
"Test suite: 129 tests passing (vitest) — SSRF, cache, auth, keys, billing, playground, screenshot, health, watermark", "Usage Dashboard: GET /v1/usage API endpoint — returns used/limit/plan/month/remaining/percentUsed (staging)",
"Usage page at /usage.html — dark-themed dashboard with progress bar, warning/danger states (staging)",
"Usage Dashboard linked from landing page nav + footer (staging)",
"Test suite: 133 tests passing (vitest) — SSRF, cache, auth, keys, billing, playground, screenshot, health, watermark, usage",
"Git deploy key configured on k3s-mgr for staging builds" "Git deploy key configured on k3s-mgr for staging builds"
], ],
"notDone": [ "notDone": [
@ -81,6 +84,6 @@
"priceId": "price_1T2XHpRtlDv9c8GoThHfd8kS" "priceId": "price_1T2XHpRtlDv9c8GoThHfd8kS"
} }
}, },
"lastSession": "2026-02-25T11:00:00Z", "lastSession": "2026-02-25T14:00:00Z",
"codeLocation": "Forgejo repo openclawd/SnapAPI. Clone: git clone forgejo-snapapi:openclawd/SnapAPI.git" "codeLocation": "Forgejo repo openclawd/SnapAPI. Clone: git clone forgejo-snapapi:openclawd/SnapAPI.git"
} }