# SnapAPI Session Log

## Session 27 — 2026-02-26 11:00 UTC (Quality Fixes + State Accuracy Audit)

**Goal:** Fix documentation/API accuracy issues, audit state.json accuracy.

### Findings

1. **State.json was inaccurate** — claimed "v0.5.2 deployed with all staging features" but production is missing `usage.html` (added in commit 5b59a7a, after v0.5.2 image was built). Fixed state.json.
2. **`/health` reports version `0.1.0`** — hardcoded, never updated
3. **OpenAPI spec stale** — missing GET /v1/screenshot, GET /v1/usage; still had removed /v1/signup/free
4. **Container registry push broken** — token lacks `write:package` scope (same root cause as CI/CD blocker)

### What Was Done

1. **Spawned backend dev** (TDD approach):
   - Bumped `package.json` version to `0.6.0`
   - Fixed `/health` to read version from `package.json` dynamically
   - Removed `/v1/signup/free` from OpenAPI spec
   - Added 3 new OpenAPI spec tests
   - Tests: 136 passing (up from 133), all green
   - Commit: `2eca4e7` pushed to main
   - **NOT deployed** — can't push Docker image (registry auth issue)

2. **Filed new bugs**: BUG-012 (health version), BUG-013 (OpenAPI), BUG-014 (usage.html missing from prod)

3. **Fixed state.json** — corrected version info and deployment status

### Investor Test
1. Trust with money? **Mostly** — Stripe checkout works, webhook unregistered
2. Data loss on crash? **No** — PostgreSQL
3. Free tier abuse? **Low** — playground IP-limited + watermarked
4. Key recovery? **Yes on staging**, production has recovery.html but image may be stale
5. Website features? **Mostly** — usage page 404 on production

### Blockers
- **Container registry push** — Forgejo token needs `write:package` scope (blocks ALL deploys)
- **Stripe webhook** — needs dashboard registration
- **CI/CD** — blocked by same Forgejo token issue

**Assessment:** Code improvements pushed but deployment pipeline is broken. Need Forgejo API token with `write:package` scope to unblock ALL deployment.

---

## Session 26 — 2026-02-26 08:00 UTC (Morning Health Check)

**Goal:** Morning health check, verify systems, push for production deploy.

### What Was Done

1. **Health check:**
   - Production: 2/2 pods running (5d20h uptime, zero restarts), 8/8 browser pages available
   - Staging: 1/1 pod running (17h uptime)
   - All pages returning 200 (landing, docs, legal pages)
   - Systems stable

2. **Investor Test:**
   1. Trust with money? **Mostly** — checkout works, Stripe webhook unregistered
   2. Data loss on crash? **No** — PostgreSQL
   3. Free tier abuse? **Low** — playground IP-limited + watermarked + URL capped
   4. Key recovery? **Yes on staging**, not in production
   5. Website features? **All working**

3. **No new development** — all remaining items blocked on external actions

**Assessment:** Staging (v0.5.2) has 6+ features/fixes over production (v0.4.3). Recommending production deploy.

---

## Session 25 — 2026-02-25 20:00 UTC (Health Check + Status Review)

**Goal:** Evening health check, run investor test, assess what's actionable.

### What Was Done

1. **Full health check:**
   - Production: 2/2 pods running, health OK, 8/8 browser pages available
   - Staging: 1/1 pod running, health OK
   - Test suite: 133 tests passing, 0 failures
   - All systems stable (pods running 5d8h without restart)

2. **Investor Test:**
   1. Trust with money? **Mostly** — checkout works, Stripe webhook still unregistered
   2. Data loss on crash? **No** — PostgreSQL with persistent storage
   3. Free tier abuse? **Low** — playground IP-limited + watermarked + URL length limit
   4. Key recovery? **Yes on staging**, not yet in production
   5. Website features? **All working on both environments**

3. **No actionable work this session** — all remaining items blocked on external actions:
   - Stripe webhook → needs dashboard access (investor)
   - Production deploy → needs investor approval for v0.5.x tag
   - CI/CD → needs Forgejo Actions runner configured

**Assessment:** Product is stable and feature-complete on staging. The gap between staging (v0.5.2) and production (v0.4.3) is growing — 6+ features/fixes waiting for promotion. Recommending production deploy approval.

---

## 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)

**Goal:** Verify system health, run investor test, request production deployment.

### What Was Done

1. **Full health check:**
   - Production: 2/2 pods running, health OK, 7/8 browser pages available, TLS valid
   - Staging: 1/1 pod running, health OK
   - Test suite: 129 tests passing, 0 failures
   - Playground: working (200, ~90KB screenshot returned)
   - Stripe checkout: working (generates valid checkout URL)

2. **Stripe webhook registration attempted:**
   - Tried to create webhook via API — BLOCKED (API key lacks `rak_webhook_write` permission)
   - Needs to be done from Stripe Dashboard or with a key that has webhook permissions

3. **CI/CD status:** Still blocked on Forgejo Actions runner (not configured on repo)

### Investor Test — Session 23
1. Trust with money? **Mostly** — checkout works, but webhook not registered means subscription lifecycle events (cancel/renew) won't be tracked
2. Data loss on crash? **No** — all in PostgreSQL
3. Free tier abuse? **Low** — playground IP-limited + watermarked + URL length limit
4. Key recovery? **YES on staging** (portal + recover endpoints), NO on production yet
5. Website features work? **Yes on prod** — landing page, playground, legal pages, pricing, checkout all verified

### Status
- **Production v0.4.3** — stable, healthy, all core flows work
- **Staging v0.5.1** — 6 features/fixes awaiting production deploy (GET endpoint, caching, key recovery, customer portal, bug fixes for FAQ/privacy/browser-restart/URL-limit)
- **Blockers:** Stripe webhook (needs dashboard access), CI/CD (needs Forgejo runner), production tag (needs investor approval)

---

## Session 22 — 2026-02-25 08:00 UTC (Customer Portal + Test Coverage Expansion)

**Goal:** Close key recovery gap (Investor Test #4), expand test coverage.

### What Was Done

1. **Stripe Customer Portal + Key Recovery (staging):**
   - POST /v1/billing/portal — creates Stripe billing portal session for subscription management
   - GET /v1/billing/recover — secure masked key lookup (no info leak on unknown emails)
   - /recovery.html — user-facing key recovery form with dark theme
   - "Lost your API key?" link added to landing page
   - New keys.ts functions: getKeyByEmail(), getCustomerIdByEmail()
   - 10 new billing tests (TDD: tests written first, then implementation)
   - Commit: c324366

2. **Comprehensive route-level tests (test-only, no prod code changes):**
   - health.test.ts, playground.test.ts, screenshot.test.ts, watermark.test.ts
   - Tests cover input validation, error handling, auth, rate limiting, SSRF blocking
   - Commit: a20828b

3. **Build fix:** Excluded test files from tsc build (commit b2688c0)

4. **Staging deployment:** Built image, transferred to workers, deployed with commit-hash tag.
   - Fixed k3s-mgr deploy key setup (was missing SSH config)
   - Learned: must use commit-hash image tags (deployment uses IfNotPresent + specific tags, not :latest)

5. **Test suite: 129 tests passing, 0 failures** (up from 61)

### Investor Test — Session 22
1. Trust? **Yes** — core flows work, playground demos well
2. Data loss on crash? **No** — all in PostgreSQL
3. Free tier abuse? **Low** — playground IP-limited + watermarked + URL length limit
4. Key recovery? **YES on staging** ✅ (was "Not yet" — now have /recover + /portal endpoints)
5. Website features work? **Yes** on production; staging has additional features pending deploy

### Staging vs Production Gap
Staging (v0.5.1) has 6+ features not in production (v0.4.3):
- GET endpoint, response caching, customer portal, key recovery, bug fixes (FAQ, privacy, browser restart, URL limit)
- Awaiting investor approval for production tag

---

## Session 21 — 2026-02-24 16:23 UTC (TDD: Lazy Stripe + Auth/Keys Tests)

**Goal:** Fix test suite (billing.ts crash) and add missing unit tests.

### What Was Done

1. **Fixed billing.ts Stripe crash** (commit f696cb3):
   - Module-level `new Stripe(process.env.STRIPE_SECRET_KEY!)` → lazy `getStripe()` function
   - Guarded `initPrices()` with env var check
   - api.test.ts now imports cleanly (shows SKIP, not FAIL)

2. **Added auth middleware tests** (`src/middleware/__tests__/auth.test.ts`, 6 tests):
   - 401 for missing key, 403 for invalid key
   - Key extraction from Bearer, X-API-Key, query param
   - Priority order: Bearer > X-API-Key > query

3. **Added keys service tests** (`src/services/__tests__/keys.test.ts`, 6 tests):
   - getTierLimit: all tiers + unknown tier + empty string

4. **Result: 61 tests passing, 1 skipped, 0 failures** ✅

### Note: CI/CD still blocked on Forgejo token — code pushed but staging won't auto-rebuild.

---

## Session 20 — 2026-02-24 16:16 UTC (Test Framework + TDD Foundation)

**Goal:** Establish test framework per new TDD mandate. Zero tests existed.

### What Was Done

1. **Test framework set up** — vitest (TypeScript-native, fast):
   - `npm test` / `npm run test:watch` scripts
   - vitest.config.ts with Node.js env

2. **SSRF validation tests** (30 tests) — `src/services/__tests__/ssrf.test.ts`:
   - Protocol rejection (javascript:, ftp:, data:, file:)
   - Private IP blocking (127.x, 10.x, 172.16-31.x, 192.168.x)
   - K8s DNS blocking, metadata IP blocking
   - URL length limit, empty/null rejection
   - DNS mocking with vi.mock()

3. **Cache service tests** (19 tests) — `src/services/__tests__/cache.test.ts`:
   - Hit/miss, TTL expiry, size eviction, bypass logic
   - Deterministic key generation, large item rejection

4. **Fixed integration test crash** — api.test.ts crashed on Stripe import without env vars, replaced with skip placeholder.

5. **Result: 49 tests passing, 1 skipped** — all green ✅

Commits: cda259a (tests), c3dabc2 (fix integration skip). Pushed to main.

### Investor Test — Session 20
Same as Session 18 — all passing, same gaps (Stripe webhook, key recovery).

---

## Session 19 — 2026-02-24 14:00 UTC (Error Handling Hardening)

**Goal:** Fix error status codes found during QA.

### What Was Done

1. **Fixed `javascript:` URLs returning 500 instead of 400:**
   - Changed SSRF error message to match catch pattern ("URL protocol not allowed")
   - Now returns 400 with clear message

2. **Fixed unresolvable hostnames returning 500 instead of 400:**
   - Added "Could not resolve" to error pattern matching in both playground and screenshot routes
   - Now returns 400 with "Could not resolve hostname"

3. **Commit b07b9cf, deployed to staging, all 3 test cases verified:**
   - `javascript:alert(1)` → 400 ✅
   - `https://nonexistent.host` → 400 ✅  
   - `https://example.com` → 200 ✅

### Production: Healthy, unchanged. Still awaiting v0.5.0 approval.

---

## Session 18 — 2026-02-24 11:00 UTC (QA + BUG-011 Fix)

**Goal:** Production QA, fix bugs found.

### What Was Done

1. **Full QA on production** (snapapi-qa-1):
   - 15 tests across desktop, mobile, all links, playground, legal pages, docs, security
   - Confirmed all previous bug fixes working in production
   - Zero console errors
   - 1 new bug found: BUG-011 (no URL length limit)

2. **Fixed BUG-011** — URL length limit:
   - Added 2048-char limit in SSRF validation
   - Returns 400 with clear error message
   - Commit 5ec8c92, deployed to staging, verified

### Investor Test — Session 18
1. Trust? **Yes** — QA confirmed core flows work
2. Data loss on crash? **No**
3. Free tier abuse? **Low** — 5/hr IP limit + watermark + now URL length limit
4. Key recovery? **Not yet** (needs Stripe portal)
5. Website features work? **Yes** — QA verified all 15 test areas

### QA Summary
- 15 tests passed, 1 new bug found and fixed (staging)
- Overall: CONDITIONALLY READY (pending prod deploy of accumulated fixes)

---

## Session 17 — 2026-02-24 08:00 UTC (GET Endpoint + Response Caching)

**Goal:** Add competitive features — GET endpoint for image embedding, response caching.

### What Was Done

1. **GET /v1/screenshot endpoint** (staging):
   - All params via query string, auth via `?key=` param
   - Enables `<img src="https://snapapi.eu/v1/screenshot?url=...&key=...">` embedding
   - Updated auth middleware, OpenAPI docs

2. **In-memory LRU response cache** (staging):
   - SHA256 cache key from URL + all params
   - 5-min default TTL (`CACHE_TTL_MS`), 100MB max (`CACHE_MAX_MB`)
   - `X-Cache: HIT/MISS` response headers
   - Bypass via `?cache=false` or `cache: false` in POST body
   - Auto-eviction when memory limit reached

3. **Landing page updated** (staging):
   - Added GET/Embed code tab with `<img>` embedding example
   - Added "Response Caching" and "GET Request Support" feature cards

4. **Deployed to staging** — commit `44e31e3`, verified healthy

### Investor Test — Session 17
1. Would a stranger trust this? **Yes** — production works, playground demos well
2. Pod crash data loss? **No** — all in PostgreSQL
3. Free tier abuse? **Low risk** — playground is IP-limited, watermarked
4. Key recovery? **Not yet** — needs Stripe customer portal
5. Website features work? **Yes** on production (staging has more features pending deploy)

### Pending Investor Decisions (unchanged)
- Tag v0.5.0 for production (includes: GET endpoint, caching, SDK tabs, bug fixes for FAQ/privacy/browser restart)
- Register Stripe webhook URL
- Forgejo token for CI/CD
- DNS for staging.snapapi.eu

---

## Session 16b — 2026-02-23 20:00 UTC (Skipped)

Skipped — 3 reports already sent today (08:00, 14:00, 17:00). Production healthy. No investor responses. No new work.

---

## Session 16 — 2026-02-23 17:00 UTC (Landing Page SDK Showcase + Deploy)

**Goal:** Deploy SDK code examples to landing page, get image onto staging.

### What Was Done

1. **Landing page updated with tabbed code examples:**
   - Hero code block now has 3 tabs: cURL, Node.js, Python
   - Shows `npm install snapapi` / `pip install snapapi` with usage examples
   - CSS for tab styling, JS for tab switching
   - Commit: `253d03f`

2. **Built and deployed to staging:**
   - Docker image built on k3s-mgr
   - Transferred to both workers (k3s-w1 @ 10.0.1.6, k3s-w2 @ 10.0.1.7) via docker save | ctr import
   - Staging deployment updated, verified: 9 code-tab elements, switchCodeTab function, npm/pip references

3. **Documented image transfer process:**
   - k3s-mgr has docker, workers use containerd via k3s
   - `docker save <img> | ssh <worker-ip> "k3s ctr images import -"`
   - Worker IPs: 10.0.1.6 (w1), 10.0.1.7 (w2)
   - App listens on port 3100 (not 3000)

### Note for Future Sessions
- Worker hostnames (k3s-w1, k3s-w2) don't resolve from k3s-mgr — use IPs
- App port is 3100, container port mapping handles 3000→3100

---

## Session 15 — 2026-02-23 14:00 UTC (SDKs + Competitive Analysis)

**Goal:** Proactive work — competitive analysis and SDK development.

### What Was Done

1. **Competitive analysis** (saved to `memory/competitive-analysis.md`):
   - Researched top 7 screenshot APIs (CaptureKit, ScreenshotOne, ScreenshotAPI.net, ApiFlash, etc.)
   - Our €9/1K pricing is competitive; EU-hosting is our unique differentiator
   - Key gaps vs competition: no SDKs, no caching, no cookie banner blocking, no PDF export

2. **Node.js SDK created** (`sdk/node/`):
   - TypeScript source with full type definitions
   - ESM + CJS dual output
   - Zero dependencies (uses native `fetch`)
   - `snap.capture(url, options)` and `snap.health()` methods
   - Full README with examples

3. **Python SDK created** (`sdk/python/`):
   - Zero dependencies (uses `urllib`)
   - Python 3.8+ compatible
   - Pythonic snake_case API with dataclass options
   - Full README with examples

4. **Pushed to Forgejo** — commit `66ecc47`

### Investor Test — Session 15
Same as Session 14 — all passing, same gaps.

### Still Pending Investor Decisions (unchanged)
- Tag v0.4.4+ for production
- Stripe webhook URL registration
- Forgejo token (CI/CD)
- DNS for staging.snapapi.eu

---

## Session 14 — 2026-02-23 (Monday Health Check)

**Goal:** Monday check-in — verify production health, look for actionable improvements.

### What Was Done

1. **Production health verified:**
   - Both pods running (k3s-w1, k3s-w2), 2d20h uptime, 0 restarts
   - Health endpoint: OK, 8/8 browser pages available, 0 queue depth
   - Playground tested: 200 OK
   - All 10 pages return 200 (/, /docs, /health, /impressum.html, /privacy.html, /terms.html, /status.html, /openapi.json, /robots.txt, /sitemap.xml)

2. **Investigated empty OpenAPI paths on production:**
   - Root cause confirmed: prod image (v0.4.3) has `apis: ["./src/routes/*.ts"]` but `./src/` doesn't exist in Docker container
   - Already fixed on staging (commit `d20fbbf` added `./dist/routes/*.js` glob)
   - Staging OpenAPI spec correctly returns all 8 endpoint paths

3. **Confirmed BUG-010 still affects production:**
   - `/privacy`, `/terms`, `/impressum` return 404 (extensionless URLs)
   - Already fixed on staging (commit `db1fa8d`)

4. **No new work spawned** — all actionable items remain blocked on investor decisions.

### Investor Test — Session 14
1. **Trust with money?** → YES (product works, playground demos well)
2. **Pod crash data loss?** → No (PostgreSQL, no in-memory state)
3. **Free tier abuse?** → Protected (5/hr/IP playground limit)
4. **Key recovery?** → Via Stripe (when webhook registered)
5. **Website features work?** → Core works; legal page URLs without .html extension 404 on prod (fixed on staging)

### Pending Investor Decisions (unchanged)
- **Tag v0.4.4+ for production** — fixes: browser restart 503s (BUG-007), FAQ accordion (BUG-008), copy improvement (BUG-009), privacy 404 (BUG-010), OpenAPI paths, SEO fundamentals
- **Stripe webhook URL** registration in dashboard
- **Forgejo token** with write:repository scope (CI/CD)
- **DNS for staging.snapapi.eu**

---

## Session 13 — 2026-02-22 (Sunday Health Check)

**Goal:** Sunday check-in — verify production health.

### What Was Done

1. **Production health verified:**
   - Both pods running (k3s-w1, k3s-w2), 44h uptime, 0 restarts
   - Health endpoint: OK, 8/8 browser pages available, 0 queue depth
   - Playground tested: 200 OK, 95KB screenshot in 2.8s
   - All systems nominal

2. **No new work spawned** — all actionable items blocked on investor decisions (unchanged from Session 12).

### Investor Test — Session 13
1. **Trust with money?** → YES
2. **Pod crash data loss?** → No
3. **Free tier abuse?** → Protected (5/hr/IP playground limit)
4. **Key recovery?** → Via Stripe (when webhook registered)
5. **Website features work?** → All work; BUG-007/008/009 fixes on staging awaiting prod tag

### Pending Investor Decisions (unchanged)
- **Tag v0.4.4+ for production** — BUG-007 (browser 503s), BUG-008 (FAQ), BUG-009 (copy), SEO
- **Stripe webhook URL** registration in dashboard
- **Forgejo token** with write:repository scope (CI/CD)
- **DNS for staging.snapapi.eu**

---

## Session 12 — 2026-02-21 (Health Check + Status Review)

**Goal:** Saturday check-in — verify production health, assess readiness.

### What Was Done

1. **Production health verified:**
   - Both pods running (k3s-w1, k3s-w2), 20h uptime, 0 restarts
   - Health endpoint: OK, 8/8 browser pages available, 0 queue depth
   - Playground tested: 200 OK, returned 95KB screenshot
   - Landing page loads correctly with all content

2. **No new work spawned** — all actionable improvements are on staging awaiting investor approval for production tag.

### Investor Test — Session 12
1. **Trust with money?** → YES
2. **Pod crash data loss?** → No
3. **Free tier abuse?** → Protected (5/hr/IP)
4. **Key recovery?** → Via Stripe (when webhook registered)
5. **Website features work?** → All work, BUG-007/008 still affect prod

### Pending Investor Decisions (unchanged)
- **Tag v0.4.4+ for production** — includes BUG-007 fix (browser restart 503s), BUG-008 fix (FAQ), BUG-009 fix (copy), SEO additions
- **Stripe webhook URL** registration in dashboard
- **Forgejo token** with write:repository scope (CI/CD)
- **DNS for staging.snapapi.eu**

## Session 11 — 2026-02-20 (SEO + Stripe Webhook Attempt)

**Goal:** Add SEO fundamentals, attempt Stripe webhook registration.

### What Was Done

1. **SEO fundamentals added** (snapapi-seo specialist):
   - `robots.txt` — allows marketing pages, blocks API routes
   - `sitemap.xml` — all public pages
   - Open Graph & Twitter meta tags on landing page
   - JSON-LD structured data (SoftwareApplication schema with pricing)
   - Canonical URL
   - Proper 404 page (dark theme, HTTP 404 status)
   - Commit: `abf66d80` — pushed to Forgejo
   - Staging deployment in progress (Docker image transfer slow)

2. **Stripe webhook registration attempted** — API key lacks `rak_webhook_write` permission. Still needs investor action.

3. **Tried to check CI/CD runner status** — Forgejo API doesn't expose runner info at repo level. Unknown if runner is configured.

### Investor Test — Session 11
1. **Trust with money?** → YES, professional product with legal compliance and SEO
2. **Pod crash data loss?** → No
3. **Free tier abuse?** → Protected (playground rate limited)
4. **Key recovery?** → Via Stripe (when webhook registered)
5. **Website features work?** → All work, BUG-007 still affects prod intermittently

### Remaining Investor Actions (unchanged)
- Tag v0.4.4+ for production (includes browser fix, FAQ fix, rate-limit copy fix)
- Forgejo token with write:repository scope
- DNS for staging.snapapi.eu
- Stripe webhook URL registration (or grant webhook_write to API key)
- UptimeRobot account

## Session 9 — 2026-02-20 (Browser Fix + CI/CD Attempt)

**Goal:** Fix production reliability bug, set up CI/CD pipeline.

### What Was Done

1. **BUG-007 Fixed: Simultaneous browser restart** (snapapi-browser-fix specialist):
   - Root cause: Both browsers hit `RESTART_AFTER_MS` simultaneously, causing 0 capacity for ~4s
   - Fix: Staggered `lastRestartTime` per browser + one-at-a-time restart guard
   - Commit: `e49c4073` — deployed to staging, verified playground returns 200
   - **Needs production tag to fix in prod** (currently affects prod every ~1hr)

2. **CI/CD pipeline partially set up** (snapapi-cicd-setup specialist):
   - Updated `.forgejo/workflows/deploy.yml` and `promote.yml` with working kubectl deployment steps
   - Created deployer SA with RBAC for both namespaces
   - Generated deployer kubeconfig with 10-year token
   - **BLOCKED:** Forgejo API token only has read scope, can't add secrets. Needs `write:repository` scope.
   - REGISTRY_TOKEN secret already exists (from previous session)
   - KUBECONFIG secret still missing

3. **Staging TLS investigation:**
   - Certificate stuck for 21h — `staging.snapapi.eu` has no DNS record
   - Needs investor to add DNS A record

### Investor Test — Session 9
1. **Trust with money?** → YES, professional product, but playground has intermittent 503 (BUG-007 in prod)
2. **Pod crash data loss?** → No, PostgreSQL is separate
3. **Free tier abuse?** → Playground rate-limited to 5/hr/IP, no free API keys
4. **Key recovery?** → Via Stripe customer portal (when webhook is registered)
5. **Website features work?** → All pages work, playground intermittently fails due to BUG-007

### Open Issues
- BUG-007 fix on staging only — needs prod tag
- Stripe webhook URL not registered
- CI/CD blocked on Forgejo token scope
- staging.snapapi.eu DNS missing
- No external uptime monitoring

## Session 8 — 2026-02-19 (Git Sync + CI/CD Prep + Checkout Verification)

**Goal:** Housekeeping — sync repo, prepare CI/CD credentials, verify checkout flow.

### What Was Done
1. **Git repo synced to v0.4.3** — Legal pages (impressum, privacy, terms) were deployed but not in repo. Specialist extracted from prod pod and pushed to Forgejo. Verified: all files present.
2. **Deployer kubeconfig created** — Created long-lived SA token for CI/CD, built kubeconfig, tested it (lists pods successfully). Base64-encoded and ready for Forgejo secret.
3. **Stripe checkout verified** — POST /v1/billing/checkout returns live Stripe checkout URL for all plans. End-to-end payment flow works (minus webhook for key provisioning).

### Investor Test — Session 8
All same as Session 7. Product is launch-ready pending webhook registration.

### No new bugs.

## Session 7 — 2026-02-19 (Code to Forgejo + Legal Pages)

**Goal:** Push codebase to Forgejo repo and add legally required pages.

### What Was Done

1. **Codebase pushed to Forgejo** (snapapi-cicd-1 specialist):
   - Extracted complete source from running staging pod
   - Created proper Dockerfile, .gitignore, CI/CD workflows
   - Pushed 28 files to `openclawd/SnapAPI` on Forgejo
   - Commit: `b58f634` — "feat: initial codebase v0.4.1"
   - Includes `.forgejo/workflows/deploy.yml` and `promote.yml`
   - Verified via Forgejo API — all files present

2. **Legal pages added** (snapapi-legal-1 specialist):
   - `/impressum.html` — Austrian §5 ECG compliance (company info, FN, VAT, management)
   - `/privacy.html` — Full GDPR privacy policy (data collected, legal basis, retention, rights)
   - `/terms.html` — Terms of Service (acceptable use, rate limits, liability, Austrian law)
   - All pages: dark theme matching site, responsive, proper nav/footer
   - Landing page footer updated with legal page links
   - Built v0.4.3 and deployed to prod (2 replicas) + staging

3. **CEO verification**:
   - Playground test: ✅ (200, 90KB, 2s response, watermark, rate limit headers)
   - Health check: ✅
   - All legal pages: ✅ (200)
   - Swagger docs: ✅ (200)
   - Status page: ✅ (200)
   - HA: pods on k3s-w1 and k3s-w2 ✅

### Investor Test — Session 7
1. **Would a stranger trust this product with their money?**
   → YES. Professional landing page, working playground, Stripe checkout, interactive docs, full legal compliance (Impressum, Privacy, ToS).

2. **If a pod crashed, would we lose customer data?**
   → NO. PostgreSQL external, usage flushes every 5s.

3. **Could someone abuse the free tier?**
   → NO FREE TIER. Playground: 5/hr per IP, watermarked.

4. **Can a paying customer recover a lost API key?**
   → Not yet — needs Stripe customer portal. Customer can email for support.

5. **Does every feature on the website actually work?**
   → YES. Playground, checkout, docs, status, legal pages — all verified.

### Remaining
- Register Stripe webhook in Dashboard (investor action)
- CI/CD secrets in Forgejo (KUBECONFIG, REGISTRY_TOKEN)
- External uptime monitoring
- Staging DNS + TLS

## Session 4 — 2026-02-19 (Emergency Bug Fix)

**Trigger:** Investor tested site himself and found 3 critical bugs that previous QA missed.

**Root Cause:** Helmet CSP default `script-src-attr 'none'` was blocking ALL inline event handlers (onclick, onsubmit). This broke signup, playground, mobile nav, and FAQ toggles. Previous QA only checked if pages loaded — never actually clicked anything.

**Bugs Fixed (v0.2.3):**
1. **BUG-004 (CRITICAL):** CSP blocking inline handlers → Added `scriptSrcAttr: ['unsafe-inline']`
2. **BUG-005 (HIGH):** Mobile nav `.show` class had no CSS → Added flex display rules
3. **BUG-006 (MEDIUM):** Signup links `href="#"` scrolling to top → Changed to `javascript:void(0)`
4. Also added `blob:` to imgSrc CSP for playground screenshot display

**Personally Verified (browser testing):**
- ✅ "Get Free API Key" button opens signup modal (desktop)
- ✅ Email signup generates API key successfully
- ✅ Playground takes screenshot and displays result
- ✅ Mobile hamburger menu opens and shows all nav links
- ✅ Zero console errors on new deployment

**Deployed:** v0.2.3 to production (2 replicas), images distributed to all 3 nodes

**Lesson:** Never trust QA that doesn't actually click through flows with a real browser. CSP issues are invisible unless you interact with elements.

## Session 1 — 2026-02-18

**Goal:** Build core SnapAPI from scratch and deploy to cluster.

### What Was Done
1. **Studied DocFast patterns** — reviewed all key files (index.ts, db.ts, keys.ts, browser.ts, auth.ts, usage.ts, Dockerfile, CI/CD workflows)
2. **Built complete SnapAPI application:**
   - Express + TypeScript + Puppeteer screenshot service
   - SSRF protection (blocks private IPs, metadata endpoints, K8s DNS)
   - Browser pool (configurable count × pages, auto-recycling)
   - PostgreSQL integration (api_keys + usage tables, retry logic)
   - Auth middleware (Bearer token or X-API-Key)
   - Usage tracking with per-key monthly limits
   - Free signup endpoint
   - Landing page with docs, features, pricing
   - CI/CD workflow files (deploy.yml + promote.yml)
3. **Docker image built** on k3s-mgr (ARM64, ~1.2GB with Chromium)
4. **Deployed to staging** (snapapi-staging namespace, 1 replica)
5. **Verified working:**
   - Health check: ✅
   - Free signup: ✅ (returns API key)
   - Screenshot: ✅ (200, 18KB PNG of example.com)

### Blockers Encountered
- **Forgejo read-only token:** Could not push code to repo or push Docker image to registry. Had to build image directly on k3s-mgr and import via containerd (docker save | k3s ctr images import)
- **No domain:** Can't set up Traefik IngressRoute or production deployment

### Image on workers
- Imported manually via `docker save | ssh | k3s ctr images import` to both k3s-w1 and k3s-w2
- Uses `imagePullPolicy: IfNotPresent` since image is pre-loaded

## Session 2 — 2026-02-19

**Goal:** CI/CD pipeline, TLS, staging ingress, code review, bug fixes.

### What Was Done
1. **Production deployment created** — 2 replicas with HA (anti-affinity, tolerations)
2. **TLS certificate** — Let's Encrypt on snapapi.eu via cert-manager ✅
3. **Staging ingress** — Created for staging.snapapi.eu (pending DNS record)
4. **BUG-001 fixed** — Cache-aside key lookup for multi-replica support
   - Keys now fall back to DB when not in memory cache
   - Verified: 6/6 requests succeed after fresh signup
5. **Code review** — Reviewed all source files, found good SSRF protection, solid patterns
6. **Image v0.1.1 built and deployed** to both staging and production
7. **k3s-mgr SSH access to workers** — Added k3s-mgr pubkey to worker authorized_keys for future image transfers
8. **CI/CD workflow files** — Already written (deploy.yml + promote.yml), match DocFast pattern

### Blockers Encountered
- **Cannot push code to Forgejo repo** — FORGEJO_TOKEN is read-only (no write:repository scope)
- **SSH port 2222 unreachable** — From both k3s-mgr and openclaw VM, so deploy key is useless
- **No staging DNS** — staging.snapapi.eu has no A record, cert-manager can't issue TLS
- Code lives on k3s-mgr at `/tmp/snapapi-build` — needs to be pushed to repo for CI/CD

### Investor Action Required
1. Create Forgejo API token with `write:repository` and `write:package` scopes for `openclawd`
2. Add DNS record: `staging.snapapi.eu` → `46.225.37.135` (same LB as production)
3. Either expose Forgejo SSH on port 2222 externally OR provide write token (option 1 preferred)

### Investor Test — Session 2

1. **Would a stranger trust this product with their money right now?**
   → NO. Free tier works well (signup → key → screenshot in seconds). But no paid tiers exist yet, no email verification, and the landing page has no Impressum/legal pages. Functional but not trustworthy for paid use.

2. **If a pod crashed, would we lose customer data?**
   → NO. All data is in PostgreSQL (external to pods). In-memory key cache rebuilds from DB on startup. Usage data flushes every 5 seconds. Maximum loss: ~5 seconds of usage counters.

3. **Could someone abuse the free tier right now?**
   → PARTIALLY. Same email returns same key (good). But no email verification means someone could generate unlimited keys with fake@emails. Rate limiting at 120 req/min per IP helps but doesn't fully prevent abuse.

4. **Can a paying customer recover a lost API key?**
   → NO. No key recovery flow. No email verification to prove ownership. This needs fixing before paid launch.

5. **Does every feature on the website actually work?**
   → YES for what's shown. Screenshot API works, signup works, docs are accurate. Pricing section shows plans but there's no actual payment flow yet.

**Honest Assessment:** The product WORKS for free tier users. The API is solid, SSRF protection is good, multi-replica cache bug is fixed. But NOT launch-ready for paid tiers. Still an impressive MVP for 2 sessions of work.

## Session 3 — 2026-02-19

**Goal:** Address investor feedback — redesign landing page, add Swagger docs, QA testing.

### What Was Done
1. **Complete landing page redesign** — Professional SaaS design inspired by screenshotone.com:
   - Hero section with gradient text, animated badge, trust badges
   - 6-card feature grid with icons
   - "How it works" 3-step section
   - EU/GDPR compliance section with checklist
   - Live API playground (enter URL, get screenshot)
   - Premium pricing cards with "Most Popular" badge
   - FAQ accordion section
   - Professional footer with links grid
   - CTA section with gradient border box
   - Mobile responsive (tested at 375px)
   - Fixed curl example (was snapapi.dev, now snapapi.eu)

2. **Swagger/OpenAPI interactive docs at /docs**:
   - OpenAPI 3.0.3 specification at /openapi.json
   - Swagger UI with dark theme at /docs
   - Full API documentation with examples, parameters, error codes
   - "Try it out" functionality enabled
   - Auth support (Bearer token + X-API-Key)
   - Per-route CSP to allow Swagger external resources

3. **QA Testing — All Passed**:
   - Health check: ✅ (200, browser pool info)
   - Signup: ✅ (returns API key)
   - Screenshot: ✅ (200, 18KB PNG)
   - /docs: ✅ (Swagger UI loads, interactive)
   - /openapi.json: ✅ (valid spec)
   - Mobile responsive: ✅
   - No console errors on landing page

4. **Built and deployed v0.2.1** to both prod (2 replicas) and staging

### Bugs Found During QA
- No new bugs found. Existing BUG-002 and BUG-003 still open.

### Investor Test — Session 3

1. **Would a stranger trust this product with their money right now?**
   → GETTING THERE. Landing page now looks professional and trustworthy. EU/GDPR prominently featured. Swagger docs add credibility. But still no paid tiers or email verification.

2. **If a pod crashed, would we lose customer data?**
   → NO. PostgreSQL external to pods, usage data flushes every 5s.

3. **Could someone abuse the free tier right now?**
   → PARTIALLY. Same mitigation as before — email dedup, rate limiting.

4. **Can a paying customer recover a lost API key?**
   → NO. Still needs email verification (BUG-003).

5. **Does every feature on the website actually work?**
   → YES. All displayed features work. Playground works for users with API keys. Swagger docs are interactive and functional.

**Honest Assessment:** Major UX improvement. The site now looks like a real product. Swagger docs address the investor's API documentation concern. Free tier is fully functional. Not yet launch-ready for paid tiers, but significantly more credible.

## Session 5 — 2026-02-19 (Strategic Pivot: Playground-Only Free Demo)

**Trigger:** Investor decision — remove free API keys, playground-only demo with watermark.

### What Was Done
1. **Removed free signup entirely** — `/v1/signup/free` endpoint removed from routes and index.ts
2. **Created playground endpoint** (`/v1/playground`):
   - No authentication required
   - IP-based rate limiting: 5 requests/hour per IP
   - Capped resolution at 1920x1080 for playground
   - Returns watermarked screenshots
3. **Created watermark service** (`src/services/watermark.ts`):
   - Uses Puppeteer to composite watermark over screenshot
   - Large diagonal text: "snapapi.eu — upgrade for clean screenshots"
   - Semi-transparent white text with shadow, rotated -30°
4. **Updated landing page completely**:
   - Playground moved to hero position (right after stats)
   - Playground calls `/v1/playground` directly (no auth needed)
   - All signup modals and signup JS removed
   - "Get API Key" buttons now link to #pricing
   - Hero messaging updated: "Try it free in the playground — no signup needed"
   - Trust badge changed from "No Credit Card Required" to "No Signup to Try"
   - Pricing section: 3 paid plans only (Starter €9, Pro €29, Business €79) — no free tier
   - "How it works" updated: Try Playground → Get API Key → Clean Screenshots
   - FAQ updated with playground vs paid API question
   - CTA section updated with playground + pricing buttons
5. **Updated OpenAPI spec** (v0.3.0) — removed signup endpoint, added playground endpoint
6. **Built and deployed v0.3.0** to both prod (2 replicas) and staging
7. **Closed BUG-002 and BUG-003** (no longer applicable without free tier)

### QA Verified (Real Browser Testing)
- ✅ Landing page loads with new design
- ✅ Playground "Take Screenshot" button works (no auth needed)
- ✅ Screenshot appears with visible watermark
- ✅ Zero console errors
- ✅ Mobile responsive (375px)
- ✅ Hamburger menu works on mobile
- ✅ All nav links correct ("Get API Key" → #pricing)
- ✅ Free signup endpoint returns 404
- ✅ Swagger docs still work (/docs, /openapi.json)
- ✅ Health check passing
- ✅ Playground rate limit header present (5/hr)
- ✅ Watermark clearly visible on playground output

### Investor Test — Session 5
1. **Would a stranger trust this product with their money right now?**
   → ALMOST. Site looks professional, playground lets them try before buying. But paid plans still show "Coming Soon" — need Stripe integration.
2. **If a pod crashed, would we lose customer data?**
   → NO. PostgreSQL external, usage flushes every 5s.
3. **Could someone abuse the free tier right now?**
   → NO FREE TIER. Playground is rate limited (5/hr per IP) and watermarked. Much harder to abuse.
4. **Can a paying customer recover a lost API key?**
   → N/A yet — no paid customers. Will be via Stripe portal.
5. **Does every feature on the website actually work?**
   → YES. Playground works, all links work, all sections function. Paid plans correctly show "Coming Soon".

**Honest Assessment:** Massive simplification. The product is now much cleaner — playground for testing, pay for clean API. No more free tier abuse vectors. Ready for Stripe integration as next step.

## Session 6 — 2026-02-19 (Stripe Billing + Status Page)

**Goal:** Integrate Stripe billing to enable paid subscriptions. Add status page.

### What Was Done
1. **Stripe billing integration (v0.4.0→v0.4.1):**
   - Added `stripe` npm dependency
   - Created `src/routes/billing.ts` — checkout, success page, webhook handler
   - 3 Stripe products created: Starter (€9), Pro (€29), Business (€79)
   - Product IDs: `prod_U0YOVzPDAht9eH`, `prod_U0YOlQO6hAF7Tg`, `prod_U0YOSor6qXhHs8`
   - Full checkout flow: landing page → Stripe Checkout → success page with API key
   - Webhook handles subscription lifecycle (create, cancel, delete, email sync)
   - Shared Stripe account filtering (ignores DocFast events)
   - Updated `src/services/keys.ts` with `createPaidKey()`, `downgradeByCustomer()`, `updateEmailByCustomer()`
   - Updated landing page: "Coming Soon" buttons → working "Get Started" checkout buttons
   - Raw body middleware for webhook signature verification

2. **Status page:**
   - Created `public/status.html` — self-contained, dark theme, auto-refresh 30s
   - Created `src/routes/status.ts` — serves status page
   - Shows API status, response time, browser pool, uptime, last checked

3. **Deployed v0.4.1** to staging (verified) then production (2 replicas)

### QA Verified
- ✅ Health check passing
- ✅ Checkout endpoint returns Stripe URLs for all 3 plans
- ✅ Browser test: "Get Started" button → Stripe Checkout page loads correctly
- ✅ Status page loads at /status
- ✅ Stripe products auto-discovered on startup (logs confirmed)

### Investor Test — Session 6
1. **Would a stranger trust this product with their money right now?**
   → YES. Professional landing page, working playground demo, Stripe checkout with real payment processing. EU-hosted, GDPR section prominent.

2. **If a pod crashed, would we lose customer data?**
   → NO. PostgreSQL external to pods. Usage flushes every 5s.

3. **Could someone abuse the free tier right now?**
   → NO FREE TIER. Playground is rate limited (5/hr per IP) and watermarked.

4. **Can a paying customer recover a lost API key?**
   → Not yet — needs Stripe customer portal integration. Customer can contact support.

5. **Does every feature on the website actually work?**
   → YES. Playground works, all 3 checkout buttons work, Swagger docs work, status page works.

### Action Required from Investor
1. Register Stripe webhook URL in Stripe Dashboard: `https://snapapi.eu/v1/billing/webhook`
   Events: `checkout.session.completed`, `customer.subscription.updated`, `customer.subscription.deleted`, `customer.updated`
