{"slug":"small-business-builder","total":18,"limit":100,"offset":0,"since":null,"commits":[{"hash":"a21cd75","date":"2026-07-22 21:47:02 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-22T21:46:55 (1 files) — package-lock.json","body":""},{"hash":"8f61557","date":"2026-07-22 21:42:17 -0700","author":"Steve Abrams","subject":"chore: v0.1.1 (barber.aa PUBLIC_HOSTS, session close)","body":""},{"hash":"3e1c27e","date":"2026-07-22 20:13:14 -0700","author":"Steve Abrams","subject":"add barber.agentabrams.com to PUBLIC_HOSTS (directory renamed from livesiteaudit.aa)","body":""},{"hash":"669babf","date":"2026-07-17 19:47:38 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-17T19:47:29 (1 files) — data/wa-screenshots/fantaseayachts-com.png","body":""},{"hash":"e704581","date":"2026-07-03 08:08:17 -0700","author":"Steve","subject":"chore: macstudio3 migration — reconcile from mac2 + repoint paths (stevestudio2→macstudio3, node/npm/npx→/opt/homebrew)","body":""},{"hash":"82a9729","date":"2026-06-24 15:33:59 -0700","author":"Steve Abrams","subject":"website-analysis: fix public-host critique page — whitelist screenshot+deep-dive, hide SHIP on public host (fantasea.agentabrams.com)","body":""},{"hash":"0a5f356","date":"2026-06-24 15:28:04 -0700","author":"Steve Abrams","subject":"auto-save: 2026-06-24T15:27:54 (1 files) — src/server/index.js","body":""},{"hash":"771aaa9","date":"2026-05-31 00:05:23 -0700","author":"SteveStudio2","subject":"fix: add rel=\"noopener noreferrer\" to target=_blank links missing it","body":"Three anchor elements in src/server/index.js (build URL kv-row, wa peek\ndrawer FULL link) and five Quick Open sidebar links in\nsrc/render/builds-index.js were missing rel=\"noopener noreferrer\",\nexposing opener context to cross-origin pages. All fixed; syntax clean.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"},{"hash":"dadcde3","date":"2026-05-13 08:58:02 -0700","author":"Steve","subject":"snapshot: 66 file(s) changed, +54 new, ~12 modified","body":""},{"hash":"783c9b7","date":"2026-05-12 16:53:32 -0700","author":"Steve","subject":"qa click-through: log session-minutes to cost-tracker via shared helper","body":""},{"hash":"a3c524f","date":"2026-05-07 12:29:31 -0700","author":"Steve","subject":"tighten .gitignore: add missing standing-rule patterns (dist/ build/ .next/)","body":""},{"hash":"5aaf4a3","date":"2026-05-06 12:50:30 -0700","author":"SteveStudio2","subject":"fix(ops): port hawk to sf-style pm2-jlist pattern — old curl-only hawk had wrong /opt/homebrew/bin/pm2 path so it logged 'No such file' every fire and silently failed","body":""},{"hash":"c6fa785","date":"2026-05-04 21:56:41 -0700","author":"SteveStudio2","subject":"deploy: ship smb-builder to Kamatera + capture full schema in migrations 002-008","body":"migrations 002-008 capture all tables that drifted into local DB ad-hoc.\nAll use IF NOT EXISTS so re-running on a populated DB is a no-op.\nValidated end-to-end against a fresh smb_migration_test DB -> 13 tables, all clean.\n\nscripts/deploy-kamatera.sh: idempotent 6-step rsync->createdb->migrate->.env->pm2.\nADMIN_TOKEN piped via stdin (never lands in argv / ps / shell history).\n\nLive at http://45.61.58.125:9760 (no public domain yet)."},{"hash":"41c8a33","date":"2026-05-04 13:01:26 -0700","author":"SteveStudio2","subject":"[morning-review] small-business-builder: gate interview admin + whitelist QA keys + UI/render hardening","body":"Critical:\n- Gate GET /biz/:slug/interview and /interview/live behind ADMIN_TOKEN\n  (POST already gated); adds shared requireAdmin() helper.\n- Whitelist incoming qa keys against QUESTIONS ids before persisting,\n  so attackers can't balloon JSONB or inject collision keys.\n\nHigh:\n- Cast $2::jsonb on interview INSERT to avoid pg-driver double-encode.\n- profile.js: white-space:pre-wrap on .qa .a so multi-paragraph answers\n  render with linebreaks intact.\n- profile.js: form maxlength now uses q.max_chars (was *2), aligning\n  the soft limit with what the server keeps.\n\nMedium:\n- profile.js: format recorded_at in UTC so \"Recorded January 2026\"\n  doesn't flicker by host TZ.\n- profile.js: new safeHref() validates http(s) scheme on b.website\n  before rendering as href or schema.org url (blocks javascript: XSS).\n- profile.js: coerce qa_json from string when legacy rows stored JSON\n  text rather than a jsonb object.\n- server/index.js: /n/:slug uses slugify() rather than an inline regex,\n  matching the slugs emitted in links.\n- interview-questions.js: localizeQuestion substitutes [neighborhood]\n  across every string field, not just q + placeholder."},{"hash":"b789cdc","date":"2026-05-04 12:51:11 -0700","author":"SteveStudio2","subject":"[morning-review] small-business-builder: harden public profile + interview API","body":"- Strip third-party mcp.figma.com/capture.js from public home + profile pages\n- Escape JSON-LD payloads so user answers can't break out of <script> (XSS)\n- Wrap new URL(b.website) so scheme-less domains don't 500 the profile route\n- Gate POST /api/biz/interview behind ADMIN_TOKEN cookie + admin_token field;\n  reject Array qa payloads, accept urlencoded qa_<id> for no-JS form fallback,\n  redirect non-JSON callers, trim history to 5 most-recent rows per business\n- Cap homepage SELECT at 200 rows; replace /n/:slug full-table scan with\n  WHERE neighborhood=$1 + DISTINCT slug resolution; 409 on slug collisions\n- Guard Number.isFinite on years_in_business, recorded_at date format,\n  empty hoodSlug links, NaN max_chars in interview form\n- Move interview-form submit button inside <form> so no-JS submit + a11y work\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"035afe2","date":"2026-05-04 10:20:20 -0700","author":"yolo","subject":"yolo: iter 3 trivial patches from claude-codex debate","body":""},{"hash":"980062b","date":"2026-05-04 09:06:47 -0700","author":"yolo","subject":"yolo: iter 2 trivial patches from claude-codex debate","body":""},{"hash":"ff56b97","date":"2026-05-03 23:46:26 -0700","author":"local","subject":"yolo: baseline before overnight","body":""}]}