Commit Graph
2400 Commits
Author SHA1 Message Date
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
SUMAN JANA 727ddb1482 feat: wire the unibox thread header's Mark as unread, Archive and Delete to a new PATCH /unibox/folder, add an Add as contact action for senders outside the CRM, and replace six private From-header parsers with one shared lib/helper/emailAddress that also understands the parenthesised form the IMAP sync stores, which left the reply composer's seeded To failing its own validator 2026-09-11 03:10:18 -07:00
SUMAN JANA 73f6bff2ed feat: stop a browser signed in as someone else from being offered Accept on an invite it cannot accept, comparing the signed-in address with the invited one on the invite page and offering Switch account instead, and naming both addresses in the backend's 403 so the cause is visible 2026-09-11 03:10:18 -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 947ba4f2d0 Merge pull request #429 from warmbly/fix/rds-tls-verification
fix: sslmode=verify-full against RDS could never have worked
2026-09-10 20:29:35 -07:00
Matthew Meszaros 62903b3806 Merge pull request #428 from warmbly/fix/tracking-rustls-provider
fix: the tracking service panics on its first TLS connection
2026-09-10 20:29:23 -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 e7f25890d2 feat: install the ring crypto provider at tracking startup so the service can open a TLS connection at all, because rustls 0.23 refuses to choose when both aws-lc-rs and ring are in the tree and panics at the first handshake, which took the whole service down the moment it pointed at a tls:// bus and which plaintext local development never reveals 2026-09-11 05:19:52 +02:00
Matthew Meszaros 1260dff108 Merge pull request #426 from warmbly/feature/posthog-error-tracking
feat: PostHog error tracking across every runtime, Sentry kept as an option
v0.4.4
2026-09-10 10:28:28 -07:00
Matthew Meszaros a84ab48729 Merge branch 'main' into feature/posthog-error-tracking 2026-09-10 10:25:21 -07:00
Matthew Meszaros 3bd9d2a1d7 Merge pull request #424 from warmbly/feature/issue-421-implementation
feat: locate every spam-check issue in the subject or body, and analyze campaign copy with AI
2026-09-10 10:18:10 -07:00
Matthew Meszaros 84a0ca0b29 feat: correct the noteStep guidance comment to match what the callers actually pass, a bounded route pattern rather than a fixed phrase, so the rule a future caller reads is the rule the trail is built on 2026-09-10 19:16:13 +02:00
Matthew Meszaros 79127c345d feat: drop a nil error and an empty message at the errs boundary instead of turning them into an issue with nothing in it, which the Sentry SDK used to swallow on its own and the PostHog one would have captured as a titleless exception 2026-09-10 19:15:21 +02: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 f8625b085a Merge remote-tracking branch 'origin/main' into feature/issue-421-implementation 2026-09-10 10:12:04 -07: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 abe9800d5b Merge pull request #425 from warmbly/fix/dockerfile-cache-mount-ids
fix: name every BuildKit cache mount so the images build on hosted builders
2026-09-10 10:09:33 -07:00
Matthew Meszaros 4b93e849a1 feat: drop the occurrence struct left behind in the round-robin span emitter, which the map of per-term span lists replaced before it was ever used and which golangci-lint's unused check does not flag for an unreferenced type 2026-09-10 10:07:18 -07:00
Matthew Meszaros 512451c8d6 feat: give every BuildKit cache mount an explicit id so the Dockerfiles build on hosted builders that reject an unnamed one, which is what stopped the backend, consumer, worker, forms, cli, updater and tracking images from building on Railway with 'flag --mount=type=cache is missing an id argument' 2026-09-10 19:05:01 +02:00
Matthew Meszaros 77dfefcf88 feat: give every occurrence of a repeated trigger term its own span rather than only the first, since pointing at one 'free' out of three sends the writer back to hunt for the other two on the next re-check, and emit the spans round by round so every term shows once in every half before any shows twice, because the list is capped for display and a word written twenty times would otherwise fill it and hide the other terms that are also wrong 2026-09-10 10:01:57 -07: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 e7b9491975 feat: drop an AI finding's category when the model returns one outside the closed set the API documents, so a client validating the response against that enum is never handed something outside it, and correct the parse comment that still described an unreadable response as falling back to the rules pass when Analyze now refuses it and refunds 2026-09-10 09:28:00 -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 427c9ce27c feat: pin the invariant the trigger-span offset map rests on, that foldIndex folds byte-for-byte identically to strings.ToLower and lands every recorded offset on a rune boundary, across Turkish dotted I, the Kelvin sign, ligatures, titlecase runes and invalid UTF-8 where a bad byte becomes a three-byte replacement rune 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 3a9b1747dc feat: map a trigger term's offset back through the case fold before slicing the copy, so a rune that changes byte length when lowercased (U+0130, U+212A) no longer shifts every following span into bytes the writer never typed or cuts one in half into invalid UTF-8, read an issue's field from the whole span list before the display cap trims it so a subject-first list of more than eight can no longer relabel a both-halves issue, and refuse an AI response carrying a verdict with no score and no findings instead of pricing its empty finding list into a confident 100 out of 100 above a verdict saying the opposite 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 b8e31433a5 Merge pull request #423 from warmbly/feat/frontends-on-pages
feat: serve the dashboard and admin panel from a static host
2026-09-10 09:07:46 -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 368b2f1bef Merge pull request #422 from warmbly/fix/split-cloud-bus-bundle
fix: the split-deployment bus bundle could not start, and nothing would have caught it
2026-09-10 08:45:17 -07: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 5ef8b608c6 feat: record the split-cloud scripts and aws-bootstrap.sh as executable, which a checkout on a filesystem that does not preserve the mode had silently dropped so make lint died with Permission denied in CI only, and assert the recorded git mode in check-split-cloud so it cannot ship non-executable again 2026-09-10 17:30:16 +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 a3edc3b0be Merge pull request #419 from warmbly/fix/issue-415-contact-panel-rebase
Fix: re-subscribing a contact no longer pops a discard prompt
2026-09-10 06:57:25 -07:00
Matthew Meszaros 378e1d15ee feat: build the custom-field record from entries so a contact field named __proto__ is a real key instead of silently setting the prototype and dropping out of what gets saved, and count a row the user has typed a value into but not named as unsaved work, so leaving the panel on it asks rather than discarding it while Save stays disabled because there is nothing to send 2026-09-10 06:54:58 -07:00
Matthew Meszaros 6a6d7fa74b Merge branch 'main' into fix/issue-415-contact-panel-rebase 2026-09-10 06:50:02 -07:00
Matthew Meszaros a04d5d98e4 Merge pull request #420 from warmbly/feat/worker-capacity-soft-target
Worker capacity is a placement target, not a hard gate
2026-09-10 06:31:24 -07: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 cd051c7150 Merge branch 'main' into fix/issue-415-contact-panel-rebase 2026-09-10 05:42:35 -07:00
Matthew Meszaros e82a249792 Merge pull request #418 from warmbly/feat/issue-414-delete-api-key
Add a permanent delete for revoked API keys
2026-09-10 05:42:17 -07:00
Matthew Meszaros f9d9967389 Merge branch 'main' into fix/issue-415-contact-panel-rebase 2026-09-10 05:38:58 -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 6149f84c7d feat: give warmblyctl the same apikey purge the customer CLI has, so the operator half of the API surface can delete a revoked key too and the two CLIs name the verb the same way 2026-09-10 05:37:28 -07:00
Matthew Meszaros 396bab0e06 Merge branch 'main' into feat/issue-414-delete-api-key 2026-09-10 05:36:06 -07:00