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 |
|