Matthew Meszaros
|
da4b89da0b
|
feat: split a unibox message's provider placement into its own provider_folder column (migration 000146) so Archive and Delete in the thread header survive the next sync without the sync losing the ability to follow a real provider move, and narrow PATCH /unibox/folder to inbox/archive/trash behind the unibox feature gate with an audit entry so the move reaches every teammate's list live
|
2026-09-11 03:23:19 -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
|
1866c45c67
|
feat: serve a PostHog reverse proxy at /ingest on the backend so the dashboard, admin panel and marketing site can report analytics and errors through this instance instead of posthog.com, which content blockers drop for a large share of visitors, splitting asset traffic to the bundle host because sending it to the ingestion host 404s, withholding the caller's cookies and Authorization from a third party, and preserving the trailing slash that path cleaning removes and PostHog's capture endpoint needs
|
2026-09-11 06:02:21 +02:00 |
|
Matthew Meszaros
|
853afe458e
|
Merge pull request #430 from warmbly/fix/bootstrap-and-tracking-domain-check
fix: two aws-bootstrap defects, and a check for tracking on your own brand
|
2026-09-10 20:29:46 -07:00 |
|
Matthew Meszaros
|
eb21d978a8
|
feat: stop aws-bootstrap from treating a bucket that exists in another region as done, since head-bucket answers globally and a second region silently kept its blobs in the first, stop it printing the database master password to stdout where a terminal, a CI log or an agent transcript keeps it forever, and add an instance check that reports a tracking domain sharing a registered domain with the product's own URLs
|
2026-09-11 05:24:57 +02:00 |
|
Matthew Meszaros
|
a962683511
|
feat: ship AWS's RDS truststore in the backend and consumer images and point the docs at it, because Amazon RDS chains to a root that is in no public trust store so the sslmode=verify-full those docs recommended failed every connection with x509 certificate signed by unknown authority, while deliberately not setting PGSSLROOTCERT by default since an RDS-only store would break a Postgres fronted by a public CA
|
2026-09-11 05:23:23 +02:00 |
|
Matthew Meszaros
|
a84ab48729
|
Merge branch 'main' into feature/posthog-error-tracking
|
2026-09-10 10:25:21 -07:00 |
|
Matthew Meszaros
|
2ff350ecf9
|
feat: apply WARMBLY_POSTHOG_ERROR_TRACKING to the public form pages too, by having cmd/forms stamp an empty browser key when it is false, since the page can only act on whether a key arrived and the flag otherwise silenced the dashboard and the admin panel while leaving form pages reporting
|
2026-09-10 19:14:34 +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
|
d51de7db3a
|
feat: address the CodeRabbit review by quoting a fragment in the copy's own casing rather than the model's retyping of it, extracting the case-fold offset map into internal/pkg/casefold so the AI half gets the same Unicode safety the rules half has, giving a trigger term a span in each half it appears in instead of losing the second one to deduplication, scanning subject links before body anchors so the display cap cannot drop the subject's own, requiring WRITE_TEMPLATES on the credit-spending analyze route so a read-only key cannot spend the workspace balance, refusing to tell a customer their credits came back when the refund is what failed, and no longer letting a stale analysis retire the newer rules request that was about to replace it
|
2026-09-10 09:50:28 -07:00 |
|
Matthew Meszaros
|
5411b1033c
|
feat: say in the analyze endpoint reference that a finding's category is absent when the model named something outside the documented set, matching the enum the response is now held to
|
2026-09-10 09:29:35 -07:00 |
|
Matthew Meszaros
|
9f2ddc218c
|
feat: correct the content-check guide to describe the badge the editor actually renders, which names both halves when the wording straddles them rather than carrying a line number the rules pass never puts there
|
2026-09-10 09:28:00 -07:00 |
|
Matthew Meszaros
|
f468f44e1d
|
feat: let a content-check issue's field carry the location instead of repeating it in the message, so the launch dialog and campaign feed stop reading 'Body: 3 spam-trigger term(s) found in subject/body', and say 'Subject and body' for an issue whose fragments straddle both halves rather than dropping the location entirely, with the editor labelling each quoted word on such an issue
|
2026-09-10 09:28:00 -07:00 |
|
Matthew Meszaros
|
ade18d1650
|
feat: leave an AI finding's field empty when the model labelled neither half and nothing in the finding could be anchored in the copy, instead of defaulting it to the body and rendering a badge that sends the writer to the wrong box on the one panel whose whole purpose is saying which box to open
|
2026-09-10 09:28:00 -07:00 |
|
Matthew Meszaros
|
331db196d8
|
feat: locate every content-check issue in the subject or the body with the exact fragments that caused it and a one-line fix, add POST /templates/analyze running the configured LLM over a campaign template for located spam findings quoted verbatim from the copy plus a rewritten subject and an overall score, verify every model quote against the draft so an invented sentence is dropped rather than shown, pin the analysis temperature so re-checking unchanged copy returns the same number, and give the editor panel a Re-check button that re-runs both passes and reports the movement since the last check
|
2026-09-10 09:28:00 -07:00 |
|
Matthew Meszaros
|
bbe9d9055a
|
feat: let web and admin be served from a static host by teaching each app's own entrypoint to render config.js wherever WARMBLY_CONFIG_OUT points, so one definition of the runtime key set serves both the container that renders it at start and a build:pages script that renders it into dist, ship a _redirects in each so a deep link stops 404ing without nginx try_files, and add scripts/check-pages-build.sh to make lint because a malformed config.js reads fine in a diff and leaves the app blank at runtime
|
2026-09-10 18:03:00 +02:00 |
|
Matthew Meszaros
|
a08ada6666
|
feat: address the review on the bus bundle by downloading the compose file and config the documented one-command install never fetched, resolving container names through compose so --install-dir stops inspecting containers that do not exist, renewing a certificate that is present but expired instead of starting a stack that refuses every connection, refusing to write an empty credential when openssl fails, and falling back to dig or host where getent does not consult DNS
|
2026-09-10 17:39:58 +02:00 |
|
Matthew Meszaros
|
9e689e6d91
|
feat: fix the three defects that stopped the split-deployment bus bundle from starting at all (NATS given store_dir twice on the command line and in nats.conf, which it refuses rather than reconciling; Redis unable to read its own private key because the image's entrypoint drops from root with gosu and discards the added group; and a healthcheck on localhost when the monitor binds IPv4 loopback, leaving the service unhealthy while serving fine), add bus/setup.sh so standing the box up is one idempotent command that verifies with real clients before printing the control plane's URLs, and add scripts/check-split-cloud.sh to make lint so a bundle that cannot start fails CI
|
2026-09-10 17:22:14 +02:00 |
|
Matthew Meszaros
|
2998f8a8c6
|
Merge remote-tracking branch 'origin/main' into feat/worker-capacity-soft-target
|
2026-09-10 06:26:47 -07:00 |
|
Matthew Meszaros
|
fa2b5330d7
|
feat: drop the auth-pressure placement term because worker_capacity_view aggregates auth_errors (per-mailbox credential failures) and not rate_limit_errors (the 454/421 per-IP throttles it claimed to measure), measure projected utilization against an age-free Capacity.Target so a freshly joined node can relieve a full fleet instead of scoring as 200% loaded after one mailbox, bound the isolated-egress override with an explicit OverTarget check now that Eligible no longer caps it, and cap rotation moves per destination since a tick scores every mailbox against one frozen materialized-view snapshot
|
2026-09-10 05:51:17 -07:00 |
|
Matthew Meszaros
|
7fa4fdfbc4
|
feat: make worker capacity a placement target rather than a hard gate, so Eligible refuses only on health and an over-target worker costs enough score to lose to anything with room instead of returning nil and dropping assignment into selectFallback, score projected utilization including the incoming mailbox's own weight, and penalise the 454/421 auth pressure the capacity view already collected and threw away
|
2026-09-10 05:38:17 -07:00 |
|
Matthew Meszaros
|
396bab0e06
|
Merge branch 'main' into feat/issue-414-delete-api-key
|
2026-09-10 05:36:06 -07:00 |
|
Matthew Meszaros
|
1e1231f3b1
|
feat: address the review of the API key delete, putting the permanent-delete route in the published OpenAPI contract with its 409, keeping one auto margin in the drawer footer so the Delete button lands on the right, and deciding the dashboard's status pill, its footer and the key-count strip on whether the key can still authenticate rather than on a status column that never says expired
|
2026-09-10 05:23:56 -07:00 |
|
Matthew Meszaros
|
64dfaa8c60
|
Merge remote-tracking branch 'origin/main' into feat/split-cloud-hosting
|
2026-09-10 14:20:22 +02:00 |
|
Matthew Meszaros
|
510ee692ba
|
feat: address the review on the split-deployment branch by moving the two broker routes onto their own NODE_BROKER_TOKEN so the internet-facing tracking and forms services no longer hold a credential that can open any organization's data key, refusing to presign any key outside the prefixes a node reaches, fixing IAM policies that named an alias ARN KMS never resolves in a Resource element, bounding both brokered HTTP clients because the sync loop's context never expires, no longer reporting a 403 from the object store as a missing body, and redacting the DSN and URL credentials the dry-run listing printed in clear
|
2026-09-10 14:19:53 +02:00 |
|
Matthew Meszaros
|
804ac149fd
|
feat: name the API key case in the docs' 409 section, so the error-codes page lists the state-based conflict alongside the duplicate-resource one
|
2026-09-10 05:13:38 -07:00 |
|
Matthew Meszaros
|
9e37ea73a8
|
feat: add a permanent delete for API keys, DELETE /api-keys/:id/permanent plus a Delete key button under a revoked key in the dashboard drawer and warmbly key purge, taking the key's usage logs with it and refusing any key that could still authenticate so revoking stays the step that records why a credential ended (issue #414)
|
2026-09-10 05:02:05 -07:00 |
|
Matthew Meszaros
|
47ba13083e
|
feat: make a split deployment work end to end by fixing the three defects that made an off-host node impossible to configure (nodeEnvKeys shipped S3_BUCKET and KMS_KEY_ID, which nothing reads, so an AWS-backed node silently used the default bucket and key alias; a joined consumer never received PRIMARY_DB and died at boot; and node.env was rewritten on every join with no file an operator could add to), then removing the need for cloud credentials on a node at all with brokered KMS and blob providers that renderNodeEnv hands out automatically, plus deploy/split-cloud, scripts/aws-bootstrap.sh, two fleet instance checks and the docs
|
2026-09-10 13:58:59 +02:00 |
|
Matthew Meszaros
|
9d6f71d683
|
feat: match every word of a contact search against first name, last name, email, company and phone instead of taking the query whole, so "Test Demo" finds the contact whose name is split across two columns (issue #413), cap a search at six words, and say in the contacts guide what search matches
|
2026-09-10 04:53:50 -07:00 |
|
Matthew Meszaros
|
2599d6abb2
|
feat: stop handing the website-tracking identification ticket to a recognised scanner, which filed its walk of a tracked link as the recipient's own page view, read TRACKING_SCANNER_BUILTINS the way the backend's configuration registry does so off no longer means on, and ship the whole-cloud Microsoft and Google ASN entries commented out because a recipient browsing from Azure or Google Cloud sits inside them
|
2026-09-10 04:32:52 -07:00 |
|
Matthew Meszaros
|
08f1420c0b
|
Merge branch 'main' into fix/issue-410-scanner-networks
|
2026-09-10 04:32:36 -07:00 |
|
Matthew Meszaros
|
82baf6b884
|
feat: name the source-network rule alongside the timing rules in the campaigns guide's account of what makes a click automated, so the guides page and the analytics page describe the same three rules
|
2026-09-10 03:41:53 -07:00 |
|
Matthew Meszaros
|
6684dafe3a
|
feat: classify opens and clicks that arrive from a known mail-filtering network as automated, so Microsoft 365 Defender's delivery-time pixel fetches and Safe Links URL detonations stop counting as engagement (issue #410), with a shipped scanner catalogue, TRACKING_SCANNER_* overrides and optional ASN matching from a trusted edge header
|
2026-09-10 03:38:50 -07:00 |
|
Matthew Meszaros
|
6dcbc6d6a7
|
feat: stop sending prompt=consent on the Outlook/Microsoft 365 authorize request, which made Entra ID re-run the consent eligibility check per sign-in and refuse every non-admin with AADSTS90095 even under a tenant-wide admin grant (issue #409), and ask for prompt=select_account instead so the account picker survives while Google keeps access_type=offline plus forced consent for its refresh token
|
2026-09-10 03:24:16 -07:00 |
|
Matthew Meszaros
|
817233cc09
|
feat: record one unresolved row per mailbox error code instead of one per sync pass, and clear IMAP_UNKNOWN when a pass completes (issue #405)
|
2026-09-09 09:30:17 -07: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
|
494996ea8a
|
feat: stop the backend image copying scripts/install-worker.sh, which the pull-based fleet change deleted, and clear the rest of that removal's dangling references out of the backend systemd unit, deploy/README, architecture and troubleshooting docs
|
2026-09-09 08:56:05 -07:00 |
|
Matthew Meszaros
|
16261de4cb
|
Merge remote-tracking branch 'origin/main' into fix/issue-401
|
2026-09-09 08:51:02 -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
|
3153f9ff23
|
Merge remote-tracking branch 'origin/main' into fix/self-hosted-unsubscribe-domain
|
2026-09-09 08:44:13 -07:00 |
|
Matthew Meszaros
|
b18bbcad7a
|
feat: name API_HOST as the listen address the unsubscribe link falls back to when API_PUBLIC_URL is unset, rather than describing the resulting localhost address alone
|
2026-09-09 08:34:04 -07:00 |
|
Matthew Meszaros
|
035865e5c5
|
Merge remote-tracking branch 'origin/main' into feat/issue-393-html-css-email
|
2026-09-09 08:30:52 -07:00 |
|
Matthew Meszaros
|
f5eeac7b2a
|
feat: address the CodeRabbit review by carrying every stretch of stylesheet the CSS parser cannot read through as a verbatim item, since the sheet is rewritten from parsed items the moment any rule inlines and an unrelated match was deleting the rest, keeping a link's destination out of the content score now that the text renderer emits it so a CTA pointing at a free-trial page stops costing eight points, promising inlining in the editor only for a stylesheet that is actually eligible for it, skipping the client notes entirely for a plain-text campaign that ships no HTML part, switching a step into HTML mode when a template replaces its body with document markup rather than waiting for the next visual edit to gut it, accepting a pasted background shorthand only when it is a single colour so Word's "yellow none repeat scroll" stops becoming an invalid longhand, listing in SCHEMA_TAGS only the tags the mounted schema actually keeps so the warning fires for h1, font, center, thead and caption instead of staying silent while they are dropped, and correcting the guide's byte-for-byte claim and its unconditional plain-text claim
|
2026-09-09 08:30:49 -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
|
a96a44d916
|
Merge remote-tracking branch 'origin/main' into refactor/automatic-worker-mailbox-placement
|
2026-09-09 07:19:03 -07:00 |
|
Matthew Meszaros
|
cdbdad09ee
|
feat: stop the unibox conversation list resetting to the top when an email is opened, by keying the app shell's route boundary and Suspense on route identity rather than the raw pathname (the open thread is a path segment, so every click was remounting the whole page), remembering each list's scroll offset across remounts and the mobile display:none pane, patching mark-as-read into the query cache instead of refetching every loaded page, and auto-loading the next page at the end of the list (issue #396)
|
2026-09-09 06:52:57 -07:00 |
|
Matthew Meszaros
|
a8d0e80f68
|
feat: address the CodeRabbit review: render EMAIL_BRAND_NAME in every transactional template body and subject instead of a hardcoded product name, name FRONTEND_BASE_URL as the source when emailed links come from it, warn on an insecure effective dashboard URL even when APP_URL was inferred rather than configured, and correct the unsubscribe guide's claim that an unset API_PUBLIC_URL disables link minting
|
2026-09-09 06:52:37 -07:00 |
|