Commit Graph
1504 Commits
Author SHA1 Message Date
Matthew Meszaros 751dd5e08c feat: turn off Stripe automatic tax on subscription and credit checkout, plan changes and proration previews in internal/app/stripe/service.go, keeping required billing address, business name and tax ID collection 2026-10-04 09:59:24 +02:00
Matthew Meszaros d112657cf2 feat: wire suppression, subscription and hold dependencies into the consumer's Salesforce service, give Salesforce token refreshes their own single-flight keyspace, release the outbox lease in memory after each terminal write so writeback notes land and only on rows with a logged Task, drop stale Salesforce import previews, keep keys from the import row menu from opening the edit dialog, and document the Salesforce callback URL and OAuth variables 2026-10-04 09:10:37 +02:00
Matthew Meszaros 6b7e254e56 feat: add native Salesforce sync with Lead and Contact matching and links, a leased activity outbox that logs sends, replies, bounces, opt-outs and meetings as Tasks, Lead Status and Email Opt Out writeback, a pull loop with CRM pause rules, list view and Campaign imports, sandbox and My Domain OAuth that refreshes expired sessions, a Salesforce settings page with contact and inbox cards in web, and docs 2026-10-04 08:54:27 +02:00
Matthew Meszaros 900806f328 feat: make HubSpot sync jobs lease-safe with per-claim tokens and one-at-a-time claims, log each email once across retries with the interested-reply outcome as its own job, move merged HubSpot contacts in a transaction, run backfill as one cursor job that skips refused records, rebuild the HubSpot client after a reconnect, accept a single portalId on card requests, and remember the Warmbly property group only after it exists 2026-10-04 08:18:16 +02:00
Matthew Meszaros 37e91fc89f feat: add HubSpot CRM mode where HubSpot deals, pipelines, tasks, notes and owners are mirrored and written through, sends and replies log as HubSpot emails, exit rules hold campaigns, list import, sync health, setup wizard in web, HubSpot app project with record card and workflow action, and docs 2026-10-04 07:47:51 +02:00
Claude 71f69f1856 feat: advance campaigns.updated_at in setForCampaignTx when linking segments inserts new campaign_segments rows so the send-plan snapshot is invalidated when an audience grows 2026-10-04 05:14:34 +00:00
Claude de230af27d feat: advance campaigns.updated_at when a segment set change detaches linked segments in setForCampaignTx, including clearing the set, so the send-plan snapshot is invalidated after leads are withdrawn 2026-10-04 05:02:11 +00:00
Claude 51482769f5 feat: advance campaigns.updated_at when a campaign's senders are replaced and when a tag or folder-only update runs so the send-plan snapshot keyed on it is invalidated and stops being served with stale false 2026-10-04 04:48:44 +00:00
Matthew Meszaros 8883a1df6b feat: connect Microsoft 365 organizations through Microsoft's v2.0 admin consent page followed by a sign-in on the same state, read the approving admin's directory role from the Graph token as well as the ID token, return an organization-wide approval link for single-mailbox Outlook sign-in (admin_consent_url) and show it in the connect panel, and document publisher verification and the admin approval path 2026-10-03 20:17:38 +02:00
Matthew Meszaros 0a95444c2f feat: send Slack inbox replies once in the background, keep AI drafts only after draft_reply succeeds, refuse thread locks on Redis errors, log Slack delivery failures and keep unreadable Slack connection config 2026-10-03 15:53:01 +02:00
Matthew Meszaros 61d16dfe9a feat: add Warmbly for Slack with the AI assistant in DMs, mentions and the assistant pane, unified inbox threads with reply, AI draft and lead actions, per-category notification routing and DMs, account linking, dashboard Slack settings, manifest and docs 2026-10-03 15:35:11 +02:00
Claude bbb692e9d6 feat: instrument campaign SendPlan read path with lookup and planner stage timings and retain safe timeout diagnostics in internal/app/campaign/handlers.go 2026-10-03 12:15:32 +00:00
Claude e3c5bd24a1 feat: guard campaign send-plan snapshot writes against version regression so a late older planner walk cannot overwrite a newer snapshot 2026-10-03 12:03:49 +00:00
Claude 84a5eee5c6 feat: bound campaign send-plan snapshot freshness by age and skip fresh snapshots via jobrun.Loop to avoid redundant cross-replica planner work 2026-10-03 11:22:12 +00:00
Claude bb580164e6 feat: compute each active campaign's send plan in a background snapshotter (internal/app/campaign) stored in campaign_send_plan_snapshots so GET /campaigns/:id/send-plan serves a stored snapshot instead of walking the planner on the request 2026-10-03 11:04:22 +00:00
Matthew Meszaros 4815f7b43c Merge pull request #809 from warmbly/claude/fix-798-inbound-bounce-errors
Make inbound bounce/complaint ingestion distinguish technical failures from genuine no-match
2026-10-03 07:01:07 +00:00
Matthew Meszaros 77ec1df58b Merge pull request #810 from warmbly/claude/fix-801-scheduler-keyset-paging
feat: bound campaign recipient selection with a two-phase ordered-candidate scan
2026-10-03 06:59:33 +00:00
Matthew Meszaros 6b38dd5e47 Merge pull request #811 from warmbly/claude/fix-796-analytics-accounts-pagination
feat: paginate and batch account analytics status reads
2026-10-03 06:59:24 +00:00
Matthew Meszaros 0c0d2a0223 Merge pull request #808 from warmbly/claude/fix-797-sendplan-coalescing
feat: coalesce cold-cache send-plan reads onto one planner walk
2026-10-03 06:59:08 +00:00
Claude 6d9f87e456 feat: run the send-plan coalescing walk on a bounded caller-independent context and let a canceled getOrCompute waiter return its own ctx.Err() promptly without affecting the shared flight 2026-10-03 06:49:24 +00:00
Claude 3288238cc0 feat: paginate and batch GET /analytics/accounts so account status reads are bounded per page and the overflow past 1000 mailboxes is reachable via cursor 2026-10-03 06:46:20 +00:00
Claude a77f25ce4f feat: bound campaign recipient selection via a cheap ordered-candidate enumeration plus chunked routedLeadsQuery hydration in FindRoutedPairs, with a campaign_leads(campaign_id,position,contact_id) index 2026-10-03 06:40:38 +00:00
Claude 80594bb120 feat: classify inbound bounce/complaint technical lookup failures as retryable and propagate them from the consumer handlers instead of dropping them as no-match 2026-10-03 06:37:35 +00:00
Claude c0ac841c3e feat: coalesce concurrent cold-cache send-plan reads onto one planner walk via readCache.getOrCompute in internal/app/campaign 2026-10-03 06:35:46 +00:00
Claude fc4832a5b3 feat: bound unibox overview_cache to one in-flight computation per scope by joining active flights regardless of age instead of starting overlapping ones past the freshness window 2026-10-03 06:33:57 +00:00
Matthew Meszaros 9ef54798dc Merge pull request #804 from Skylinerffm97/fix/unibox-mark-unread
fix(unibox): make Mark as unread stick, and let it reach a sent-only conversation
2026-10-03 05:11:39 +00:00
Matthew Meszaros 8db2409a81 feat: read dialTCP and smtpsEgress once at the top of DialSubmission and hand them to the dial goroutines and closeLosers, so the 465/587 race's goroutines that outlive the call never read the package variables a later dial or test may be replacing 2026-10-03 06:24:09 +02:00
Matthew Meszaros 45786649c7 feat: let the incoming reply repair query use idx_tasks_message_id and idx_contacts_org_email by matching each In-Reply-To in its bracketed and bare forms against the raw task Message-ID and resolving the mailbox's workspace before the contact address match, so a batch over the 45-day window finishes instead of hitting the statement timeout every minute 2026-10-03 06:07:20 +02:00
Skylinerffm97andClaude Opus 5.5 c433a483ec fix(unibox): make Mark as unread stick, and let it reach a sent-only conversation
useMarkSeen invalidated every ["unibox"] query after an unread, including the body queries ["unibox", "email", id]. A body GET marks the message read server side (GetByID), so the still-mounted reader undid the unread. Bodies never change once synced, so the unread path now skips them.

MarkSeenByThreads skipped every sent copy, so a conversation with no received message could not be marked unread at all. It now falls back to the newest sent copy when nothing was received. Received mail still wins, drafts never turn unread, and explicit ids and folder sweeps keep refusing sent and draft copies.

Herkunft: [Claude]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 15:31:48 +02:00
Matthew Meszaros a09ba27b0c feat: confirm a missing SPF or DMARC record with the sending domain's own authoritative nameservers before reporting it, look names up fully qualified so a resolver failure is never retried under the host's search domains and read as not found, look up internationalized domains in ASCII, record the verdict when a mailbox manager presses Check in the drawer, and show an unanswered lookup as unverified rather than missing 2026-10-02 06:13:37 -07:00
Matthew Meszaros 50d50d0fbc Merge pull request #793 from warmbly/fix/inbox-follow-up-sweep-paging
feat: page the hourly inbox follow-up sweep through each mailbox newest first in bounded keyset pages that resolve thread state only for the threads on the page, resume each workspace's cycle from a cursor persisted in inbox_follow_up_sweeps under a per-pass time budget, check recently active threads first every pass, and add the unibox_emails (email_id, internal_date, id) index the walk reads
2026-10-02 06:33:14 +00:00
Matthew Meszaros 39285173f1 feat: never move the follow-up changed-thread watermark past a page it failed to read, step past a failing page, thread or unreadable mailbox only after three failures spanning at least an hour, fence sweep state saves on the lease owner alone and log a takeover, clear a stale failure count once the walk moves on, and note that imported unibox rows keep their source ingested_at 2026-10-01 23:20:45 -07:00
Matthew Meszaros 0bcbab91ac Merge remote-tracking branch 'origin/main' into fix/inbox-follow-up-sweep-paging
# Conflicts:
#	internal/app/orgtransfer/spec.go
2026-10-01 23:20:32 -07:00
Matthew Meszaros b2310f5d4b feat: renumber the inbox follow-up sweep migrations from 000243-000247 to 000245-000249 so they follow 000243_campaign_task_subject and 000244_unibox_rail_layout on main instead of colliding with them 2026-10-02 08:15:42 +02:00
Matthew Meszaros e883e60c3d Merge pull request #795 from warmbly/fix/worker-465-egress
feat: name a worker's own blocked outbound 465 instead of blaming the mailbox's server
2026-10-02 06:12:30 +00:00
Matthew Meszaros e79551867f feat: have a worker learn from its own dials when its network blocks outbound 465, dial 587 at once there, tell a mailbox whose server only takes 465 that the block is on the sending side instead of blaming its server, report the block on every heartbeat as the node's last error, rename the admin Workers filter to Has node error, and document the outbound ports a worker needs 2026-10-02 08:02:36 +02:00
Matthew Meszaros 244b2e6613 feat: renumber the unibox rail layout migration to 000244 after main took 000243 2026-10-01 22:59:25 -07:00
Matthew Meszaros b8a8ec4743 Merge remote-tracking branch 'origin/main' into feat/unibox-rail-layout-per-member 2026-10-01 22:58:31 -07:00
Matthew Meszaros 1aeb45773b feat: check threads changed since each workspace's last follow-up pass by when the message was stored (new unibox_emails.ingested_at) or its verdict written, behind a persisted watermark, give each workspace's sweep a single leased walker whose saves are conditional on the lease, stop the cursor at the last thread whose label was written and step past a page or thread after three consecutive failures, keep the cycle running when the changed-thread check fails, and accept warmblyctl inbox-tag follow-ups --limit as a deprecated no-op 2026-10-01 22:52:43 -07:00
Matthew Meszaros 945fadb260 Merge pull request #788 from warmbly/fix/ab-variant-thread-subject
feat: thread campaign follow-ups on the A/B arm each contact was actually sent by recording every send's rendered subject on campaign_tasks.subject (migration 000243) and reusing it verbatim in ThreadParentForLead, and list the opening step's variant subjects in the follow-up composer
2026-10-02 05:46:33 +00:00
Matthew Meszaros 1e1acef6f4 Merge pull request #791 from warmbly/fix/unibox-refresh-load
feat: coalesce and dedupe unibox realtime refreshes in useRealtimeEvents, forward TanStack Query abort signals through every unibox client and the shared Request helper with cancellations kept out of error handling, share one organization-scoped unibox overview computation per second with in-flight dedup and write-time invalidation, bound interactive unibox reads at 30s including pool wait, and log slow pgxpool connection acquisitions
2026-10-02 05:46:17 +00:00
Matthew Meszaros bce968646f feat: thread campaign follow-ups on the A/B arm each contact was actually sent by recording every send's rendered subject on campaign_tasks.subject (migration 000243) and reusing it verbatim in ThreadParentForLead, and list the opening step's variant subjects in the follow-up composer 2026-10-01 22:41:11 -07:00
Matthew Meszaros 8f89c36756 feat: refresh the open conversation for inbox events that name only a message id, give unibox refresh keys added just before a max-wait flush a trailing flush, cancel a shared unibox overview computation once its last caller leaves and bound it and GET /unibox/overview at 30s, include scheduled sends in the coalesced inbox refresh, and word the slow pgxpool acquire log as acquire time rather than saturation 2026-10-01 22:41:00 -07:00
Matthew Meszaros 7707f6fb02 Merge pull request #789 from warmbly/fix/unibox-unread-latest-received
feat: mark only a conversation's newest received message unread on Mark as unread, never a sent or draft copy
2026-10-02 05:37:48 +00:00
Matthew Meszaros 54a05027cc feat: save the unibox scope rail's favorites, row and section order and hidden rows to the member's account per workspace through a unibox_rail view with a validated layout on /me/views, synced from the dashboard store so every device shows the same rail while folds and widths stay per browser 2026-10-01 22:37:23 -07:00
Matthew Meszaros 6758bc8035 feat: page the hourly inbox follow-up sweep through each mailbox newest first in bounded keyset pages that resolve thread state only for the threads on the page, resume each workspace's cycle from a cursor persisted in inbox_follow_up_sweeps under a per-pass time budget, check recently active threads first every pass, and add the unibox_emails (email_id, internal_date, id) index the walk reads 2026-10-01 22:29:41 -07:00
Matthew Meszaros e137530895 feat: run the jobrun scheduler tests on the testing/synctest fake clock and cover a claim that errors with or without its write landing, so each slot still runs exactly once 2026-10-01 22:29:39 -07:00
Matthew Meszaros dc2cffd786 feat: coalesce and dedupe unibox realtime refreshes in useRealtimeEvents, forward TanStack Query abort signals through every unibox client and the shared Request helper with cancellations kept out of error handling, share one organization-scoped unibox overview computation per second with in-flight dedup and write-time invalidation, bound interactive unibox reads at 30s including pool wait, and log slow pgxpool connection acquisitions 2026-10-01 22:25:53 -07:00
Matthew Meszaros a84b3bbbf3 feat: mark only a conversation's newest received message unread on Mark as unread, never a sent or draft copy, from the reader, the row menu, the selection bar, PATCH /unibox/seen and the mark_thread_seen AI tool, with the guide and API docs updated 2026-10-01 22:22:56 -07:00
Matthew Meszaros 7c8ed01775 feat: resume every scheduled job from its stored next_run_at after a restart instead of starting a fresh interval, run a job that came due while the process was down right after its phase offset, and claim each slot with a compare-and-swap on next_run_at so a job hosted by several processes runs once per slot 2026-10-01 22:16:16 -07:00