Commit Graph

33 Commits

Author SHA1 Message Date
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 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 7901e9a92c feat: wire the Pub/Sub realtime provisioning, the instant-branch automation runner, and the campaign-chain reconciler into the backend and consumer binaries 2026-06-13 06:27:06 +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 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 160dc0bc76 feat: implement the coming-soon notification delivery channels — Email (SES/SMTP to the account email) and Slack (posts to the org's connected workspace via a new integration NotifySlack), wired in both backend and consumer with per-channel gating, real toggles replacing the coming-soon labels, and updated docs 2026-06-11 12:21:48 +02:00
Matthew Meszaros abdfd05c34 feat: org-scope realtime events (inbox, campaign, tracking, account health) and emit EMAIL_SENT/EMAIL_REPLIED/EMAIL_DELETED pulses so the whole team's dashboard updates live 2026-06-11 07:43:57 +02:00
Matthew Meszaros 4013b33008 feat: expose security notification APIs
Wires notification and two-factor services into the backend and consumer, adds the authenticated notification feed/preferences endpoints, and exposes the public 2FA login verification endpoint.
2026-06-08 15:04:47 +02:00
Matthew Meszaros 51c99458ad feat: fire instant actions from tracking events 2026-06-07 17:24:32 +02:00
Matthew Meszaros da82993846 feat: add campaign workflow backend support
Add sequence action-node storage and execution, template conditional rendering, lead progress state, profile updates, webhook fan-out throttling, and supporting repository fixes.
2026-06-06 07:49:52 +02:00
Matthew Meszaros 35fbf73347 feat: persist warmup engagement dwell
Store delayed warmup engagement actions in Postgres and drain them from the consumer so read, important, and star actions survive worker restarts.

Keep foldering and spam rescue immediate while routing delayed actions to the mailbox's current worker at fire time.
2026-06-03 11:14:02 +02:00
Matthew Meszaros 59d253ef1d feat: harden warmup action handling
Wire warmup health webhooks in the consumer and log skipped warmup actions when a recipient mailbox has no assigned worker.

Run foldering and spam rescue immediately while keeping only low-stakes engagement signals behind the dwell delay.
2026-06-03 06:40:35 +02:00
Matthew Meszaros 15ef9d4994 feat: add warmup content controls
Add warmup content generation and admin review surfaces, plus mailbox warmup appeal/status APIs.

Track warmup engagement and tampering signals so unsafe mailboxes can be handled by the warmup flow.
2026-06-03 05:05:53 +02:00
Matthew Meszaros 2430095197 feat: move infrastructure state off dynamodb
Remove DynamoDB-backed storage paths, add Postgres/HTTP repositories for mailbox state maps, wire the internal message-map API, and add provisioning runner/migration plumbing.
2026-06-02 15:54:12 +02:00
Matthew Meszaros 83eae84d49 feat: merge main into warmup branch
Resolve the main-branch conflict in realtime event publishing by keeping both warmup account-health and audit-created events. Renumber the warmup migrations after the current main migration tail.
2026-06-01 11:36:04 +02:00
Matthew Meszaros a04d7450bc feat: guard warmup reconciliation by access
Make the warmup task reconciler re-check account state and org warmup access before scheduling replacement tasks. Remove pool membership for accounts whose org can no longer use warmup to avoid repeated no-access task churn.
2026-06-01 11:19:44 +02:00
Matthew Meszaros 4500aeba0f feat: add integration oauth connections
Adds OAuth-backed integration connection management across the API, repository, event dispatch, migrations, docs, and dashboard UI.

Includes realtime invalidation and small dashboard type compatibility fixes needed for the web typecheck gate.
2026-06-01 04:25:14 +02:00
Matthew Meszaros d2414ad29f ci(go): gofmt all flagged files
Go CI fails on golangci-lint's gofmt check. Ran gofmt -w against
every file the linter named plus a handful of others that drifted
during the autonomous-fleet work. No semantic changes — alignment
of struct field whitespace and one mis-indented import block.

gofmt -l ./... is now empty; go build + go vet are clean.
2026-05-27 16:40:23 +00:00
Matthew Meszaros 51506d98f4 cmd: wire pluggable infra (KMS, encryptedkeys, eventbus, codec, settings)
cmd/backend/main.go:
  - kms.FromEnv replaces kms.New (defaults to AWS, accepts local)
  - encryptedkeys.FromEnv with Deps{DB, Dynamo}; default postgres
  - codec.NewAvroFromClient wraps the existing Schema Registry client
  - eventbus.FromEnv with kafka default; KafkaBus.Producer().WithAvrov2
    preserves the existing Avro wire format on Kafka
  - events.NewPublisher takes (bus, codec) instead of (producer, avrov2)
  - settings.Registrar reflects KMS / EncryptedKeys / Blob / EventBus
    choices into storage_backends on boot
  - Handler gains EncryptedKeys + StorageBackendRepo for the new admin
    and internal endpoints

cmd/consumer/main.go: same eventbus + codec + encryptedkeys swap; the
legacy kafkaProducer is kept around for the consumer's tracking pipeline
which still uses *kafka.Consumer directly (follow-up refactor).
2026-05-27 14:43:51 +00:00
Matthew Meszaros 7e02bb2a5a feat(consumer): hourly risk rebalancer migrates mailboxes between risk pools
New background job in the consumer process:

  1. Pulls up to 1000 mailbox candidates joined with their worst warmup
     health state (across all pools they participate in) and their
     current worker's risk_pool. Dedicated workers are excluded — single
     tenant, segregation not applicable.
  2. Recomputes risk_band from health state via RiskBandFromHealth.
     If it changed, writes the new band.
  3. If the band's matching pool doesn't equal the worker's pool, picks
     a new worker via SelectSharedWorkerForBand and migrates the mailbox.
     Increments/decrements account counts.
  4. Logs each migration to admin_audit_log with action=
     "risk_rebalance_migrate" so operators see what moved and why.

Boot-time run + hourly ticker. Rebalancing is intentionally batch, not
event-driven: warmup health states change on a slow rolling-window basis
(warmup_health_sweep is also hourly), so reacting in real time gains
nothing and would cause thundering-herd migrations.

JobsService gets an AssignmentService dep. Nil disables the job (lets
self-hosters opt out by simply not wiring it).
2026-05-19 05:39:27 +00:00
Matthew Meszaros 2aefb7da02 feat(consumer): log auto-reassignment events to admin_audit_log
When the dead-worker job reassigns email accounts from a worker whose
heartbeat expired, write a row into admin_audit_log so the dashboard's
audit viewer surfaces these system actions alongside admin-driven ones.

admin_user_id is uuid.Nil (the platform identity), so admins searching
the log can distinguish "system did this" from "an admin did this" by
filtering on that ID. Details include the replacement worker, account
count, and reason.

JobsService gets an optional AdminRepo dep. Nil disables logging — keeps
the contract loose for any other call site that doesn't have one.
2026-05-19 05:21:26 +00:00
Matthew Meszaros 8ae7759964 feat(consumer): sync worker heartbeats from Redis to workers.last_seen_at
Workers heartbeat into Redis every 90s as RFC3339 timestamp values with a
3-min TTL. The dashboard surfaces liveness based on workers.last_seen_at,
but until now nothing populated that column — the "Live" badge was always
red.

New 60s job in the consumer reads each active worker's Redis heartbeat
value, parses the timestamp, and writes it to workers.last_seen_at. Runs
on its own interval (separate from the 5-min dead-worker detection job,
which does heavier reassignment work) so the UI sees fresh data within a
minute.
2026-05-18 14:55:34 +00:00
Matthew Meszaros 1ad8e7e995 feat: implement dead worker detection with heartbeat TTL and auto-reassignment 2026-04-12 11:14:24 +00:00
Matthew Meszaros 23b5c925e4 feat: add scheduled warmup health sweep, pool health summary endpoint, and admin overview 2026-04-09 15:57:04 +00:00
Matthew Meszaros 0799020dac feat: add metrics, warmup content variety, tz-aware scheduling, org budget, admin stubs, and bug fixes 2026-04-09 14:33:45 +00:00
Matthew Meszaros 19d20e72b4 feat: add warmup health throttled state, complaint/bounce metrics, A/B analysis, and rate limiting 2026-04-09 12:51:30 +00:00
Matthew Meszaros d8d88c7f69 feat: add warmup health tracking, migrate repos to postgres, and overhaul web UI 2026-04-03 06:08:52 +00:00
Matthew Meszaros 21ffb6a748 feat: add advanced outreach controls with A/B testing, deliverability dashboard, and DLQ 2026-02-20 08:59:17 +00:00
Matthew Meszaros c12fd93def Add local Sentry logging 2026-02-14 05:49:49 +01:00
Matthew Meszaros 141bc54974 Add sample auth UI theme 2026-02-10 19:30:47 +01:00
Máté Mészáros (Laptop) 7ed5719c15 Config & Deploy 2026-01-29 08:50:38 +01:00
Máté Mészáros (Laptop) 41624a6f79 Analytics & Tracking 2026-01-29 05:59:04 +01:00
Matthew Meszaros 772c19820d New Repository: Add Backend Code 2026-01-17 14:11:14 +00:00