2026-08-28 12:20:11 -07:00
..
2026-06-02 15:54:29 +02:00
2026-05-28 08:47:57 +02:00
2026-08-27 03:21:25 -07:00
2026-08-28 10:29:39 -07:00
2026-07-30 17:15:09 +02:00
2026-07-19 13:22:56 +02:00
2026-08-28 11:48:44 -07:00
2026-05-25 10:23:32 +00:00
feat: AI contact research agent that gathers cited web findings per contact with sync and background-batch runs - contact_research_runs table plus a strict save_research schema (every signal and public_artifact must carry a url, confidence high/medium/low, signals<=5 hooks<=3, reject-and-reprompt once then fail), a text/template runtime prompt injecting org voice, contact record, objective, and 5-search/6-fetch budgets, a research service that drives search_web/fetch_url through the provider loop and charges 2 credits on save (billable even for nothing_found, refund-free since charged only on save, balance and abuse-cap pre-checked so a capped org never does free work), POST/GET /contacts/:id/research plus a 500-cap /contacts/research/batch draining through a bounded pool of 4 workers over FOR-UPDATE-SKIP-LOCKED claims (no new Kafka), an org-scoped AI_RESEARCH_PROGRESS realtime event gated to view_contacts, APIPermAIResearch bit 23, a ContactEdit Research tab and a ContactsTable bulk Research action, and docs; also org-scopes every credit and research idempotency key so a client-supplied Idempotency-Key can never replay across tenants
2026-07-13 19:34:11 +02:00
feat: add Delete and Duplicate campaign actions to the dashboard (issue #185): every campaign row and the detail header get a ⋯ menu (Edit, Duplicate, Start/Pause, Delete) plus a Delete card at the bottom of Settings, all permission-gated with a confirm that spells out what goes; DELETE /campaigns/:id is now organization-scoped instead of user_id-scoped so teammates can delete, runs in one transaction that also deletes the campaign's pending tasks and cancels a wakeup tick claimed at that moment (campaign_tasks only nulls its link, so those rows kept firing), removes attachment objects and publishes CAMPAIGN_DELETED so a teammate's open detail page is sent back to the list; new POST /campaigns/:id/duplicate copies the campaign row as a draft with steps and their branch graph rewired onto new step ids, tags, folders, senders with rotation reset, A/B variants, advanced settings and attachments (quota-checked, blobs undone if the copy fails) and none of the leads, progress, logs, counters, ramp level, guardrail trip or past dates, naming it (copy)/(copy N) inside the 50 byte cap without splitting runes; a claimed campaign tick whose campaign vanished now ends the chain instead of staying active forever; covered by TestLiveCampaignLifecycle* against real SQL, RemapBranchTargets and duplicateName unit tests and a react-query vitest for the list cache, with API reference, endpoint map and campaigns guide updated
2026-08-25 08:54:51 -07:00
2026-08-28 11:20:19 -07:00
2026-08-28 01:44:39 -07:00
2026-07-22 10:58:35 +02:00
feat: give each mailbox a human sending persona (randomized daily and hourly caps, send spacing, work start/end, lunch break and working weekdays, rolled once per local day in the mailbox's own timezone and applied across the campaign, warmup and smart-send schedulers), add campaign auto-pause guardrails that stop a campaign when its bounce, complaint or reply rate leaves the configured band, make mailbox rotation actually rotate for tag-resolved and all-mailbox campaigns, stop every scheduler from ever returning a slot in the past, and correct the mailbox min-gap field that stored seconds while labelling them minutes
2026-08-13 16:51:29 +02:00
2026-01-29 05:59:04 +01:00
feat: unbox campaign start dates and make follow-up pacing real: accept today as "start now" and let an explicit null clear start/end dates on PATCH /campaigns (models.NullableTime distinguishes absent from null, which used to silently no-op while the error message told users to send null), reschedule an active campaign's parked wakeup when any schedule field changes so clearing a future start date takes effect immediately instead of at the old slot, let a completed campaign be started again and turn the past-end-date start 500 into a clear 400, gate the campaign task on the step's hard-constraint floor (wait_after, start date, windows, day capacity, mailbox min-gap) via ErrCampaignDeferred so an early successor tick can no longer send a wait-3-days follow-up seconds after step one (live-tested in TestLiveFollowUpWaitIsHonored), disable past days in the schedule date picker, and fix the sandbox seed leaving worker 1a01 free-tier after make seed which unassigned the paid org's mailboxes and failed every send
2026-08-24 05:20:26 -07:00
2026-08-28 10:40:25 -07:00
2026-08-28 10:40:25 -07:00
2026-05-24 16:04:48 +00:00
2026-08-28 11:50:48 -07:00
2026-08-27 03:43:54 -07:00
2026-05-18 13:09:11 +00:00
2026-07-19 13:22:56 +02:00
2026-06-13 10:47:17 +02:00
2026-05-24 04:42:43 +00:00
2026-06-28 05:58:25 +00:00
2026-08-22 09:37:26 -07:00
2026-08-24 09:02:29 -07:00
2026-01-17 14:11:14 +00:00
2026-07-04 11:36:47 +02:00
2026-08-28 11:02:45 -07:00
2026-01-17 14:11:14 +00:00
2026-01-17 14:11:14 +00:00
2026-07-04 08:07:49 +02:00
2026-05-27 15:56:01 +00:00
2026-01-17 14:11:14 +00:00
2026-06-10 17:16:56 +02:00
2026-08-28 11:02:45 -07:00
2026-01-17 14:11:14 +00:00
feat: make self-hosted auth work without a mail relay by rewriting the platform SMTP transport with real AUTH and TLS (it did neither, so SMTP_USERNAME/SMTP_PASSWORD were dead and every documented relay was unreachable), adding MAIL_TRANSPORT=smtp|log|ses with a log transport that prints codes so a fresh install can sign in with no relay, demoting the emailed login code to AUTH_LOGIN_CODE=always|new_device|off (off on self-host, per NIST SP 800-63B and OWASP ASVS), claiming the first owner through a single-use setup link or WARMBLY_BOOTSTRAP_* instead of register-then-psql, deriving every emailed URL from APP_URL rather than a hardcoded app.warmbly.com that leaked live reset tokens to the vendor, fixing the confirm hooks that read path params against paramless routes and broke login, register and reset confirmation in the dashboard everywhere, adding generic OIDC with PKCE, one-time state, verified nonce and (issuer,subject) identity binding, enforcing 2FA on the social paths that skipped it, adding a per-IP limiter and trusted-proxy handling to the unthrottled auth group, refusing boot on the published default secrets, and dropping mailpit from the default stack (#99)
2026-08-14 14:57:09 +02:00
2026-06-28 19:09:37 +02:00
2026-08-21 18:45:09 +02:00
2026-06-08 06:25:40 +02:00
2026-06-08 06:25:40 +02:00
2026-07-22 10:58:35 +02:00
2026-06-04 11:49:55 +02:00
2026-01-17 14:11:14 +00:00
2026-01-17 14:11:14 +00:00
2026-07-13 20:05:24 +02:00
2026-08-22 09:37:26 -07:00
feat: unbox campaign start dates and make follow-up pacing real: accept today as "start now" and let an explicit null clear start/end dates on PATCH /campaigns (models.NullableTime distinguishes absent from null, which used to silently no-op while the error message told users to send null), reschedule an active campaign's parked wakeup when any schedule field changes so clearing a future start date takes effect immediately instead of at the old slot, let a completed campaign be started again and turn the past-end-date start 500 into a clear 400, gate the campaign task on the step's hard-constraint floor (wait_after, start date, windows, day capacity, mailbox min-gap) via ErrCampaignDeferred so an early successor tick can no longer send a wait-3-days follow-up seconds after step one (live-tested in TestLiveFollowUpWaitIsHonored), disable past days in the schedule date picker, and fix the sandbox seed leaving worker 1a01 free-tier after make seed which unassigned the paid org's mailboxes and failed every send
2026-08-24 05:20:26 -07:00
feat: unbox campaign start dates and make follow-up pacing real: accept today as "start now" and let an explicit null clear start/end dates on PATCH /campaigns (models.NullableTime distinguishes absent from null, which used to silently no-op while the error message told users to send null), reschedule an active campaign's parked wakeup when any schedule field changes so clearing a future start date takes effect immediately instead of at the old slot, let a completed campaign be started again and turn the past-end-date start 500 into a clear 400, gate the campaign task on the step's hard-constraint floor (wait_after, start date, windows, day capacity, mailbox min-gap) via ErrCampaignDeferred so an early successor tick can no longer send a wait-3-days follow-up seconds after step one (live-tested in TestLiveFollowUpWaitIsHonored), disable past days in the schedule date picker, and fix the sandbox seed leaving worker 1a01 free-tier after make seed which unassigned the paid org's mailboxes and failed every send
2026-08-24 05:20:26 -07:00
2026-07-16 08:57:19 +02:00
2026-01-17 14:11:14 +00:00
2026-08-18 07:53:39 -07:00
2026-07-19 11:04:58 +02:00
2026-07-19 13:22:56 +02:00
2026-08-28 11:20:19 -07:00
2026-06-13 07:18:23 +02:00
2026-05-27 16:40:23 +00:00
2026-05-27 12:06:18 +00:00
2026-06-08 06:25:40 +02:00
2026-06-28 05:09:50 +00:00
feat: AI contact research agent that gathers cited web findings per contact with sync and background-batch runs - contact_research_runs table plus a strict save_research schema (every signal and public_artifact must carry a url, confidence high/medium/low, signals<=5 hooks<=3, reject-and-reprompt once then fail), a text/template runtime prompt injecting org voice, contact record, objective, and 5-search/6-fetch budgets, a research service that drives search_web/fetch_url through the provider loop and charges 2 credits on save (billable even for nothing_found, refund-free since charged only on save, balance and abuse-cap pre-checked so a capped org never does free work), POST/GET /contacts/:id/research plus a 500-cap /contacts/research/batch draining through a bounded pool of 4 workers over FOR-UPDATE-SKIP-LOCKED claims (no new Kafka), an org-scoped AI_RESEARCH_PROGRESS realtime event gated to view_contacts, APIPermAIResearch bit 23, a ContactEdit Research tab and a ContactsTable bulk Research action, and docs; also org-scopes every credit and research idempotency key so a client-supplied Idempotency-Key can never replay across tenants
2026-07-13 19:34:11 +02:00
2026-05-23 16:54:12 +00:00
2026-08-28 11:48:44 -07:00
2026-08-28 11:48:44 -07:00
2026-08-23 10:18:24 -07:00
feat: org AI skills (playbooks) that every AI feature loads and follows - ai_skills table (org-scoped, unique name per org, 32KB content cap) with a skills service exposing CRUD plus an enabled-skills preamble injected into the dashboard agent, contact research, and reply-draft prompts and a load_skill read-tool that returns a playbook's full content by name, /ai/skills CRUD gated on manage_settings (JWT) or the AI_AGENT scope (API) with an ai_skill audit entity and spine entry, an AI skills settings page (list rows opening a right-side drawer with name, one-line description, enable toggle, and a markdown body), and docs with two example playbooks
2026-07-13 19:46:25 +02:00
2026-06-28 05:09:50 +00:00
2026-08-18 09:09:52 -07:00
2026-06-07 07:03:49 +02:00
2026-05-24 12:01:37 +00:00
2026-08-28 12:20:11 -07:00
2026-06-08 15:04:36 +02:00
2026-08-21 18:45:09 +02:00
2026-07-19 18:45:50 +02:00
2026-07-22 12:11:19 +02:00
2026-05-25 15:42:50 +00:00
2026-05-27 16:17:53 +00:00
2026-08-27 01:04:50 -07:00
2026-06-01 03:09:17 +02:00
2026-06-15 08:11:20 +02:00
2026-06-15 08:11:20 +02:00
2026-08-21 18:45:09 +02:00