85 Commits

Author SHA1 Message Date
Garfield
87b2fc074b docs(runbooks): update fix log with Gitea install lock, image upgrade, and push steps
Some checks are pending
CI / test (push) Waiting to run
2026-06-14 12:45:44 -04:00
Garfield
0e255e570a docs(runbooks): add 2026-06-14 public edge outage RCA, fix log, infra findings, debt, and monitoring plan
Some checks failed
CI / test (push) Has been cancelled
2026-06-14 12:26:34 -04:00
Garfield
2014e03190 fix(oauth): include state in /oauth/connect-claude-ai flow
Claude.ai's MCP auth callback requires a state parameter. Generate a random
state in /oauth/connect-claude-ai and preserve it through the consent form
and login redirect so it is echoed back to claude.ai.
2026-06-12 15:09:19 -04:00
Garfield
f084be6bc6 fix(oauth): register Anthropic Claude.ai redirect_uri for browser MCP flow
Add https://claude.ai/api/mcp/auth_callback to the pre-registered OAuth
client redirect_uris so the new /oauth/connect-claude-ai route works.
ensureOAuthAppRegistered uses ON DUPLICATE KEY UPDATE so the DB row is
updated on the next server startup.
2026-06-12 15:04:46 -04:00
Garfield
6604ab5d2b feat(connect): dedicated Claude.ai / ChatGPT browser connect picker
- Replace single 'Connect to Claude / ChatGPT' button with a modal picker
  offering Claude.ai web, Claude Desktop, Codex CLI, and ChatGPT/GPT Actions.
- Add /oauth/connect-claude-ai backend route that redirects to Anthropic's
  official https://claude.ai/api/mcp/auth_callback OAuth callback.
- Update MCP callback result page with browser-specific instructions for
  Claude.ai web, Claude Desktop, ChatGPT/GPT Actions, and Codex CLI.
- Deploy new app and hermes images to K8s.
2026-06-12 14:55:36 -04:00
Garfield
51315527c0 docs(handoff): Facebook/Instagram long-lived token generation steps 2026-06-12 14:03:35 -04:00
Garfield
d4b2ec2902 deploy: app accessibility fixes + docs design updates 2026-06-12 13:47:53 -04:00
Garfield
7e32dca0d8 style(a11y): add aria-labels and title tooltips to all buttons and form inputs
Addresses claude.ai accessibility flagging: all 11 platform Connect buttons now
have aria-label="Connect [Platform]" and title="Connect [Platform]"; all form
inputs have aria-label; modal close button has aria-label="Close".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 13:40:56 -04:00
Garfield
45cf9cafe6 fix(clients): fall back to env credentials when customer has no per-account creds 2026-06-12 13:14:08 -04:00
Garfield
723cf17869 docs(deploy): mark reviewer account setup complete 2026-06-12 13:09:28 -04:00
Garfield
de6d6ae9de fix(redis): add reconnect strategy to prevent closed client errors 2026-06-12 13:08:36 -04:00
Garfield
a326611806 style(design): apply favicon and nav link fixes to all subpages 2026-06-12 12:57:51 -04:00
Garfield
58a6d0f200 style(design): FINDING-003,004,005,006,007,008,009 — remove emoji, H4→H3, touch targets, favicon, nav link, H1 text-wrap 2026-06-12 12:55:42 -04:00
Garfield
b08d234494 style(design): FINDING-002 — restore nav links on mobile (wrap below logo row) 2026-06-12 12:53:40 -04:00
Garfield
cbdf1a795f style(design): FINDING-001 — replace system UI font stack with IBM Plex Sans 2026-06-12 12:53:25 -04:00
Garfield
9a4ce986be feat(site): add favicon.ico for Google favicon lookup and Claude.ai form 2026-06-12 12:46:10 -04:00
Garfield
8eafb2b05b feat(site): add 512x512 logo for GPT Store and Claude.ai marketplace 2026-06-12 12:35:46 -04:00
Garfield
b08dc2680c docs(deploy): reviewer account setup progress summary 2026-06-12 12:15:02 -04:00
Garfield
663107bfbc deploy: hermes-mcp reviewer enum + squaremcp-site legal update 2026-06-12 12:13:56 -04:00
Garfield
af084133fa legal: update privacy policy and terms for v1 consumer launch 2026-06-12 12:12:46 -04:00
Garfield
13350881e0 feat(manifest): add sqcp_reviewer account to ACCOUNT_PARAM_SCHEMA enum 2026-06-12 12:09:00 -04:00
Garfield
d1ff459b46 chore(k8s): deploy Facebook/Instagram creds from vault (token currently 500) 2026-06-12 09:45:51 -04:00
Garfield
e0623574ec docs(deploy): v1 launch execution summary 2026-06-12 07:23:06 -04:00
Garfield
bc58befd5e feat(ui): v1 launch — consumer hero, onboarding flow, Obsidian app card 2026-06-12 06:39:07 -04:00
Garfield
f74f90a2f0 fix(webhook): preserve raw body for Meta webhook HMAC validation
The global express.json() middleware at line 77 was parsing the body
into a JS object before the route-level express.raw() could capture
the raw Buffer. When WHATSAPP_APP_SECRET is set and a signature is
present, crypto.createHmac().update(req.body) received an Object
instead of Buffer, throwing TypeError and crashing the process.

Fix: register app.use('/webhook/whatsapp', express.raw({ type: '*/*' }))
before app.use(express.json()) so the raw body is preserved for HMAC.

Post-deploy verification: all 7 webhook tests pass, pod 0 restarts.

Related: SquareMCP/2026-06-10-twilio-whatsapp-webhook-deployment.md
2026-06-10 22:37:00 -04:00
Garfield
e5152eef12 feat(webhook): Twilio WhatsApp inbound route + Meta webhook hardening
Add POST /webhook/twilio/whatsapp for the pilot approval loop — Alex
replies 1/2/3 to the Twilio number to approve post drafts. Includes
HMAC-SHA1 signature validation, Redis dedup (wa_msg_seen:MessageSid),
pilot_owner_phone allowlist, staleness check (7d), tracking link
creation, and draft status update.

Also fix two security bugs in the existing Meta webhook handler:
fail-open when WHATSAPP_APP_SECRET unset (now 503), and missing length
guard before timingSafeEqual (was RangeError → 500, now 403).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 21:30:16 -04:00
Garfield
5effb41af4 feat(tracking): MySQL-backed tracking links + pilot schema
- src/tracking-links.ts — create, get, record click, validate URL, bot detection
- src/tracking-links.test.ts — 20 tests, all passing
- src/db.ts — tracking_links table, post_drafts table, 6 pilot columns on customers
- src/index.ts — public GET /t/:token redirect route (no auth)

Analytics (click count) is fire-and-forget after redirect.
MySQL is source of truth; redirect never depends on Redis.

Related: SquareMCP/2026-06-09-tracking-links-deployment.md
2026-06-09 14:22:58 -04:00
garfieldheron
95b4138f87 docs(spv): add marketing intelligence specs and lodge-first launch design
- spv/marketing-intelligence-features.md — full 7-feature technical spec
  with build order, dependency map, and tool signatures
- spv/lodge-first-launch-design.md — approved office hours design doc;
  Phase A→C→B sequencing targeting Alex/lodge July demo and CMG Opal
  replacement; includes pull analysis and success criteria

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 12:17:26 -04:00
Garfield
2bb1a2db60 chore: add broker demo video, exclude .runner from git
- product/site/squaremcp-broker-demo.mp4 — 45s mortgage broker demo video
  served at squaremcp.com/squaremcp-broker-demo.mp4, sent to Ferrari Lending
- .gitignore: add .runner (Gitea Actions runner token, should not be committed)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 09:18:21 -04:00
Garfield
7ddb6d48b4 fix(email): route sqcp SMTP through Azure ACS relay
Replaces direct Poste.io SMTP (mail.squaremcp.com:30587, port 25 blocked)
with Azure Communication Services relay (smtp.azurecomm.net:587).
All sqcp_* accounts share a single ACS credential; FROM addresses unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 14:22:21 -04:00
Garfield
da4058483a fix(auth): switch to K8s Redis, add claude.ai/chatgpt CORS origins
- REDIS_URL → K8s ClusterIP with auth (fixes silent hang on host Redis)
- Socket timeouts (connectTimeout 3s, socketTimeout 5s) on Redis client
- Add claude.ai, chatgpt.com, chat.openai.com to CORS allowlist
- Update hermes-mcp image SHA (includes above changes)
- Add squaremcp-broker-demo.mp4 to site Dockerfile; bump site image SHA

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 05:39:48 -04:00
Garfield
34983c44e2 security: fix reset token leak, add rate limiting, body limits, webhook HMAC, JWT_SECRET
- CRITICAL: forgot-password no longer returns token in response; sends email via info@squaremcp.com instead
- Rate limit: login 10/15min, forgot-password 5/hr, chat 30/hr (Redis, per IP)
- express.json() capped at 100kb
- WhatsApp webhook HMAC verification (activates when WHATSAPP_APP_SECRET is set)
- JWT_SECRET now explicitly set in K8s (was falling back to CREDENTIAL_ENCRYPTION_KEY)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 20:14:08 -04:00
Garfield
423dc89c94 perf(oauth): Redis-cache getTokenCustomer to eliminate uncached DB hit on every ChatGPT API call
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 20:02:02 -04:00
Garfield
4746c4ee1c fix(whatsapp): fall back to default Twilio account when customer has no WhatsApp creds
Customers who haven't connected WhatsApp in the dashboard now
automatically use the SquareMCP default number (+19547385805 via Twilio)
instead of throwing 'WhatsApp not connected'. Routing flag usingDefault
replaces the !customer check so OAuth sessions get the same Twilio path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 00:46:21 -04:00
Garfield
c270f8f74b fix(oauth): allow wildcard ChatGPT callback URI pattern
ChatGPT regenerates its GPT ID (and callback URL) every time the GPT
is saved, making exact redirect_uri matching impossible. Added support
for the registered URI pattern https://chat.openai.com/aip/*/oauth/callback
which matches any valid ChatGPT GPT callback via regex.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 00:15:46 -04:00
Garfield
c6504ec60f feat: /openapi-chatgpt.json — 29-op spec for ChatGPT Custom GPT limit
Drops obsidian (5 ops) and whatsapp/templates list (1 op) to stay
under ChatGPT's 30-operation cap. Served at /openapi-chatgpt.json.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:39:02 -04:00
Garfield
b67146dfc8 feat(whatsapp): Twilio send path for default account + API v21
The SquareMCP number (+19547385805) is registered under Twilio's BSP,
so direct Meta API sends were blocked with #200 permission errors.
Default account now routes through Twilio's REST API; customer-owned
accounts still use Meta's Cloud API directly.

- twilioSend(): POST to api.twilio.com with Basic auth
- resolveTemplateText(): fetches template body from Meta, substitutes
  {{1}}/{{}} parameters, so templates render correctly via Twilio
- Bumped WHATSAPP_API_VERSION to v21.0
- Added TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_WHATSAPP_NUMBER,
  WHATSAPP_DEFAULT_BUSINESS_ACCOUNT_ID to K8s deployment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 21:34:42 -04:00
Garfield
dcc1c39754 chore: add WhatsApp credentials for SquareMCP number +19547385805
WHATSAPP_DEFAULT_PHONE_NUMBER_ID, WHATSAPP_DEFAULT_ACCESS_TOKEN,
and WA_VERIFY_TOKEN (hermes-wa-2026) added to K8s deployment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 13:15:24 -04:00
Garfield
d89df87a6c feat: Twilio voice webhook to reject calls on WhatsApp number
POST /webhook/twilio/voice returns TwiML that says the number doesn't
accept voice calls and hangs up — needed for Twilio number config.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 12:31:09 -04:00
Garfield
adebe29ca0 feat: Slack alerts for chat widget escalations + support@ email polling
- notifications/slack.ts: added sendChatEscalationAlert (fires when visitor
  asks about pricing, demo, help, or a human) and sendSupportEmailAlert
- email-poller.ts: polls support@squaremcp.com every 5 min via IMAP,
  deduplicates with Redis (support📧alerted_uids), fires Slack alert
  for each new unseen message
- index.ts: detectEscalation() scans last user message for trigger phrases;
  chat endpoint fires alert fire-and-forget after responding; startEmailPoller()
  called on server boot

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 21:47:43 -04:00
Garfield
d613119d55 chore: add SLACK_DEFAULT_BOT_TOKEN to K8s deployment
Enables Slack demo tools in the chat widget agent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 19:29:47 -04:00
Garfield
18b838c268 feat: ChatGPT Custom GPT support in chat bot + sqcp SMTP routing fix
- chat.ts: system prompt now includes step-by-step ChatGPT Custom GPT
  setup (openapi.json import + OAuth), Claude/Cursor/Windsurf config,
  and mortgage broker guidance — bot no longer incorrectly says ChatGPT
  is unsupported
- smtp.ts: all sqcp_* accounts now route to mail.squaremcp.com (SQCP_SMTP_HOST)
  instead of the fetcherpay server
- tools.ts: ACCOUNT_PARAM description now lists all 14 mailboxes including
  the 7 squaremcp.com accounts so Claude picks the right one without guessing
- package.json: postinstall hook runs imapflow patch script after npm install
- hermes-k8s.yaml: updated image digest to current production build

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 18:53:42 -04:00
Garfield
1f8d97b6bd fix: serve chat-widget.js correctly in production
- Copy product/ into Docker image (was missing from final stage)
- Fix static file path: ../../product → ../product (wrong depth from dist/index.js)
- Add ANTHROPIC_API_KEY to K8s manifest (chat endpoint was returning 500)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 18:45:43 -04:00
Garfield
c7eae2c735 fix(imap): robust error logging + parser-instance.js null guards
- Move client.connect() inside try/catch in withClient
- Add logImapError() writing full stack to /vaults/imap-errors.log for diagnosis
- Extend patch-imapflow.cjs to guard this.remainder.trim() in parser-instance.js
- Root cause of reported crash was undefined args.q (callers passing 'query' not 'q')

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 18:13:26 -04:00
Garfield
0714d2d6d6 fix(docs): correct signup link to app.squaremcp.com, deploy updated image
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 12:39:12 -04:00
Garfield
38e367ea58 feat(email): add all 7 squaremcp.com email accounts
- New accounts: sqcp_garfield, sqcp_info, sqcp_sales, sqcp_support,
  sqcp_founder, sqcp_contact, sqcp_admin
- All use same poste.io mail server as fetcherpay.com (IMAP 30993, SMTP 30587)
- Password: onelove for all accounts
- Updated: imap.ts, smtp.ts, tools.ts, manifest.ts, hermes-k8s.yaml
2026-05-15 11:34:56 -04:00
Garfield
be1a14f783 feat(chat): upgrade to full agentic demo bot (Option B)
Chat widget now runs a live tool-use loop via Claude Haiku. Exposes
slack, discord, and telegram demo tools — bot can actually send messages
and read channels to prove the platform works in real time. Widget shows
a purple pill with tool names when the agent calls a live platform.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 10:49:18 -04:00
Garfield
4bf93d6763 feat: Slack platform + Claude-powered chat support widget
- Add Slack as customer-facing messaging platform (client, 4 MCP tools, dashboard card)
- Add /api/chat endpoint powered by Claude Haiku with SquareMCP system prompt
- Add embeddable chat-widget.js injected into all 3 sites (docs, app, www)
- Add ANTHROPIC_API_KEY, serve product/ as static files
- Update Platform type to include slack

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 10:44:24 -04:00
Garfield
05b4a30759 feat(remotion): mortgage broker demo video for Alex Ferrari
- Add SquareMCPBrokerDemo composition (1920x1080, 45s)
- 5 scenes: title, email inbox (47 unread → 5 replies), rate blast (200 prospects),
  WhatsApp auto-response, Facebook page reply
- Outro: SquareMCP logo + tagline
- Uses existing brand colors and spring animations
2026-05-15 06:19:28 -04:00
Garfield
fd7ea2fee5 feat(remotion): WhatsApp template management demo video for Meta app review
16s landscape (1920x1080): shows SquareMCP chat prompt triggering an
animated cURL call to the Business Management API creating a message
template (HEADER/BODY/FOOTER components with variables), then the right
panel renders a WhatsApp phone UI previewing the template bubble with
variable placeholders highlighted and a PENDING status badge.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 20:38:35 -04:00