Commit Graph
250 Commits
Author SHA1 Message Date
Matthew Meszaros cc0871d1b8 feat: contacts search gains an additive lead_status filter plus per-status lead_counts on the first page when exactly one campaign_id is set - the SQL predicates reproduce the read-time status derivation exactly (unsubscribed > bounced > replied > active > pending via LATERAL bool_or rollups), invalid lead_status or multi-campaign combinations return 400, and the web types/table pick up the new lead_counts shape 2026-07-11 10:11:36 +02:00
Matthew Meszaros 3acb51df6c feat: add server-side status-bucket filtering to GET /campaigns (draft/active/paused/completed, paused matches every paused_* variant, invalid values 400) and a new GET /campaigns-overview endpoint returning status and per-folder counts, with the campaigns API reference and endpoint scope map updated 2026-07-07 09:40:27 +02:00
Matthew Meszaros a20ba926cb feat: add native Apple/Google sign-in to the backend - POST /auth/apple and /auth/google exchange provider-signed ID tokens for sessions, GET /auth/providers exposes configured providers for app discovery, with a JWKS-verifying idtoken package, auth config, stable error codes, and API/security docs 2026-07-07 05:56:35 +02:00
Matthew Meszaros ad1d40fd2b test: cover the gmail/graph message mapping (read-state inversion, spam/category labels, unpadded base64url bodies, warmup and classification header surfacing), the imap header-flag parser, the graph MIME builder, and the human-behavior timing (sub-minute randomisation, daily volume factor, night-deferred and heavy-tailed engagement) 2026-07-04 11:45:01 +02:00
Matthew Meszaros f9142345ca feat: occasionally skip all positive warmup engagement on a message so a mailbox files but never opens some mail, avoiding a perfect every-message-engagement pattern while keeping spam-rescue and foldering 2026-07-04 11:38:23 +02:00
Matthew Meszaros 8b0f08c08d feat: throttle the worker reconciler to republish each mailbox at most every five minutes so the safety-net loop stops re-shipping every account's credentials over Kafka each tick, while onboarding and reassignment still load immediately 2026-07-04 11:36:47 +02:00
Matthew Meszaros 041ae5afd5 feat: resolve inbound bounce events back to the original campaign send by message id and record them idempotently through the deliverability pipeline (suppression, campaign progress, breaker), and document permanent-only bounce detection 2026-07-04 11:36:47 +02:00
Matthew Meszaros ab3c925eca feat: detect permanent NDRs worker-side from the synced bounce body across gmail/graph/imap and emit an INBOUND_BOUNCE event, giving api-sent mail its only bounce signal without adding SQL or S3 to the worker 2026-07-04 11:36:47 +02:00
Matthew Meszaros 3738f17643 feat: make warmup read engagement heavy-tailed up to an hour instead of uniform within four minutes and defer read/star/important actions into the recipient's waking hours so no pool mailbox reads mail at 3am 2026-07-04 11:27:36 +02:00
Matthew Meszaros b8e4002adb feat: fetch the warmup verify token and machine-reply headers via BODY.PEEK on IMAP sync and surface them as flag pseudo-headers, and join replies to the parent's thread instead of forking a new thread at every reply depth 2026-07-04 09:30:27 +02:00
Matthew Meszaros 3e4c3e9655 feat: write the caller's Message-ID header on SMTP sends so the recorded id matches the wire message for reply and bounce correlation, classify refused recipients as recipient-rejected instead of server-unreachable, and use the resolved host for the SMTP client handshake 2026-07-04 09:30:27 +02:00
Matthew Meszaros 1d4212c725 feat: key the Gmail messageId map by the Gmail message id so remove and label lookups match the add entry, and translate Gmail label transitions into internal flag add/remove events with the UNREAD inversion 2026-07-04 09:30:27 +02:00
Matthew Meszaros 4c0da59763 feat: categorize Graph warmup mail by surfacing the verify token into flags and filing it into the Warmbly folder, re-resolving the live message id from the immutable RFC Message-ID so post-move engagement actions never act on a stale id 2026-07-04 08:07:50 +02:00
Matthew Meszaros cb13c65d5d feat: load active mailboxes onto their assigned workers via a backend reconciler and immediately on onboarding, decrypting each account's credentials into the AddWorkerEmail payload, fixing gmail/outlook/smtp accounts that were assigned but never loaded 2026-07-04 08:07:49 +02:00
Matthew Meszaros 52c5f224fa feat: rebuild the provider oauth2 config locally on the worker so delegated mailbox tokens refresh, and ship BOX_ google/outlook client credentials to provisioned workers through the orchestrator env 2026-07-04 08:07:49 +02:00
Matthew Meszaros eb0a5654fd feat: persist the opaque per-folder Graph delta cursor in a new email_delta_links table via a repository and a GRAPH_DELTA_UPDATE consumer handler wired into the consumer service 2026-07-04 08:07:49 +02:00
Matthew Meszaros 049d751a11 feat: route the outlook provider through Microsoft Graph in the wmail worker with nil-guarded send/sync/new-email dispatch and a delta-cursor event, request delegated Graph OAuth scopes instead of the legacy IMAP/SMTP scopes, and always sync Outlook mailboxes 2026-07-04 08:07:49 +02:00
Matthew Meszaros d4ead05456 feat: persist campaign sequence canvas coordinates with x/y columns (migration 000053) plus a bulk sequence-layout service/repo path that scopes by campaign owner and never bumps updated_at 2026-06-30 10:06:20 +02:00
Matthew Meszaros 73838cecf5 feat: add an unaudited automation node-layout endpoint handler/service/repo backed by an atomic jsonb x/y merge that leaves edges, config, and updated_at untouched 2026-06-30 10:06:19 +02:00
Matthew Meszaros 9dd37b0d62 Merge pull request #52 from warmbly/referral-credits
feat: implement referral program with credit-based rewards
2026-06-28 09:12:57 +02:00
Matthew Meszaros 22b75c9165 feat: implement ListByOrganization on the discount service test's fake redemption repo so the package typechecks under golangci-lint in CI 2026-06-28 06:35:42 +00:00
Matthew Meszaros 0d22e546a9 feat: update the discount service test's fake redemption repo to the new offset-based ListByCode signature 2026-06-28 05:58:25 +00:00
Matthew Meszaros 22bce66503 feat: thread an offset instead of a UUID cursor through the discount service ListRedemptions to match the offset-paged repository 2026-06-28 05:58:25 +00:00
Matthew Meszaros 233dee8766 feat: move danger-zone deletion emails onto the shared templates package and delete the off-brand standalone emails.go wrapper 2026-06-28 05:27:28 +00:00
Matthew Meszaros 57adf4f9b2 feat: route notification.deliverEmail through GenerateNotificationHTML and drop the hand-rolled htmlEscape/inline-fragment email body 2026-06-28 05:27:28 +00:00
Matthew Meszaros b1f26e24f9 feat: list an organization's promo redemption history through the discount service and repository for the billing page 2026-06-28 05:09:50 +00:00
Matthew Meszaros a21f4d0d0e feat: capture the signup referral code through the auth registration flow and the WireReferral attributor hook 2026-06-28 05:09:50 +00:00
Matthew Meszaros 234e624fdc feat: add the Stripe customer-balance applier and wire referral reward, qualify, and clawback hooks into the Stripe webhook handlers 2026-06-28 05:09:50 +00:00
Matthew Meszaros 8b05f381f7 feat: add the referral service covering code minting, signup attribution, the reward and clawback lifecycle, and Stripe customer-balance sync in internal/app/referral 2026-06-28 05:09:50 +00:00
Matthew Meszaros 2c910dcdeb feat: make a campaign step's Original a first-class weighted A/B arm driven by a single draggable traffic-split bar, persisting the control share as an is_control variant row 2026-06-15 08:11:53 +02:00
Matthew Meszaros 03acdb87e3 fix: thread organization_id through contact, CRM, and unibox reads and writes so non-owner org members see and edit their workspace data, and backfill contacts.organization_id for single-membership users (migration 000049) 2026-06-15 08:11:53 +02:00
Matthew Meszaros c5dfa5e4e7 feat: remove the HTTP-request action from campaign steps and automations in favor of signed webhooks, keep fire_event for custom payloads, and drop the now-unused outbound quota plumbing 2026-06-15 08:11:35 +02:00
Matthew Meszaros 9d0c432be7 feat: let OAuth apps subscribe to webhooks by declaring a url/events/secret and materializing per-org endpoints gated by each grant's scopes, with secret rotation and delivery observability (migration 000050) 2026-06-15 08:11:20 +02:00
Matthew Meszaros 173736a004 feat: add a Stripe-grade webhook platform with a typed event catalog, HMAC-signed delivery, retries with backoff, endpoint ownership verification, per-endpoint throttling, an audit-spine event bridge, and firehose emit sites (migration 000048) 2026-06-15 08:11:20 +02:00
Matthew Meszaros fcafac4195 refactor: remove the campaign 'notify (webhook)' step type now that the HTTP request step covers outbound calls and there is no webhook setup surface 2026-06-14 10:48:06 +02:00
Matthew Meszaros ab24d8bbc8 feat: add a 'Fire event' action and campaign step that publish custom events to the realtime gateway (no public URL), an HTTP-request campaign step, a configurable automation dry-run test with per-step toggles, and fix the false 'updated by a teammate' toast on your own save 2026-06-14 09:52:49 +02:00
Matthew Meszaros fcdb31cda7 feat: OAuth apps always issue a client secret (drop the public/PKCE-only client type, secret required for the token exchange), add an app-logo upload endpoint, and align the docs to OAuth2 with optional PKCE 2026-06-14 09:52:49 +02:00
Matthew Meszaros 8c175d4221 feat: add an OAuth 2.1 authorization server (migration 000047 apps/codes/grants, app registration CRUD, authorization-code-with-PKCE authorize+token+refresh-rotation+revoke endpoints, RFC 8414 discovery, bearer-token validation wired into the auth middleware reusing the API-permission gates, scopes mapped to API permission bits) 2026-06-13 13:56:39 +02:00
Matthew Meszaros 20935ef061 feat: add a nil-safe per-org daily outbound-action quota (Redis daily counter, anti-abuse ceiling on the HTTP-request automation node, wired in both backend and consumer, fail-open) to bound webhook relay abuse 2026-06-13 13:41:20 +02:00
Matthew Meszaros 1fa9c65ada fix: harden every user-supplied-URL outbound path against SSRF with a shared dial-time guard (resolves the host, blocks private/loopback/link-local/metadata IPs, pins the validated IP to defeat DNS rebinding, re-validates redirects) and log automation HTTP requests + blocked attempts with org attribution 2026-06-13 13:34:19 +02:00
Matthew Meszaros 501b5009b4 feat: add an on-error branch to automation action nodes (try/catch routing, rose on-error handle, executor follows the error edge and treats the failure as handled instead of failing the run) 2026-06-13 13:15:41 +02:00
Matthew Meszaros 9aa3300f46 feat: capture per-action output in automation run history (HTTP status/ok, set-variables values, rendered channel/url/message) and render it under each action in the builder History panel 2026-06-13 13:11:58 +02:00
Matthew Meszaros 331745ecc5 feat: add a generic per-automation inbound webhook trigger (inbound.webhook event, token-gated POST /api/v1/integrations/inbound/automation/:token, migration 000046 inbound_token, background graph run with the JSON body as event payload) 2026-06-13 13:04:10 +02:00
Matthew Meszaros f1cf470121 feat: render Discord notifications as sky-themed rich embeds and Slack notifications as sky-accented attachment cards with contact and subject fields instead of plain text lines 2026-06-13 12:41:26 +02:00
Matthew Meszaros 534928cfdd feat: add a safe Set-variables (transform) automation node — computes named values from Go templates against the event + prior step output and writes them back for later steps to reuse, running the same sandboxed text/template engine as every other action value (no I/O, no arbitrary code execution) 2026-06-13 12:18:45 +02:00
Matthew Meszaros f4a2b87c50 feat: add a configurable warmbly.http_request automation action (the generic send-a-webhook/call-any-API node) — templated method/url/headers/query/body, SSRF-guarded + bounded retry, captures the response back into the event data under an output key so downstream nodes use {{.response.body...}} and conditions branch on {{.response.ok}} 2026-06-13 12:02:11 +02:00
Matthew Meszaros 57e8705a82 feat: make public API list cursors opaque base64 tokens (internal/utils/paging) instead of raw record UUIDs, decoding on input with a 400 on a bad cursor; admin endpoints keep transparent UUID cursors 2026-06-13 07:18:23 +02:00
Matthew Meszaros c5911fe37a feat: fire run_automation on campaign instant branches (reply/open/click) through a wired AutomationRunner instead of stamping the action node sent without ever running the flow 2026-06-13 06:26:48 +02:00
Matthew Meszaros ba89a932cd feat: run the label_email action on reply — campaign instant and scheduled paths via advanced LabelThread/LabelLatestThreadForContact, automations via execNativeAction reading thread_id and _user_id from the reply payload — and move the native-actions adapter to a shared package wired into the consumer too so reply/bounce/warmup automation actions stop silently failing 2026-06-12 16:44:16 +02:00
Matthew Meszaros 8de7e32857 feat: treat a campaign step's own email as the A/B control arm so contacts split across the original plus active variants by weight, and redesign the step variants editor to show the original and variants as one weighted set with live split percentages 2026-06-12 08:04:03 +02:00