Commit Graph
1002 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 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 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 a84ab48729 Merge branch 'main' into feature/posthog-error-tracking 2026-09-10 10:25:21 -07: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 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 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 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 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 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 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 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 08f1420c0b Merge branch 'main' into fix/issue-410-scanner-networks 2026-09-10 04:32:36 -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 6fe92c985f feat: stop asking a server without CONDSTORE for MODSEQ, which made every FETCH a malformed fetch-att that IONOS answered BAD so the mailbox synced nothing on every pass (issue #405), and gate the LIST RETURN options on LIST-EXTENDED for the same reason 2026-09-09 19:45:01 -07:00
Matthew Meszaros 054115ba91 Merge branch 'main' into fix/issue-405-imap-error-noise 2026-09-09 10:13:28 -07:00
Matthew Meszaros 2d20e1a6a0 Merge branch 'main' into fix/unibox-threading-and-transport-errors 2026-09-09 10:08:57 -07:00
Matthew Meszaros bb2b2b1743 feat: make the one-unresolved-error-per-code rule a partial unique index with a conflict path, collapsing the duplicate rows a repeating mail error already left behind 2026-09-09 09:46:39 -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 568bdb48ba feat: never render an empty IMAP error detail and close the CRM rail when the viewport narrows past lg 2026-09-09 09:24:43 -07:00
Matthew Meszaros 88ea60cd4d feat: renumber the custom-domain TLS lookup indexes to 000144 after main landed 000143 for campaign lead senders, because two migrations sharing a version stop golang-migrate before either runs 2026-09-09 09:07:26 -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 b74fff34e5 feat: prove the on-demand TLS domain lookup against the real schema, covering the campaign-level tracking override and the empty string that every row without a custom domain stores 2026-09-09 08:59:40 -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 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
SUMAN JANA 73d9c18bfe fix(imap, unibox): show the server's text for a codeless IMAP error; contact rail starts closed
- An IMAP NO/BAD without a response code (Gmail's "NO System Error")
  rendered as "Something went wrong: " in the mailbox's error list. Fall
  back to the server's text when the code is empty.
- The unibox contact rail opened by itself on lg+ screens, putting the
  contact form in front of every thread the reader opened. It now starts
  closed at every width and opens from the header toggle.
2026-09-09 15:47:50 +00: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 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 538dc29575 feat: stop the CSS inliner deleting the half of a selector list it cannot take over, so a rule like ".btn, .other:hover" keeps its declaration for the hover half after the first inlines, leave a rule whose selector list cannot be split on commas exactly as the author wrote it because a comma inside :is() or an attribute value belongs to the selector and rejoining the pieces writes a different one, keep a rule that matches nothing today rather than dropping it, and declare the paste-adoption ref above the editor that closes over it as the other paste-time refs already are 2026-09-09 08:20:23 -07:00