Commit Graph
2698 Commits
Author SHA1 Message Date
Matthew Meszaros d855abfaa3 feat: replace the marketing site's Open Graph and Twitter card with a top-left 1.91:1 crop of the new dashboard export, and derive og:image type, width and height from the real image so blog covers stop declaring 1280x640 jpeg 2026-09-19 18:45:55 +02:00
Matthew Meszaros d8a3e70450 Merge pull request #609 from warmbly/fix/suppression-add-dialog
feat: suppression add dialog, row menu fix, and warmup suppression cleanup
2026-09-19 15:51:20 +00:00
Matthew Meszaros 530b184748 Merge pull request #607 from warmbly/feature/two-factor-setup-flow
feat: rebuild two-factor setup in Settings > Security as a three-step wizard with a QR code, manual setup key and TOTP parameters, inline code errors, and recovery codes with download, copy and print; show enable date and remaining recovery codes, add POST /auth/2fa/recovery-codes to regenerate them, return two_fa_invalid_code on a mismatched code, and update the security guide, API reference, error codes and OpenAPI
2026-09-19 15:48:03 +00:00
Matthew Meszaros 6b834b49f6 feat: cap the suppression add dialog's chip preview at 200 with a count of the rest, and refuse a paste over the server's 5000-entry limit before submitting instead of after 2026-09-19 08:46:24 -07:00
Matthew Meszaros 68ec5a016e feat: delete the reauth attempt counter when a refund leaves it at zero or below so it always carries an expiry, and focus the first field of a 2FA dialog on open 2026-09-19 08:43:11 -07:00
Matthew Meszaros e9d1a7e734 feat: reserve the per-account reauth attempt atomically before checking a password or 2FA code, keep the 2FA dialogs open while a request is in flight, move and trap focus in them, show a retry row when 2FA status fails to load, and drop Idempotency-Key from the recovery-code route with the reason documented 2026-09-19 08:36:59 -07:00
Matthew Meszaros b8f47c94f4 Merge pull request #608 from warmbly/feat/unibox-message-details
feat: open a message details panel in the unibox from the recipient line, sender and an info icon, with every address, exact times, mailbox, folder, size and identifiers, and add email_id and folder to GET /unibox/:id
2026-09-19 15:31:23 +00:00
Matthew Meszaros 8349ac2695 Merge pull request #610 from warmbly/fix/posthog-sourcemap-dlx
Fix the PostHog source map upload on Cloudflare Pages
2026-09-19 15:25:50 +00:00
Matthew Meszaros 69ddac8c75 feat: replace the inline suppression add form with a modal dialog that previews each pasted address and domain as chips with counts and flags unrecognized values, fix the suppression row menu so Remove from list sits on one line with its icon and the added date no longer wraps, tint danger menu item icons red, and add migration 000186 removing suppression entries and deliverability events that only warmup sends produced 2026-09-19 08:23:10 -07:00
Matthew Meszaros eceed10d89 feat: invoke the PostHog CLI as pnpm dlx @posthog/cli@<version> sourcemap ... in the web, admin and forms source map scripts, because pnpm dlx --package <pkg> <bin> is only understood by pnpm 10 and later and Cloudflare Pages builds the dashboards with an older pnpm that reads --package as the package name and fails the deploy on a registry 404 2026-09-19 17:23:10 +02:00
Matthew Meszaros a1d3f3f3f1 feat: open a message details panel in the unibox from the recipient line, sender and an info icon, showing every From, Reply-To, To, Cc and Bcc address, sent and received times in the reader's zone, the mailbox, folder, size, Message-ID and In-Reply-To with one-click copy; summarise all recipients on the header line; add email_id and folder to GET /unibox/:id and document both 2026-09-19 08:22:14 -07:00
Matthew Meszaros de10ca5216 feat: put 2FA disable and recovery-code regeneration behind the per-account reauth attempt budget and document it in the account API reference 2026-09-19 08:16:53 -07:00
Matthew Meszaros 274ff888a5 feat: rebuild two-factor setup in Settings > Security as a three-step wizard with a QR code, manual setup key and TOTP parameters, inline code errors, and recovery codes with download, copy and print; show enable date and remaining recovery codes, add POST /auth/2fa/recovery-codes to regenerate them, return two_fa_invalid_code on a mismatched code, and update the security guide, API reference, error codes and OpenAPI 2026-09-19 08:15:31 -07:00
Matthew Meszaros 7dd0177e0a Merge pull request #604 from warmbly/feat/warmup-plan-cloud-upsell
feat: present the $15 pool plan as the Warmup plan everywhere: rename the plan row (migration 000185), add it to the dashboard catalog so the header and billing overview name it, show the cloud tier in a self-hosted instance's header pill and a Plan section under Settings > Warmbly Cloud with upgrade and manage links to the cloud billing page, nudge on the mailboxes page only when the free pool is full, drop the self-host framing from the cloud's checkout dialog, paths panel and locked screen, rebuild the checkout dialog in the plan chooser's style, pitch Premium on deliverability from one shared benefit list, and update the billing and Warmbly Cloud guides and the pricing FAQ
2026-09-19 13:00:55 +00:00
Matthew Meszaros 464ec521ca feat: present the $15 pool plan as the Warmup plan everywhere: rename the plan row (migration 000185), add it to the dashboard catalog so the header and billing overview name it, show the cloud tier in a self-hosted instance's header pill and a Plan section under Settings > Warmbly Cloud with upgrade and manage links to the cloud billing page, nudge on the mailboxes page only when the free pool is full, drop the self-host framing from the cloud's checkout dialog, paths panel and locked screen, rebuild the checkout dialog in the plan chooser's style, pitch Premium on deliverability from one shared benefit list, and update the billing and Warmbly Cloud guides and the pricing FAQ 2026-09-19 05:57:41 -07:00
Matthew Meszaros 895c76210a Merge pull request #603 from warmbly/fix/restore-home-hero-b2b-copy
feat: restore the home hero B2B outreach copy and first-paint mock scaling reverted by the CASA merge
2026-09-19 12:02:17 +00:00
Matthew Meszaros d0857718c0 feat: restore the home page hero subheading about scaling B2B outreach and the first-paint hero mock scaling from PR #597, which the CASA AL1 merge in PR #599 reverted by re-committing a stale copy of site/src/pages/index.astro 2026-09-19 04:58:49 -07:00
Matthew Meszaros 14724065b6 Merge pull request #602 from warmbly/fix/tracking-rust-toolchain
fix: raise the tracking builder to Rust 1.96 and pin the Rust CI job to it
v0.4.27
2026-09-19 11:55:42 +00:00
Matthew Meszaros 3923b50a2b feat: raise the tracking builder to Rust 1.96 because the AWS SDK now declares rust-version 1.94.1, and pin the Rust CI job to whatever that Dockerfile says instead of stable so a dependency outgrowing the builder fails a pull request rather than a release 2026-09-19 13:49:43 +02:00
Matthew Meszaros 848e64865d Merge pull request #600 from warmbly/fix/mailbox-disconnect-and-prod-errors
fix: workspace-scoped mailbox disconnect, eviction of mailboxes whose row is gone, and the production errors from this morning
2026-09-19 11:31:28 +00:00
Matthew Meszaros 834da184d9 feat: clear every dependency advisory that has an upstream fix, dropping the AWS SDK's legacy-rustls-ring default feature that was pulling a second hyper 0.14, rustls 0.21 and rustls-webpki 0.101 into the tracking service alongside the current ones, moving async-nats to 0.50 for the last old webpki and reqwest to 0.12, boxing the NATS producer variant the bigger client made oversized, refreshing the node trees with overrides for the esbuild and postcss-selector-parser that fumadocs pins, recording why the two unpatched cowlib advisories cannot be reached from a service that sets no cookie, and deciding the credential-validation timeout from the subscription context's deadline rather than the error's shape 2026-09-19 13:25:33 +02:00
Matthew Meszaros 28b3dc9f05 feat: move the CASA evidence pack out of this repository to CASA_EVIDENCE_DIR and make the generator refuse any destination inside the tree, because a pack that maps every control to its file and lists the advisories still open with their reachability conditions is a reconnaissance document for anyone attacking a self-hosted instance that has not updated yet 2026-09-19 13:08:33 +02:00
Matthew Meszaros 9b1eb4db7c Merge pull request #601 from warmbly/test/multi-sender-reply-attribution
Test multi-sender reply attribution end to end
2026-09-19 11:08:27 +00:00
Matthew Meszaros 1497762d66 feat: add live regression tests proving replies to a campaign rotating across several mailboxes stamp each lead as replied and reach the campaign reply count, with and without thread headers, and document in the analytics guide that each lead's reply is expected in the mailbox that wrote to them 2026-09-19 04:05:34 -07:00
Matthew Meszaros 2c886a3202 feat: decide the credential-validation timeout from the subscription context rather than the error's shape so a Redis socket timeout inside a live deadline stays an internal error, and require a synthetic mechanism and an empty stack as well as a default object string before dropping an exception so a message that stringified an object alongside real text is still reported 2026-09-19 13:00:23 +02:00
Matthew Meszaros acecd62c88 feat: scope mailbox disconnect and warmup lifecycle to the workspace rather than the member who connected the mailbox so an admin can act on every mailbox the list already shows them, evict a mailbox whose row is gone from every live worker when its provider errors arrive so a deleted mailbox stops calling the provider once a sync interval forever, subscribe before publishing the credential-validation job and classify a socket deadline as the retryable timeout it is, give the worker's validation reply its own budget so a slow mail host no longer loses a finished verdict, guard every global key handler against a keydown carrying no key, drop exceptions whose whole message is an object's default toString, make the Postgres pool size configurable, and record the CASA and security invariants in AGENTS.md 2026-09-19 12:49:46 +02:00
Matthew Meszaros b09ec39907 Merge pull request #599 from warmbly/chore/casa-al1-security-assessment
feat: complete the ADA CASA AL1 control set and ship the assessment evidence pack
v0.4.26
2026-09-19 06:39:12 +00:00
Matthew Meszaros 03f59d4d6f docs: state the tenant and key-shape invariants in these comments as the constraints they are, rather than as an account of what each check replaced, since this repository is public and every self-hosted instance that has not updated yet reads the same text 2026-09-19 08:28:41 +02:00
Matthew Meszaros e0d68fddeb style: format the realtime runtime config so mix format --check-formatted passes 2026-09-19 08:21:14 +02:00
Matthew Meszaros e668a2a36b feat: complete the ADA CASA v2.1.1 AL1 control set across authentication, sessions, access control, cryptography, input validation and configuration, adding a breached-password denylist and per-account login throttling, enforced multi-factor authentication on the admin panel, step-up confirmation before an action that mints a lasting credential, purpose-scoped session tokens, single-use TOTP steps, tenant verification on every cross-referenced identifier, security headers on every surface, encrypted webhook signing secrets, per-organization idempotency, PKCE and a minimal two-scope Gmail consent on the mailbox OAuth flow, bounded spreadsheet and archive decoding, a patched Go toolchain with govulncheck in CI, and the evidence pack under compliance/casa 2026-09-19 08:18:35 +02:00
Matthew Meszaros 6428e6b3e9 Merge pull request #594 from warmbly/feature/disable-google-oauth-new-mailboxes
feat: route new Gmail mailboxes through a guided app-password connect instead of Google sign-in, behind BOX_GOOGLE_OAUTH_CONNECT, leaving existing OAuth mailboxes sending and re-authorizable
2026-09-19 06:11:15 +00:00
Matthew Meszaros 8664684b3f Merge pull request #595 from warmbly/fix/warmup-system-issue-592
feat: hold a pending warmup send when the day's target is cut after it was scheduled
2026-09-19 06:03:47 +00:00
Matthew Meszaros c24f0265f2 Merge remote-tracking branch 'origin/main' into fix/warmup-system-issue-592 2026-09-18 22:47:16 -07:00
Matthew Meszaros 79bd4f62e3 feat: hold a warmup send whose send-time budget reports the mailbox not warming instead of letting it through, because a failed campaign read produces that sentinel and let a health-check mailbox send uncapped, and cover both held-status writes with a test that a hold whose write fails is retried rather than acknowledged 2026-09-18 22:47:09 -07:00
Matthew Meszaros 91ceb59fac Merge pull request #598 from warmbly/fix/posthog-error-handling
feat: fix the open PostHog issues and the error handling underneath them
2026-09-19 05:45:18 +00:00
Matthew Meszaros d46cfad597 feat: check the warmup daily target again at the moment a send executes rather than only when the next one is placed, so a spam placement, health band or partner loss that cuts the target while a send is pending holds it as skipped_daily_limit and parks the chain at the next opening with a reply-back's aim intact, fail closed when that count cannot be read, share one target resolver between the placer and the send-time gate, add the skipped_org_suspended task status the suspended-workspace hold has written since #233 without a migration so its write stops failing and leaving the task pending for the dispatcher to re-fire, and anchor the ramp live fixture in UTC off the day boundary so its assertions no longer depend on the host timezone 2026-09-18 22:39:52 -07:00
Matthew Meszaros 49acd51b64 feat: stop one recurring fault burying error tracking by reporting it once per five minutes with the count it stands for, keep a cache outage from answering every signed-in request with a 500 and from taking realtime down by treating an unreachable Redis as a miss and the websocket handshake nonce nothing reads as best-effort, answer a 5xx with a sentence the reader can act on while the call site's own words go to the log against the same request id, prefer the API's own message over the HTTP class in the admin and dashboard clients, and name the fix on a schema registry refusal, an SES sandbox rejection and a mailbox check that could not be run 2026-09-19 07:39:40 +02:00
Matthew Meszaros caeeb1d2aa Merge pull request #597 from warmbly/feature/home-hero-copy-and-instant-mock
feat: home hero copy about scaling B2B outreach, and a hero mock that renders on first paint
2026-09-19 05:39:25 +00:00
Matthew Meszaros c42207ea5e feat: rewrite the home page hero subheading around scaling B2B outreach and winning more clients in a wider max-w-3xl box, and render the hero dashboard mock on first paint by giving its frame a CSS 16:9 aspect ratio and scaling the shell from an inline script instead of a deferred bundled module that left the frame at zero height until it loaded 2026-09-18 22:38:35 -07:00
Matthew Meszaros e8f14bb2fd feat: address the review on the Gmail app-password connect by reading BOX_GOOGLE_OAUTH_CONNECT through config.GoogleOAuthConnect in the instance-settings table so a yes/on value cannot display true against a gate that parses it as false, dropping the coming-soon line from the walkthrough banner on deployments where Google sign-in is actually available, naming the 2-Step Verification app-password control an administrator still has rather than the Less secure apps page Google removed, saying the OAuth client re-authorizes existing mailboxes as well as refreshing them, and marking the marketing send trace as the Google sign-in path 2026-09-18 22:18:56 -07:00
Matthew Meszaros 0e652bf357 Merge pull request #596 from warmbly/feature/pricing-page-redesign
feat: rebuild the pricing plan cards as the home page's joined panel and redesign the self-hosted block
2026-09-19 05:10:17 +00:00
Matthew Meszaros b884d65d8b feat: rebuild the /pricing plan cards as the single joined panel the home page uses, replacing the four ring-outlined floating cards with shared hairline dividers, a tint plus top accent rule on the featured plan, annual price with struck monthly and a yearly-saving badge, and a sends-per-day meter, and redesign the self-hosted block into a two-column section whose right panel carries the two warmup pool tiers over a one-command install terminal, with the paid tier renamed Premium and sold on the premium pool, priority service and better deliverability rather than the free tier claiming the same pool 2026-09-18 22:09:01 -07:00
Matthew Meszaros ee46cb49e8 feat: route new Gmail and Google Workspace mailboxes through a guided three-step app-password connect over smtp.gmail.com and imap.gmail.com instead of Google sign-in, behind BOX_GOOGLE_OAUTH_CONNECT (off by default) and announced to clients as gmail_oauth_connect on /auth/config, refusing a new gmail OAuth start with 403 mailbox_gmail_oauth_disabled in both the direct and Warmbly Cloud broker paths while leaving mailboxes already connected that way sending, syncing and re-authorizable 2026-09-18 22:06:09 -07:00
Matthew Meszaros e562e09354 Merge pull request #593 from warmbly/fix/mailbox-disconnect-workspace-scope
Scope mailbox disconnect to the workspace and surface the API's reason
2026-09-19 04:15:40 +00:00
Matthew Meszaros 4b2b641f92 feat: pass the workspace id to the mailbox delete in the database-backed removal and erasure tests, which compiled with the owner's id but would answer not found now that Delete is scoped to the organization, and rename the cloud link stub's parameter to say what it carries 2026-09-19 06:10:32 +02:00
Matthew Meszaros f99ee57484 feat: scope mailbox disconnect to the workspace instead of the connecting member, so a teammate with manage_emails no longer gets 404 on a mailbox the list shows them, delete by id in the repository on the strength of that check while the worker removal still names the owner the consumer's unibox cleanup is keyed on, and read the API's own reason off the normalised AppError in the accounts page so a refused disconnect says why instead of "The mailbox couldn't be disconnected" on every failure 2026-09-19 06:01:03 +02:00
Matthew Meszaros b31c5d521b Merge pull request #591 from warmbly/fix/reply-attribution-and-human-opens
Count thread replies from any address as replied, and count only a person's opens
v0.4.25
2026-09-18 12:56:39 +00:00
Matthew Meszaros ffe3159256 feat: order the repair sweep's fake inbox by id so the cursor assertion is deterministic like the query it stands in for 2026-09-18 14:51:18 +02:00
Matthew Meszaros bd092dcf04 Merge remote-tracking branch 'origin/main' into fix/reply-attribution-and-human-opens
# Conflicts:
#	internal/app/consumer/event_new_email.go
2026-09-18 14:44:41 +02:00
Matthew Meszaros 6aebfe7e63 feat: store IMAP-synced addresses as Name <addr> like the Gmail and Graph syncs instead of Name (addr), teach mailhdr.Bare, the reply path's sender and recipient checks and the warmup sender fallback to read the old form for existing rows and older workers, so a reply into an IONOS or any other IMAP mailbox is attributed to its lead again after the address checks added on 16 September refused every one of them, and add a consumer sweep that re-offers unclaimed inbound mail answering a campaign send or coming from a contact to reply processing at boot and daily so the replies missed that week are attributed without anyone touching the database 2026-09-18 14:37:35 +02:00