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
|
18486ecfd4
|
feat: add a generic branded notification email template with an optional CTA button for the in-app notification email channel
|
2026-06-28 05:27:28 +00:00 |
|
Matthew Meszaros
|
789da671d6
|
feat: send organization member invitations through GenerateInvitationHTML so they match the rest of the transactional mail
|
2026-06-28 05:27:18 +00:00 |
|
Matthew Meszaros
|
6b2ee63593
|
feat: add a branded team-invitation email template with html/template-escaped org and inviter names and a slate CTA button
|
2026-06-28 05:27:18 +00:00 |
|
Matthew Meszaros
|
7dcd5ac83f
|
feat: render the trial-expiration job notice via GenerateTrialExpiredHTML instead of the raw unstyled h2/ul HTML fragment
|
2026-06-28 05:27:18 +00:00 |
|
Matthew Meszaros
|
f57f211d20
|
feat: add a branded trial-expired email template rendered through the shared transactional base shell in internal/notify/templates
|
2026-06-28 05:27:18 +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
|
660d717456
|
feat: register the webhook and oauth-app-webhook routes and wire the delivery worker, audit-to-webhook bridge, and app domain resolver into the backend
|
2026-06-15 08:11:20 +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
|
0a81fd361b
|
feat: add safehttp dial-time SSRF guards and the whdomain subdomain-aware allowlist matcher used to harden outbound webhook delivery
|
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
|
3c7c0b6411
|
fix: finish the opaque-cursor doc sweep — change the offset query params to cursor on the CRM search operations in the OpenAPI spec, and drop the dead SearchContacts.Offset field and its docs (clamped but never used in SQL)
|
2026-06-13 11:00:59 +02:00 |
|
Matthew Meszaros
|
aed4a06190
|
feat: unify pagination by making the offset-based CRM deals/tasks search and meetings endpoints expose the same opaque next_cursor and {total, next_cursor, has_more} envelope as every keyset list (offset hidden inside the token), updating web clients, the OpenAPI spec, and the reference docs
|
2026-06-13 10:47:17 +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
|
587eae774e
|
feat: serve the entire customer API (auth + resources) only under /v1 with no unversioned alias, and repoint the web and admin clients to the versioned base accordingly
|
2026-06-13 07:18:23 +02:00 |
|
Matthew Meszaros
|
49b01c6b67
|
feat: version the public API under /v1 by mounting the customer surface under both /v1 and the bare paths, adding an API-Version response header and Deprecation/Sunset headers nudging API-key callers off the unversioned aliases
|
2026-06-13 06:27:01 +02:00 |
|
Matthew Meszaros
|
71abb12a38
|
feat: stop campaigns silently stalling on a transient scheduler error by retrying instead of completing the task, end past-end-date campaigns cleanly, record scheduler failures to the campaign log, add a campaign-chain reconciler, and surface failures live in the dashboard activity panel
|
2026-06-13 06:27:01 +02:00 |
|
Matthew Meszaros
|
919af47d29
|
feat: select the realtime transport by PUBSUB_ENABLED in backend/consumer and auto-provision the Pub/Sub topics and per-topic subscriptions on boot so prod never publishes to a subscription the Elixir fanout never created
|
2026-06-13 06:26:48 +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
|
4762256c49
|
feat: add the warmbly.label_email native action type and the label_ids action config field across the campaign ActionConfig and the IntegrationAction enum + IsNativeAction
|
2026-06-12 16:44:07 +02:00 |
|
Matthew Meszaros
|
496e474756
|
feat: add additive unibox thread-label repo methods — AddThreadLabels (insert-only, category-ownership guarded) and LatestThreadIDForContact (exact from_addr address match, never an ILIKE substring) — to back a reply-only label-email action
|
2026-06-12 16:44:07 +02:00 |
|
Matthew Meszaros
|
a7a43e0c4c
|
feat: rename the campaign sequences resource to steps across the API and URL (/campaigns/:id/steps), the JSON fields (target_step_id, step_id/step_name/step_index, analytics steps[], create body steps), the web client/models/route segment/labels, the audit step entity type, and the wire-contract docs; internal Go type names and the Kafka avro schema stay
|
2026-06-12 09:38:11 +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 |
|
Matthew Meszaros
|
0fd3d03f55
|
feat: add org-wide team presence privacy columns (presence_show_online, presence_show_activity) with update plumbing and a PRESENCE_POLICY_UPDATED realtime event so a settings change re-gates connected sockets live
|
2026-06-12 05:59:01 +02:00 |
|
Matthew Meszaros
|
8547fe97eb
|
feat: scope unibox MarkSeenBulk by organization so a non-owner member opening a thread clears the shared org-wide unread state instead of updating zero rows
|
2026-06-12 05:14:50 +02:00 |
|
Matthew Meszaros
|
4db027a342
|
feat: scope unibox GetByThread by organization instead of user_id so non-owner members see the full conversation they already see in the org-scoped inbox list, not an empty thread
|
2026-06-12 05:10:00 +02:00 |
|
Matthew Meszaros
|
ba3ab98e1e
|
feat: bridge realtime events over Redis pub/sub when Google Pub/Sub is unconfigured (RedisBus publisher in backend/consumer plus Realtime.Redis.EventSubscriber and a shared EventBroadcaster) so dashboard live updates and presence-driven collaboration actually fire in local dev
|
2026-06-12 04:49:58 +02:00 |
|
Matthew Meszaros
|
21b4ba4ea0
|
fix: let members with the integration permission save automations (write was gated on manage-settings while read used use-integrations, so a manager could open the builder but 403 on save) and surface the backend's real error in the save toast instead of a generic message
|
2026-06-11 18:15:55 +02:00 |
|
Matthew Meszaros
|
6a3b8ac0eb
|
fix: scope the unibox unread-count endpoint by organization_id so the sidebar Inbox badge counts the workspace's unread mail instead of always showing 0 for non-owner members
|
2026-06-11 18:05:18 +02:00 |
|
Matthew Meszaros
|
594c696bf6
|
fix: scope the unibox inbox list and overview by organization_id (via the workspace's email accounts) instead of the logged-in user_id, so every member sees the org's incoming mail; per-user thread labels and snoozes stay personal
|
2026-06-11 17:57:52 +02:00 |
|
Matthew Meszaros
|
21032a8fce
|
fix: scope the contacts list by organization_id instead of user_id so all members see the workspace's contacts (and per-contact campaign badges); categories badge still user-scoped pending an organization_id column on categories
|
2026-06-11 17:52:36 +02:00 |
|
Matthew Meszaros
|
88e241d536
|
fix: scope the analytics dashboard (overall stats, recent activity, top campaigns, daily trend, account health) by organization_id instead of user_id, so every workspace member sees the org's analytics rather than an empty dashboard
|
2026-06-11 17:49:39 +02:00 |
|
Matthew Meszaros
|
a21dc57e07
|
fix: scope campaign list/detail/count queries by organization_id instead of user_id, so all workspace members see the org's campaigns rather than only the creator
|
2026-06-11 17:47:04 +02:00 |
|
Matthew Meszaros
|
6ae5e52c4e
|
fix: scope email-account list/detail queries by organization_id instead of the logged-in user_id, so every member of a workspace sees the org's mailboxes (not just the owner who connected them)
|
2026-06-11 17:43:56 +02:00 |
|
Matthew Meszaros
|
709b77cdc6
|
fix: notification email links use the configured APP_URL instead of a hardcoded app.warmbly.com, so dev and self-hosted deployments link to the right host
|
2026-06-11 12:43:17 +02:00 |
|