Matthew Meszaros
|
41413afa2a
|
feat: keep a failed contact lookup distinguishable from a missing contact in the native automation actions by wrapping the repository error instead of folding it into the no-contact-matched message, as CodeRabbit's follow-up on the lead-intake PR pointed out
|
2026-09-06 00:54:05 -07:00 |
|
Matthew Meszaros
|
04a2ed59c9
|
feat: address the CodeRabbit review on the lead-intake PR by giving the webhook sink its own copy of every map payload so the automation goroutine never writes into the map still being marshalled for endpoint delivery, propagating contact lookup errors in the upsert action's skip mode and in the native actions adapter so a failed lookup is never mistaken for a missing contact, adding the contacts source CHECK as NOT VALID in migration 000129 to skip the table scan under the migration lock, defaulting a new create-or-update-contact node's email template to the address key the chosen trigger actually carries, correcting the n8n guide on which lead-form sources have a trigger node, naming API batches over 100 contacts among the silent bulk arrivals in the contacts guide, and updating the marketing automations page from nine to twelve triggers
|
2026-09-06 00:47:33 -07:00 |
|
Matthew Meszaros
|
a3989f9d9c
|
feat: turn automations into a lead-intake path so a Facebook, Instagram, LinkedIn or TikTok lead form pushed by Zapier, Make, n8n or any webhook becomes a tagged, campaign-enrolled contact without leaving Warmbly: add the warmbly.upsert_contact and warmbly.add_to_campaign built-in actions with templated field mapping, custom fields, tags, campaign and an if-exists policy, fire a rich contact.created event from the one contact write path (silent for file imports, sheet syncs and API batches over 100) and expose contact.created and form.submitted as automation triggers with condition fields, variables and sample data, carry an automation depth through events raised by an action so a flow that creates a contact cannot re-trigger itself past five hops, stamp automation-created contacts with the new automation source (migration 000129), share the campaign picker between the sheet sync wizard and the automation builder, document lead intake in the automations, Zapier, Make, contacts, forms, integrations, expressions and webhook pages plus a new n8n guide, mirror the new triggers and actions on the marketing automations page, and drop the 34 MB cli binary that was committed by mistake
|
2026-09-06 00:36:05 -07:00 |
|
Matthew Meszaros
|
508ee741cf
|
Merge remote-tracking branch 'origin/main' into fix/salvage-expired-batch
|
2026-09-05 21:33:20 -07:00 |
|
Matthew Meszaros
|
c88118661f
|
feat: record an admin cancel on a warmup generation batch job through a conditional MarkBatchCancelling update that only touches a job still running with a non-terminal batch status, so a cancel racing the poller can no longer overwrite the completed state and counts the poller just wrote or send the job back into the active set to be ingested twice
|
2026-09-05 21:24:11 -07:00 |
|
Matthew Meszaros
|
b0c090e521
|
feat: keep an admin-cancelled warmup generation batch job running with batch_status cancelling instead of marking it failed on the spot, so PollBatches reaches the cancelled branch that PR 333 added and ingests the conversations OpenAI finished before the cancel landed while the admin's reason survives the ingest, refuse a second cancel on a batch already cancelling, hide the admin Cancel button while a batch is cancelling, and refresh the PollBatches, CancelBatch and WarmupBatchPoller doc comments that still said expired and cancelled batches are marked failed
|
2026-09-05 21:14:46 -07:00 |
|
joao-crm
|
9b44f84fb2
|
feat: ingest what an expired or cancelled warmup generation batch did finish instead of discarding it, since OpenAI still hands back the requests it completed before the window closed and the poller was marking the job failed with zero generated while a paid output file sat unread, with the terminal-batch decision lifted into endedBatchOutcome so the reason is recorded alongside the salvaged rows
|
2026-09-05 15:43:07 +00:00 |
|
Matthew Meszaros
|
3bf8d4bdfa
|
Merge remote-tracking branch 'origin/main' into feature/mailbox-fair-use-allowance
|
2026-09-04 21:25:53 -07:00 |
|
Matthew Meszaros
|
c7da25d126
|
fix: never leave a per-IP rate-limit counter without a TTL, which would block that address forever once it passed the limit, by dropping the key and failing open when EXPIRE fails and repairing a missing expiry on the reject path, and assert the exit status as well as the message when the CLI installer rejects a flag
|
2026-09-04 21:12:27 -07:00 |
|
Matthew Meszaros
|
bf46839fb7
|
feat: address the CodeRabbit review on the mailbox allowance work by reserving the mailbox slot inside the account insert transaction under a per-organization lock so concurrent connects cannot both take the last one, resolving the storage limit under the quota lock so a plan change cannot be raced past, deleting refused attachment objects on a context that outlives the request, settling already-connected rows before the bulk batch spends allowance, leaving password columns out of the failed-rows CSV, stopping click propagation from the portalled allowance dialog, and counting bulk progress once
|
2026-09-04 21:11:25 -07:00 |
|
Matthew Meszaros
|
b35e111705
|
fix: address the review on the CLI PR: give the sign-in handshake its own per-IP budget so a 200-poll login cannot lock the address out of the browser login, keep https for a remote host that names a port instead of sending a bearer token in cleartext, report truncation when a paginated walk stops at max-pages, accept a piped secret with no trailing newline, normalise WEBSOCKET_URL on its suffix so a bare /socket becomes a real endpoint, destroy a minted secret the moment its code expires, gate cli-installer-ci on the required status check, print a rejected flag instead of an unbound-variable error, and use a portable sha256 so the packaging runs on macOS
|
2026-09-04 21:03:58 -07:00 |
|
Matthew Meszaros
|
3596a9770f
|
feat: make mailboxes truly unlimited under a fair-use allowance of one mailbox per daily send the plan includes (15,000 on Business), drop the 200 hard cap and the 5-per-day connect throttle, open a request-more dialog with inline limit requests and plan upgrade when the allowance is reached, add bulk CSV mailbox import with live progress and a downloadable failed-rows file, reserve attachment storage atomically under a per-org lock so concurrent uploads cannot pass the quota (#326), report storage and the allowance on the billing usage meters, and honor approved daily-send overrides in the sender
|
2026-09-04 21:00:26 -07:00 |
|
Matthew Meszaros
|
d80816efa1
|
feat: make a successful warmbly auth login always the active host instead of deciding it from three overlapping conditions, and say why the CLI state file tolerates an unwritable home
|
2026-09-04 20:16:56 -07:00 |
|
Matthew Meszaros
|
f68918d7f6
|
Merge remote-tracking branch 'origin/main' into feature/warmbly-cli
|
2026-09-04 20:14:46 -07:00 |
|
Matthew Meszaros
|
f46fc86a7c
|
feat: add the warmbly CLI at cmd/cli, a signed-in multi-host client of the public REST API with 30 command families over one spec table, gh-shaped api passthrough, live event tailing, tables on a terminal and JSON in a pipe, and a confirmation gate in front of everything that puts real mail on the wire
|
2026-09-04 20:14:33 -07:00 |
|
Matthew Meszaros
|
028689fd2e
|
feat: device-code sign-in for the CLI, with a browser approval page at /cli that mints a scoped API key, self-revocation at DELETE /api-keys/self so a read-only credential can always end itself, and app_url plus websocket_url on /auth/config so a client can find the dashboard and the realtime gateway on a self-hosted layout
|
2026-09-04 20:14:27 -07:00 |
|
Matthew Meszaros
|
5fd9aedb80
|
Merge remote-tracking branch 'origin/main' into feature/plan-upgrade-paywall-modal
|
2026-09-04 09:11:51 -07:00 |
|
Matthew Meszaros
|
e5360713e7
|
Merge remote-tracking branch 'origin/main' into feature/install-script-setup-wizard
|
2026-09-04 06:43:12 -07:00 |
|
Matthew Meszaros
|
d78e4423e4
|
fix: address the review of the notifications work — bound detached alert delivery to a fixed pool that drops and logs rather than spawning a goroutine per event, never echo a transport error that embeds the webhook URL, treat an emptied channel target as cleared so switching transport cannot post Slack payloads to a Discord URL, emit user.registered for invited signups and the worker alert after a successful reassignment, format Stripe amounts by currency exponent, refuse an upgrade while the plan list is still loading instead of silently opening the portal, apply a fixed discount to the annual invoice rather than to each month, convert proration from minor units, contain focus in the nested enterprise dialog, hide the odometer wheels from assistive tech, and drop the last dedicated-IP row from the pricing matrix
|
2026-09-04 06:33:20 -07:00 |
|
Matthew Meszaros
|
9a2184fda7
|
Merge remote-tracking branch 'origin/main' into fix/step-scoped-attachments
|
2026-09-04 06:28:26 -07:00 |
|
Matthew Meszaros
|
77058a2cb4
|
feat: address the review on the installer branch by keeping the database password out of pg_dump's argv, excluding backup bundles from the blob root they are written into, tolerating blobs that change or vanish mid-archive, making the instance-settings bootstrap a single atomic insert, and validating the release tag before it is written into .env
|
2026-09-04 06:24:05 -07:00 |
|
Matthew Meszaros
|
fb868dfe40
|
feat: delete the storage objects of a step's attachments when the step is deleted, since the attachment rows cascade away with the sequence and left their bytes counted against the organization's storage quota with no row left to reach them
|
2026-09-04 06:20:26 -07:00 |
|
Matthew Meszaros
|
a54774c0a5
|
feat: install the attachment upload's body cap before the first form field is read, since reading step_id parses the whole multipart body and left the MaxBytesReader that followed it with nothing to limit
|
2026-09-04 06:19:29 -07:00 |
|
Matthew Meszaros
|
85f3dad215
|
feat: send the files a step actually carries by honouring campaign_attachments.sequence_id in the send, test-send and preview paths instead of attaching every campaign file to every step, count them per step in the preflight content score, and refuse an upload naming another campaign's step
|
2026-09-04 06:16:16 -07:00 |
|
Matthew Meszaros
|
05e19ffb69
|
feat: scope the campaign attachment routes to the caller's organization, so listing, uploading to or deleting from a campaign id belonging to another workspace is a 404 instead of leaking presigned download URLs, adding a file that workspace then sends, or deleting their stored objects
|
2026-09-04 06:16:16 -07:00 |
|
Matthew Meszaros
|
81d6ba4520
|
Merge remote-tracking branch 'origin/main' into feature/plan-upgrade-paywall-modal
|
2026-09-04 06:09:14 -07:00 |
|
Matthew Meszaros
|
a0c9d5a5b0
|
feat: add operator notification channels an admin configures in the panel (Discord, Slack, HMAC-signed webhook, or email) with per-channel event subscriptions, a synchronous test probe, SSRF-guarded URLs and credentials redacted on read, wire nine instance events including the enterprise inquiry that previously wrote a row nobody was told about, and reword the plan-specific limits copy so it reads correctly without billing
|
2026-09-04 06:02:40 -07:00 |
|
Matthew Meszaros
|
d68bbcd2ab
|
feat: add a one-command self-host installer at warmbly.com/install.sh with an interactive data-control wizard, give docker-compose.yml image keys and per-store volume variables, add an image-mode updater, move engagement/form/audit retention into instance settings, and add warmblyctl backup/restore
|
2026-09-04 05:49:54 -07:00 |
|
Skylinerffm97
|
1749d5c48e
|
feat: persist schedule_windows on POST /campaigns by adding the field to models.CreateCampaign, validating it with CampaignScheduleWindows before the transaction and writing it in the create INSERT, with a unit test for rejected windows, a live repository test for the round trip and the create field table in the campaigns API reference (issue #307 item 5)
|
2026-09-04 12:58:09 +02:00 |
|
Matthew Meszaros
|
483d6c2fe7
|
Merge remote-tracking branch 'origin/main' into fix/issue-307-test-send-preview-from-name
|
2026-09-04 03:34:35 -07:00 |
|
Matthew Meszaros
|
915390f42a
|
feat: match the closing body tag case-insensitively when placing the mailbox signature so a pasted document written with </BODY> still gets it inside the body, drop a step preview response whose request has been superseded so an out-of-order reply cannot repaint stale copy, and keep pulling mailbox pages in the preview sender picker while an enabled campaign sender is still unaccounted for
|
2026-09-04 03:11:53 -07:00 |
|
Matthew Meszaros
|
64e6e3a502
|
Merge remote-tracking branch 'origin/main' into fix/campaign-daily-budget-deferrals
|
2026-09-04 03:06:45 -07:00 |
|
Matthew Meszaros
|
de33b03891
|
feat: give the HTML mailbox signature its own block with a top margin instead of a hard double line break that stacked against the body's trailing margin and rendered as two to three blank lines in Apple Mail and Outlook, insert it inside the document when the body carries a closing body tag as the tracking pixel and opt-out footer already do, and say so in the mailboxes guide
|
2026-09-04 03:01:19 -07:00 |
|
Matthew Meszaros
|
2a19bf0519
|
Merge remote-tracking branch 'origin/main' into fix/campaign-daily-budget-deferrals
|
2026-09-04 02:59:01 -07:00 |
|
Matthew Meszaros
|
5c9d365163
|
feat: pick a closed-hours mailbox that stays closed for the next ten minutes so the scheduling pass cannot run after it opens, and assert the mixed-pool deferral lands on the reopening from both sides instead of accepting any earlier time
|
2026-09-04 02:59:00 -07:00 |
|
Matthew Meszaros
|
997aa2c748
|
Merge remote-tracking branch 'origin/main' into fix/issue-307-test-send-preview-from-name
|
2026-09-04 02:58:40 -07:00 |
|
Matthew Meszaros
|
8ce331a7ac
|
feat: fix the campaign test-email endpoint answering 404 for every caller by scoping its campaign lookup to the organization instead of the user, let it send from any mailbox of the organization and render a real contact through a new contact_id, attach the campaign's files, and extend the template preview with contact_id, campaign_id and account_id so it applies the signature, opt-out footer and plain-text rule the send path does
|
2026-09-04 02:58:36 -07:00 |
|
Matthew Meszaros
|
f844c14804
|
feat: carry the mailbox display name in the emsg body blob of every send so a renamed sender reaches the worker on its next message instead of waiting for an inactive-active toggle, read it into the From header of the Gmail, Graph and SMTP clients with the name cached at load time as the fallback, and say so in the mailboxes guide
|
2026-09-04 02:58:36 -07:00 |
|
Matthew Meszaros
|
eb85224cc8
|
Merge remote-tracking branch 'origin/main' into fix/contact-timeline-opaque-cursor
|
2026-09-04 02:57:59 -07:00 |
|
Matthew Meszaros
|
850ff2b6a2
|
feat: lock the campaign row for update while replacing its linked segments so two concurrent replacements cannot commit the union of their sets, and return the status read under that lock from ReplaceForCampaign so the wake or restart reaction no longer depends on a post-commit link lookup that a concurrent detach could empty
|
2026-09-03 20:46:27 -07:00 |
|
Matthew Meszaros
|
ab0c756aa2
|
feat: show a campaign's linked segments on the Leads tab as chips with live enrolled and held-out counts that filter the list, explain an empty list caused by an empty segment or hand-removed members and add them back in one click, add a scope-aware Export to campaign leads and segment members with a campaign-ready preset that carries lead status and engagement, write the links and the enrolment of PUT /campaigns/:id/segments in one transaction so a failed enrolment changes nothing instead of answering added 0, restart a completed campaign when a one-shot enrol adds leads, clear the manual-removal record when a contact is added by hand, count every link's members in one scan, audit sweep enrolments so open Leads tabs refresh, and document it in the campaigns and segments guides and the API reference
|
2026-09-03 20:38:27 -07:00 |
|
Matthew Meszaros
|
4bc971eecb
|
feat: resume a campaign whose pool mixes capped and hours-closed mailboxes at the earlier of tomorrow and the closed mailbox's reopening, log the daily cap only when every usable mailbox is capped, and add the mixed-pool live regression
|
2026-09-03 20:26:21 -07:00 |
|
Matthew Meszaros
|
0981635c3a
|
feat: reject a contact timeline cursor whose source rank names no merged table with a 400 in the handler through ContactTimelineSource.Valid, since rank zero is reserved for the legacy before bound and a rank past the last source would re-admit the events at the cursor's instant
|
2026-09-03 20:21:42 -07:00 |
|
Matthew Meszaros
|
630dd4cab1
|
feat: add a live repository test that walks ten timeline events, eight of them at one instant across progress stamps, notes and activities, in pages of three and proves nothing is skipped or repeated, each cursor is the last event's key, the final page carries no cursor, and before still means strictly older
|
2026-09-03 20:19:16 -07:00 |
|
Matthew Meszaros
|
a4665579de
|
feat: accept an opaque cursor on GET /contacts/:id/timeline, keep before as a deprecated alias that maps onto the keyset at rank zero, and answer an invalid cursor, before or limit with a 400 instead of silently ignoring it
|
2026-09-03 20:19:16 -07:00 |
|
Matthew Meszaros
|
88d8a2ba8a
|
feat: page every contact timeline source on a row comparison against the (at, source, id) cursor, unnest campaign progress stamps to one row per event so the limit and the logged-open and logged-click suppression apply per event, fetch one row past the page from every source, return all matching suppression entries, and encode the next cursor from the last event's key
|
2026-09-03 20:19:16 -07:00 |
|
Matthew Meszaros
|
18a1862d82
|
feat: rank the contact timeline's sources in models.ContactTimelineSource, give every event a ContactTimelineKey (at, source, id) with the newest-first comparison the merged sort uses, and add the standard pagination envelope to ContactTimelineResult while keeping has_more as a mirror
|
2026-09-03 20:19:16 -07:00 |
|
Matthew Meszaros
|
407a85ecf9
|
feat: cover the merged-feed cursor codec with a round-trip test that keeps sub-second precision and rejects a bare timestamp, a wrong-version token, bad base64 and trailing garbage
|
2026-09-03 20:19:16 -07:00 |
|
Matthew Meszaros
|
0cb4f312a0
|
feat: add a versioned opaque cursor codec for merged feeds to internal/utils/paging that carries an (at, source rank, id) keyset position and decodes a malformed or wrong-version token to a 400
|
2026-09-03 20:19:16 -07:00 |
|
Matthew Meszaros
|
1c88c2196b
|
feat: add live tests proving wake-ups leave the daily budget and min-gap untouched, real sends still count, and a capped campaign parks a wake-up with a single daily log line instead of pausing
|
2026-09-03 20:18:43 -07:00 |
|