Commit Graph
332 Commits
Author SHA1 Message Date
Matthew Meszaros 0a5e7947b4 feat: return a failed warmup retention delete from the worker so the bus redelivers it up to five times, re-key a Graph message in the map on every move so the sender copy's body can be dropped, never expunge a whole IMAP folder for one message (UID EXPUNGE, else MOVE to Trash, else refuse), build the two retention indexes concurrently in their own migrations 000193 and 000194, keep the dashboard stepper off 1 and 2 days, and describe retention as applying wherever the placement files warmup mail 2026-09-21 01:11:22 -07:00
Matthew Meszaros 1513419a2a feat: delete warmup mail from each mailbox once past a per-mailbox retention window (email_accounts.warmup_retention_days, else retention.warmup_mail_days, default 30) via a consumer sweep that retires the receipt and sender copy and a worker delete action that trashes on Gmail, deletes on Graph, expunges on IMAP and drops the stored body, prune per-message warmup records after retention.warmup_event_days, and count a warmup deletion as tampering only within 24 hours of arrival and never for a retired message, judging Gmail's Trash label on the same rule 2026-09-21 00:52:02 -07:00
Matthew Meszaros 742a173b51 Add steel Warmbly wordmark for theme-agnostic email signatures 2026-09-20 14:58:07 +02:00
Matthew Meszaros 876076942a Add white Warmbly wordmark for dark-mode email signatures 2026-09-20 13:40:13 +02:00
Matthew Meszaros 56286f94e8 Add Warmbly wordmark for email signatures 2026-09-20 13:26:33 +02:00
Matthew Meszaros 06ccb9af38 feat: point every marketing-site call to action at a route the dashboard actually serves, rewriting app.warmbly.com/login and /register to /auth/login and /auth/register and the developers page's /settings/api-keys to /app/api-keys 2026-09-19 19:35:53 +02:00
Matthew Meszaros 758e83efe1 Merge pull request #614 from warmbly/remove-site-banner
feat: remove the site-wide launch banner from the marketing site
2026-09-19 17:01:08 +00:00
Matthew Meszaros f0b15c2ddc feat: remove the site-wide launch announcement banner from the marketing site layout and delete the LaunchBanner component 2026-09-19 10:00:01 -07:00
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 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 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 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
2026-09-19 06:39:12 +00: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 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 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 2dd4f9c3a4 feat: announce the live development beta in the homepage launch banner 2026-09-17 19:47:28 -07:00
Matthew Meszaros 6f0314081c feat: update vulnerable dependencies across Go Phoenix docs site and web 2026-09-17 07:04:40 -07:00
Matthew Meszaros 9a2c565abe feat: enable Stripe Tax for subscriptions, credit purchases, automatic top-ups, billing details, and failure alerts 2026-09-17 15:25:26 +02:00
Matthew Meszaros 0334d2c64a feat: prevent ResizeObserver feedback warnings from reaching PostHog and scope worker outage alerts per workspace on shared cloud workers 2026-09-16 17:42:38 +02:00
Matthew Meszaros ae012dd13f Clear the live error-tracking issues, and the workspace rename that renamed the wrong workspace (#533)
* feat: stop a managed Kafka cluster refusing topic creation from failing the publish, by treating a topic- or cluster-authorization failure from CreateTopics as a topic the cluster owns rather than one that is missing, which on Confluent Cloud dropped every warmup event and filed one issue per message because the topic never became known

* feat: drop a report whose error is a cancelled context in errs rather than at ninety call sites, so a browser navigating away or a container draining on deploy stops filing one issue per query that happened to be in flight, while a deadline this process set and blew through still reports

* feat: stop renaming one workspace from renaming another, by keying the workspace settings editor on the workspace id so a switch re-seeds the name field instead of leaving the previous workspace's name against the new workspace's autosave baseline, and pinning every save on the workspace, sending and tracking pages to the workspace its draft was hydrated from

* feat: drop Script error. and the ResizeObserver notice on the marketing site and the hosted form page the way the dashboard and admin panel already do, since those two carry no stack and no bug and between them were the largest issues in error tracking, all of it from warmbly.com

* feat: rename the forms Turnstile script module to turnstileScript.ts so it no longer differs only in case from the Turnstile.tsx component, which resolved both imports to one file on a case-insensitive filesystem and failed forms' typecheck with TS1149

* feat: upload source maps from the static build:pages build as well as the image build, so the dashboards served from a static host stop reporting every stack frame as a minified name beside 'Invalid source map: bad json', which is PostHog falling back to fetching the .map from a host that answers with its SPA fallback

* feat: build every admin list in pg_admin.go with make rather than declaring it nil, so an empty page serializes as [] instead of null, and guard the audit table's own empty check, which is what crashed admin.warmbly.com/audit with 'null is not an object (evaluating d.data.length)' whenever a filter matched nothing

* feat: match the whole broker description rather than a substring when deciding a topic create was refused for permissions, since that answer remembers the topic as present, and clear the cached promise and dead tag when the forms Turnstile script fails to load so a blocked first attempt no longer leaves every later mount with the same rejection and the captcha permanently missing
2026-09-15 09:05:53 -07:00
Matthew Meszaros b9a98cef8f feat: rebuild the unified inbox as three columns with no metric strip, a flattened scope rail with one row language and bare counts, three-line conversation rows carrying an unread dot in the gutter instead of an avatar and bar, a subject-first thread header with icon-only actions, a filter popover that applies on the spot and shows each added filter as a removable chip that never repeats what the current view already fixes, and real loading throughout: a delayed progress bar over dimmed stale rows, row-shaped skeletons for first load, next page and the thread reader, and optimistic row removal so archive, delete and snooze land instantly 2026-09-14 08:26:03 -07:00
Matthew Meszaros c28f915648 feat: erase everything a disconnected mailbox leaves behind, revoking its OAuth grant at Google and deleting its stored message bodies through a durable retried queue, cascade the nine mailbox foreign keys that had none so warmup receipts, tampering events and provider message maps stop outliving the mailbox, clear thread labels and snoozes on conversations the delete emptied, make workspace deletion possible at all by cascading the four organization foreign keys with no delete action, and put Disconnect in the mailbox row menu and a Settings danger zone since it was only reachable from the selection bar (#506) 2026-09-14 07:55:01 -07:00
Matthew Meszaros d74d5e6836 fix: retire the warmup spam score, a counter that grew with volume rather than misbehaviour and that no band could act on (#508)
* fix: retire the warmup spam score, a ratchet that grew with volume rather than misbehaviour and that no band ever read, dropping the column from the pool row and the reputation ledger and explaining a pool finding with the band's own reason instead (#491)

* test: pin the advisor snapshot's pool columns against the scan, since the band's reason now reaches the finding through that select alone (#491)

* fix: hold a warmup sentence's score and reason with the sentence itself, keep the retired spam_score key on the published analytics payload as a deprecated zero, seed the sandbox with severity-shaped scores, and record the raw spam report when the warmup service is absent (#491)
2026-09-14 07:44:34 -07:00
Matthew Meszaros 40506c4f05 fix: seed the two warmup pools on every instance under fixed ids and make one pool per type structural, since the baseline squash dropped the insert and a fresh self-hosted instance never warmed; move memberships onto the canonical pools, scope the standing mirror trigger to the columns it mirrors so a pool move keeps a retention window, commit the runtime and every seeder to the ids through MoveToPool, assert the pools at boot and in a warmup_pools_missing health check, and drop the guide's claim of cross-tier borrowing the health gate rejects (#493) 2026-09-13 21:37:17 -07:00
Matthew Meszaros 7300b3b021 feat: full PostHog coverage: identify the signed-in user and workspace in the dashboard and admin panel with autocapture, heatmaps, dead and rage clicks, web vitals, network timing, console capture and session replay masking only password fields, send server-side signup, trial and subscription events under the user id with the organization as a group, keep the marketing site and form pages cookieless while capturing everything stateless plus a form funnel, upload the form app's source maps, and add WARMBLY_POSTHOG_SESSION_REPLAY 2026-09-13 20:58:22 -07:00
Matthew Meszaros 6b6efca865 fix: campaign follow-ups opened a new conversation instead of replying in the contact's thread, so carry In-Reply-To/References and the Gmail threadId from the previous send, give every step a reply-in-thread switch, and let a threading step inherit the conversation's subject (issue #472) (#489) 2026-09-13 20:51:41 -07:00
Matthew Meszaros 1dc4aedc3c fix: retire the warmup invalid-token band with its table, metric query, service and repository methods and admin tab, since nothing has fed it since #481 and no attributable forged-token signal exists; key the live pool fixtures on the canonical pool ids so the warmup, repository routing and tasks routing suites run on a fresh database, and correct every doc, site and advisor line that still described the retired signal or a spam-score threshold nothing implements (#490) 2026-09-13 08:09:01 -07:00
Matthew Meszaros 9074f2a9cb feat: host the Microsoft identity association file at site/public/.well-known/microsoft-identity-association.json so warmbly.com verifies as the publisher domain for the Entra app registration that connects Outlook mailboxes (#486) 2026-09-13 04:54:49 -07:00
Matthew Meszaros 8799680166 fix: never charge a mailbox for a warmup token that arrived in its inbox, hold a quarantine or block for its full term against fresh metrics, and keep a penalised address's standing across removal, pool exit and export through a trigger-maintained mirror, since the recipient never controlled the token, the bands read seven days against 30-day terms, and the pool row died on paths a snapshot at deletion never saw (#481) 2026-09-13 04:34:44 -07:00
Matthew Meszaros 55d712579b feat: collapse the left navigation to an icon rail, drag the unibox conversation list against the thread, and remember the contact rail toggle instead of reopening it on every conversation (#479) 2026-09-13 01:09:29 -07:00
Matthew Meszaros 9ce576bb3f feat: rebuild the marketing contact page as a minimal list of real channels (team@warmbly.com, the Discord, GitHub issues and discussions, docs, status) and the Mindroot Ltd registration, dropping the invented Delaware entity, postal address, team locations, business hours and SLA 2026-09-12 03:02:57 -07:00
Matthew Meszaros 170c33780a feat: pass ui_host to PostHog in the dashboard, admin panel and marketing site from its own environment variable so a proxied api_host stops breaking toolbar and session-replay links, which the SDK builds against whatever it sends events to and which a reverse proxy does not serve, defaulting to us.posthog.com so an install that does not proxy is unaffected 2026-09-11 11:34:02 +02:00
Matthew Meszaros ced741e352 feat: make PostHog the default error tracker across every runtime while keeping Sentry fully supported alongside or instead of it, by turning internal/observability/errs into a two-sink fan-out with a local-log fallback, adding $exception capture to the Go services, the Rust tracking service, the Elixir realtime service and the dashboard, admin and form apps, reporting gin panics with their route, request id, workspace and user, attaching that identity plus a route and failed-request trail to browser exceptions, and wiring POSTHOG_ERROR_TRACKING, the node join env, compose, source-map upload and the docs to match 2026-09-10 19:11:32 +02:00
Matthew Meszaros cab27fac62 Merge remote-tracking branch 'origin/main' into fix/main-ci-failure-and-issue-400 2026-09-09 09:05:45 -07:00
Matthew Meszaros 9356c748b9 Merge remote-tracking branch 'origin/main' into fix/main-ci-failure-and-issue-400
# Conflicts:
#	docs/content/docs/guides/mailboxes.mdx
#	site/public/install.sh.sha256
2026-09-09 08:59:37 -07:00
Matthew Meszaros 3591d64404 Merge remote-tracking branch 'origin/main' into fix/issue-401 2026-09-09 08:58:08 -07:00
Matthew Meszaros 18a8c7b009 feat: give a self-hosted instance on-demand TLS for customer tracking and forms domains, gating Caddy's ask on a /tls/authorize endpoint that answers only for domains this instance has verified, so a workspace CNAME stops serving every tracked link and opt-out link with no certificate 2026-09-09 08:56:08 -07:00
Matthew Meszaros 68b5d8f358 feat: bind a campaign lead to the mailbox that sends its first email so every follow-up leaves from the same address, holding a lead back while its mailbox is merely out of budget or outside its hours and moving it to another mailbox only when that one can no longer send for the campaign at all 2026-09-09 08:51:00 -07:00
Matthew Meszaros 6ebf9cfdcf Merge remote-tracking branch 'origin/main' into fix/self-hosted-unsubscribe-domain 2026-09-09 08:24:04 -07:00
Matthew Meszaros 7d58b874b8 feat: keep every recipient-facing and self-host-facing address on the deployment's own domain: mint unsubscribe links on a workspace's verified tracking domain (served by the tracking service, proxied to the backend that owns the pages), attach RFC 8058 one-click only over https, resolve all branding through config.Brand() gated on SelfHosted() so a self-host's email footer, sign-in links, stats card, API example and public form badge name nobody else, drop the app.warmbly.com fallback from AppBaseURL, blank TRACKING_DOMAIN and FORMS_DOMAIN on core-only installs, and have install.sh offer to configure a fresh interactive install instead of silently defaulting to localhost 2026-09-09 06:34:43 -07:00
Matthew Meszaros 435dbb522f feat: replace the worker tier/type/risk-pool/egress categories with a scored placement model and make the fleet pull-based, so a machine joins with one command, workers and consumers share one node registry with usage and liveness, nodes self-update to the version the control plane resolves, and the Hetzner provisioning, worker profiles and SSH orchestrator are removed 2026-09-09 04:54:01 -07:00
Matthew Meszaros 156a90c39a feat: default every PostHog capture host (site build, dashboard runtime, backend analytics client) to PostHog Cloud US instead of EU, and update the configuration docs table, since the customers are primarily US-based 2026-09-07 20:28:31 -07:00
Matthew Meszaros de4b1e3aff Merge remote-tracking branch 'origin/main' into fix/issue-371-public-images
# Conflicts:
#	site/public/install.sh.sha256
2026-09-07 09:13:22 -07:00
Matthew Meszaros c4bfbaf4a9 feat: address the review on the image publicity gate by passing build-push only the seven services that workflow actually publishes, since web, admin and cli have no :dev tag and would have warned falsely on every push to main, by taking the release tag through the step env instead of interpolating github.ref_name into the shell, and by no longer asserting the tag is fine when a pull is refused, because GHCR denies an unknown namespace exactly as it denies a private one, so a mistyped --registry now gets its own reading in the installer message, the troubleshooting table and the fork note, which also splits the personal and organization paths to the visibility setting 2026-09-07 09:02:23 -07:00
Matthew Meszaros 719a81866c feat: gate the release on every published image being pullable with no credentials, because GHCR creates each package private and does not inherit the repository's visibility, so the authenticated imagetools inspect in create-release passed for four releases while ghcr.io/warmbly/warmbly/* returned unauthorized to everyone outside the org and no curl | sh self-host install could pull a byte (#371); adds scripts/check-images-public.sh as the anonymous pull test, makes it the gate before create-release and the source of the digests in images.json, warns from build-push on main where a new service image first appears, and teaches install.sh to report a registry refusal as one instead of as a missing tag 2026-09-07 08:51:57 -07:00
Matthew Meszaros 766bd3ae6a feat: let a self-hosted instance connect a mail server on its own machine by adding a third mailbox security mode, "none", accepted only for a loopback literal and only where the worker shares a host with the relay, so Proton Bridge on 127.0.0.1:1143/1025 and a local Dovecot or Mailpit can be connected at all, with the rule enforced in onboarding and reauth validation, again by the worker against the peer it actually dialled rather than the name it was given, and hidden from the connect form on the hosted product where the worker is never the customer's machine 2026-09-07 08:07:40 -07:00
Matthew Meszaros 26c88d2426 feat: address the CodeRabbit review on the PostHog PR by dropping a referrer that is not a hostname instead of storing its query string or fragment, redacting email-shaped values out of every acquisition field before they reach the database or an analytics property, counting an invited signup which returned before the count was taken, hanging subscription_started off the persisted trial-to-paid transition so a redelivered webhook cannot report a second start, capturing the validated provider in both OAuth mailbox paths including Warmbly Cloud, making the two acquisition toggles mutually exclusive and naming them after what they actually select, and replacing the unsupported CNIL consent-exemption claim with what the guidance says and an explicit note that qualifying is a deployment-specific assessment this document does not make 2026-09-07 05:45:11 -07:00