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
|
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
|
f68918d7f6
|
Merge remote-tracking branch 'origin/main' into feature/warmbly-cli
|
2026-09-04 20:14:46 -07:00 |
|
Matthew Meszaros
|
23f88293c8
|
feat: document the warmbly CLI at docs.warmbly.com/api/cli with every install channel, the device flow in api/authentication, the new auth/cli and api-keys/self routes in the endpoint scope map, a warmbly-cli agent skill, and a note on warmblyctl saying which of the two CLIs a reader wants
|
2026-09-04 20:14:43 -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
|
5c4f87c1aa
|
feat: list the campaign's unscoped attachments under a Sent with every step group in the step composer, so files the step really carries stop being invisible in the panel that claims to show them, and say in the confirm that removing one takes it off every step
|
2026-09-04 06:40:48 -07:00 |
|
Matthew Meszaros
|
b0db8cc02b
|
feat: chain the backup bundle cleanup behind a successful docker compose cp so a failed copy cannot delete the only backup, and tell a pinned image install to set WARMBLY_TAG before pulling by hand
|
2026-09-04 06:35:04 -07:00 |
|
Matthew Meszaros
|
af9e852314
|
Merge branch 'main' into fix/step-attachments-mount
|
2026-09-04 06:34:53 -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
|
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
|
81d6ba4520
|
Merge remote-tracking branch 'origin/main' into feature/plan-upgrade-paywall-modal
|
2026-09-04 06:09:14 -07:00 |
|
Matthew Meszaros
|
7314e85dfe
|
Merge branch 'main' into fix/create-schedule-windows
|
2026-09-04 06:08:05 -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 |
|
Matthew Meszaros
|
87ada2c99f
|
feat: drop the purple gradient and indigo plan accents for the app's own slate and sky palette (Business wears sky, Enterprise solid ink, no gradients anywhere), highlight the best-value plan instead of whatever sits one rung up, remove the duplicated capability matrix from Overview and the comparison table from Plans, and stop calling dedicated workers 'dedicated IPs' across the dashboard, docs, pricing page, FAQ and agencies page
|
2026-09-04 05:11:47 -07:00 |
|
Matthew Meszaros
|
01dd6e3450
|
feat: rebuild Billing > Plans on the same large plan cards the upgrade dialog uses (extracted to a shared component with rolling prices, interval sheen and a highlighted next-step-up plan), add a side-by-side comparison table of every limit and capability sourced from the server plan records with the current plan column highlighted, and show the proration preview per card
|
2026-09-04 05:03:28 -07:00 |
|
Matthew Meszaros
|
19f8dfbc20
|
feat: rebuild Billing > Overview as a real control panel with cancel and resume, live usage meters against server-enforced limits, a capability matrix, trial and past-due and pending-cancellation banners; price plan switches with a proration preview on the Plans tab; fix the cancel client that sent no body and always 400'd; stop the Payment tab claiming no card is on file
|
2026-09-04 04:48:59 -07:00 |
|
Matthew Meszaros
|
7fe7b7c8e9
|
feat: scope the collaboration guide's offline claim to the data that is actually refetched, since live events are never replayed and presence and cursors resume from current state rather than backfilling what was missed
|
2026-09-04 04:07:44 -07:00 |
|
Matthew Meszaros
|
1533b83c16
|
feat: open a full-screen upgrade dialog from every plan lock (sidebar rows, the unified inbox frosted overlay, the free-workspace screen) with the four plan cards, a monthly/annual toggle with animated prices, the unlocking plan highlighted, promo codes and one-click Stripe checkout or in-place plan change through a shared useUpgradeFlow hook that the billing page now uses too, return the Stripe redirect to the originating page and settle it in place, and add a plans and billing guide
|
2026-09-04 04:03:44 -07:00 |
|
Matthew Meszaros
|
ebc6de1f81
|
feat: refetch the campaigns list on a slow cycle while the realtime socket is not connected, so send counts kept current by live invalidation cannot sit on their five-minute cache with no event coming to refresh them, and document what the header's connection dot means and what still refreshes while it is down
|
2026-09-04 04:03:01 -07:00 |
|
Skylinerffm97
|
16d4a13810
|
feat: mount StepAttachments under the step composer in SequenceView for email steps so per-step attachments can be seen, uploaded and removed from the dashboard, and describe per-step attachments in the sequences guide (issue #307 item 3)
|
2026-09-04 12:59:19 +02: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
|
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
|
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
|
aa55b31422
|
feat: give the campaign step preview a contact and mailbox picker so it renders for a real lead with that sender's signature, the opt-out footer and the attachment list, add a Send test action that mails the saved step through the chosen mailbox, and document both in the sequences guide
|
2026-09-04 02:58:36 -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
|
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
|
8aaf9e8c8c
|
feat: say in the contacts API reference and the OpenAPI 400 description that a before value on the contact timeline that is not an RFC 3339 timestamp is rejected with a 400 rather than accepted
|
2026-09-03 20:28:51 -07:00 |
|
Matthew Meszaros
|
2f32b1b8c3
|
feat: bring the ContactTimelineEvent OpenAPI schema up to the real event shape with the lifecycle, form_submitted and page_hit types and the machine, link, origin, category, form and page_hit fields backed by new ContactLinkClick, EngagementOrigin and WebsitePageHit schemas, and list form_submitted and page_hit with their payloads in the contacts API reference
|
2026-09-03 20:21:42 -07:00 |
|
Matthew Meszaros
|
eeed44f2ed
|
feat: document the contact timeline's cursor parameter and pagination envelope in the contacts API reference, mark before as deprecated with why a bare timestamp can skip events at a page boundary, and say that a bad cursor or limit is a 400
|
2026-09-03 20:19:16 -07:00 |
|
Matthew Meszaros
|
c298d898a7
|
feat: document in the campaigns guide what counts against a mailbox's daily budget and that a capped campaign waits for the next day rather than pausing
|
2026-09-03 20:18:43 -07:00 |
|
Matthew Meszaros
|
dc04ea1b52
|
feat: match a logged open to the step's first open inside a one-minute window on both sides so an unrelated older row cannot hide the summary event, and say in the contacts API reference that only a person's click counts as an open in the contact engagement totals
|
2026-09-03 05:57:31 -07:00 |
|
Matthew Meszaros
|
611704b365
|
feat: count only a person's opens in the contact engagement totals and last-opened time as analytics already does, keep a step's legacy first open on the timeline when only later opens were logged per event, and say so in the contacts API reference
|
2026-09-03 05:43:31 -07:00 |
|
Matthew Meszaros
|
701dc404a2
|
Merge remote-tracking branch 'origin/main' into fix/click-without-open-tracking
|
2026-09-03 05:22:05 -07:00 |
|
Matthew Meszaros
|
3d5eb36ae5
|
feat: second review pass on self-hosted updates: git describe suffixes after a prerelease (rc.1-2-gabc1234) now parse as prerelease plus commit distance, Apply validates the updater for every target including explicit tags, a DNS failure only reads as the compose profile being off when UPDATER_URL names the updater service and stays unreachable for custom hosts, the admin dialog re-checks that the update can still start before launching it and drops the confirmation when it cannot, the bare-metal installer refuses symlinks anywhere inside a build directory, restores config.js with --remove-destination and bounds every health probe, and the bare-metal docs add the single sudoers rule before the upgrade command
|
2026-09-03 05:04:30 -07:00 |
|
Matthew Meszaros
|
bb35de0455
|
feat: address review on self-hosted updates: the updater no longer re-locks its mutex when a job finishes (every job used to deadlock at completion and freeze the status API), the backend caches the updater view so the member version pill, the health checks and the admin poll share one read and an absent updater is reported as not running rather than broken, the bare-metal upgrade builds unprivileged and hands off to a root-owned fixed-path installer that refuses symlinks so sudoers allows one command instead of install/cp/rm/chown/chmod/systemctl/ln, the installer fails when the backend does not come back, the seed image gets the version build args, the dashboard gates the update action on manage_settings and stops polling a backend that answers 404, and revived timestamps are typed as Date
|
2026-09-03 05:04:30 -07:00 |
|
Matthew Meszaros
|
b2ea1f1961
|
feat: add self-hosted update awareness and one-click updates: every binary is stamped with its version and commit, the backend polls GitHub Releases and a new host-side updater (cmd/updater, compose profile or systemd unit) reports the checkout's commit distance, the admin panel's top bar shows a version pill that turns into an update indicator and opens a dialog with confirmation, live step progress and log, restart tracking and result, the dashboard header shows the same pill to every member of a self-hosted instance with the full update flow for platform admins, Setup and health gains update_available and updater_unreachable checks, warmblyctl status prints the version, make upgrade and scripts/upgrade-bare-metal.sh cover the by-hand paths, and docs gain an Updates page plus configuration, health, deployment and API reference updates
|
2026-09-03 05:04:30 -07:00 |
|
Matthew Meszaros
|
a3264f0d39
|
feat: address the review on the rebuilt engagement branch: a deferred human click's effects are now durable and once-only (announce_pending on the click row written before the event is marked processed, a claim in finishHumanClick and a minute-by-minute sweep that finishes what a restart cut off, a burst relabel clears the flag), the tracking service keys the source-address token with TRACKING_IP_HASH_KEY so it cannot be enumerated back into an IPv4 address, the migration no longer adds a blocking index to the existing click table, and timeline click and open rows carry task_id
|
2026-09-03 04:13:39 -07:00 |
|
Matthew Meszaros
|
6830e3277d
|
feat: keep the tracking-domain exclusion when link tracking falls back to UTM-only tagging, leave links the URL parser rejects untouched instead of minting a dead click ticket, and say in the campaigns guide that the sequence versus one-time choice is fixed at creation
|
2026-09-03 03:53:39 -07:00 |
|
Matthew Meszaros
|
31dabea0a4
|
feat: rebuild the click-without-open fix on top of the per-link click attribution from #298: a person's click now also counts as an open and a burst that withdraws the click withdraws the open it implied unless a real open is on record, routing readers ignore machine opens as the docs promised, every open gets its own log row and every open and click records the mail client or proxy, browser, device, OS, country, region and city (migration 000124: origin columns on email_link_clicks plus an email_opens table), the tracking service publishes only the address's network in a nullable client_ip field which the consumer resolves with GeoLite and drops, the contact Activity tab shows each open and the origin of opens and clicks, the campaign overview gains a who-engaged-from-where breakdown exposed as engagement in campaign analytics, live open and click events carry occurred_at, client and location, the leads table explains why an open is not always counted, both logs are pruned daily after a year, email_opens joins the export registry, the consumer reads GEODB_PATH optionally, and the guides and API references are updated (fixes #294)
|
2026-09-03 03:49:44 -07:00 |
|
Matthew Meszaros
|
579b0ac04c
|
feat: merge main into the unsubscribe branch again, carrying the UTM campaign columns alongside unsubscribe_mode in every campaign scanner, keeping unsubscribe links out of the moved link tracker and its UTM tagging, and renumbering the opt-out migration to 000124 because main released 000123 for link clicks
|
2026-09-03 03:43:47 -07:00 |
|