Matthew Meszaros
7f425c1624
feat: dashboard-wide AI assistant with streamed tool-use runs, per-action approvals, and per-iteration credits - agent_sessions/agent_messages/ai_tool_policies migration, aiagent service runs the M2 registry through the provider loop over a resumable jsonb transcript, streams text/tool-step/approval/done events over SSE, gates write tools behind approve/deny/always-allow (send always per-action) and charges 1 credit per iteration (budget 20, refund on provider failure, out-of-credits 402 insufficient_credits, cap 429 usage_cap_exceeded) with a resume-safe idempotency namespace, provider PreIteration budget hook, /ai/sessions endpoints (cursor list + two SSE runs) gated by membership with tools bound to the member's org-permission bits, APIPermAIAgent bit 22, ai_session audit entity + spine, and a right-side resizable panel (Cmd+I / sparkle button) with streamed text, collapsible tool steps, inline approval and draft-artifact deep-link cards, stop, new chat, and a credits/budget meter; tenancy enforced at the SQL layer and docs for the assistant, endpoints, permissions, and error codes
2026-07-13 18:46:43 +02:00
Matthew Meszaros
6ad2f13a39
feat: shared AI tool registry (internal/app/aitools) that runs 16 permission-gated tools as the invoking user over existing service-layer calls - Registry+Invocation enforce org-permission bits (JWT) or API-key bits per tool, ToolDefs binds handlers into the provider agent loop and Call powers direct MCP invocation; tools cover contacts (search/get/update/add_tag/remove_tag), CRM (create_task/create_deal), campaigns (list/stats/create_campaign_draft), unibox (list_threads/get_thread/draft_reply, gated on CanUseUnibox, draft never sends), create_automation_draft (disabled), and web search_web + fetch_url (webhook SSRF validator + safehttp dial-block + 2MB cap + html-to-text + 15min Redis cache + rune-safe truncation); every write audits via AuditService.LogAction so the spine refreshes teammates, registry built once in main and exposed on the handler for M3/M8
2026-07-13 18:15:58 +02:00
Matthew Meszaros
e07c33d3cd
feat: provider-agnostic LLM agent-loop layer (OpenAI-first, Anthropic self-host connector) with RunAgent tool-use loop, approval/resume contract, pluggable web search, and extracted voice-rules builder - generation.Provider.RunAgent executes Go tool handlers over a resumable transcript with a read-auto/write-approve gate, openAIProvider drives it via a lean HTTP client retargetable with OPENAI_BASE_URL for any OpenAI-compatible endpoint and also serves the writing assistant, anthropicProvider mirrors it with tool_use/tool_result multi-turn plus hosted web_search, NewProvider prefers OPENAI_API_KEY, SearchClient supports Serper/SearXNG with a clean not-configured error, and BuildVoiceRules extracts the humanizer prompt for reuse; refreshed stale model ids to sonnet-4-6 and haiku-4-5
2026-07-13 17:52:09 +02:00
Matthew Meszaros
5d6ed2a068
feat: AI credit economy with monthly plan grants, non-expiring purchased top-ups, and Stripe billing - two-pool credit_ledger (monthly allowance reset each cycle on invoice.paid, purchased pool via checkout mode=payment fulfilled webhook-only), consume drains monthly-then-purchased, 3 fixed top-up packs, /subscription/credits balance+checkout+paginated transactions gated on manage_billing, one-time trial grant, billing credits card with balance ring and pack buttons, credit_purchase/credit_grant audit entities and spine, wired plan.monthly_credits through pg_plan reads/writes, retry-safe webhook idempotency, and an AI credits guide
2026-07-13 17:40:20 +02:00
Matthew Meszaros
b9a99f91a9
Merge pull request #67 from warmbly/feature/ios-realtime-steps-preview
...
iOS realtime parity, richer sequence preview, and mobile push notifications
2026-07-13 16:15:18 +02:00
Matthew Meszaros
d6b7885e8b
feat: mobile push notifications end to end - APNs provider-token client, device_tokens table with session-scoped register/delete endpoints, a push channel in notification preferences (web + iOS toggles), and Redis-backed immediate-then-digest batching (first event pushes now, bursts summarize when the 5h window closes) wired in backend and consumer, with iOS registration/badge sync and docs for the channel, endpoints, and APNS_* deploy env
2026-07-13 16:11:15 +02:00
Matthew Meszaros
262d25779c
feat: realtime admin dashboard + diagnosability - new Elixir admin:platform channel (JWT-only, gated on users.admin_permissions) mirrors every platform event, the admin app connects through a /getaway-tokenized Phoenix socket client with a throttled react-query invalidation spine, a Live Events firehose page streams the platform with filters/pause/JSON expand, a System Status page runs parallel infra probes (postgres/redis/kafka/schema-registry/realtime/tracking via /admin/system/status), and the worker logs viewer gains follow mode, line-count selection, and copy
2026-07-12 09:00:10 +02:00
Matthew Meszaros
a26d144b49
feat: continuous warmup-content refresh + full admin control surface - the scheduler now recycles the most-used AI threads each run (refresh_enabled/refresh_per_run) so fresh warmup messages keep generating after the target is reached, the warmup-content overview exposes the whole automation pipeline (AI configured/enabled/scheduled/stocked, per-segment stock vs target, daily budget), state legends explain risk-pool/health/job-status enums, and new settings pages cover worker profiles, releases, provisioning policy, and AWS credentials
2026-07-12 08:59:59 +02:00
Matthew Meszaros
9d7e3aa61f
feat: make scheduled sending self-healing - dispatch Cloud Tasks callbacks by the task row type (all enqueues share one webhook URL, so campaign callbacks were run through the warmup handler), cancel pending tasks stranded past their slot so the reconcilers re-seed chains after a lost callback or emulator restart, and cast the status enum in the two UPDATE ... CASE queries that failed parameter type deduction on every callback
2026-07-11 17:31:23 +02:00
Matthew Meszaros
167cc370b3
feat: re-key dedicated_worker_assignments to organizations (migration 000055) - the assignment service has always keyed by org id but the column carried a users FK, so every runtime bind failed with an FK violation and dedicated-plan orgs could never get a worker; renames the column, remaps seed rows, and updates the repository, admin filter, and convert-to-dedicated endpoint to org semantics
2026-07-11 17:31:23 +02:00
Matthew Meszaros
07a6777536
feat: email OAuth callback page gains a native-app fallback - when there is no web opener to postMessage (an ASWebAuthenticationSession has no popup parent) it redirects to warmbly://email-oauth with provider/code/state/error so the iOS app can finish the connect; web popup behavior is unchanged and the docs describe both delivery paths
2026-07-11 10:13:10 +02:00
Matthew Meszaros
cc0871d1b8
feat: contacts search gains an additive lead_status filter plus per-status lead_counts on the first page when exactly one campaign_id is set - the SQL predicates reproduce the read-time status derivation exactly (unsubscribed > bounced > replied > active > pending via LATERAL bool_or rollups), invalid lead_status or multi-campaign combinations return 400, and the web types/table pick up the new lead_counts shape
2026-07-11 10:11:36 +02:00
Matthew Meszaros
3acb51df6c
feat: add server-side status-bucket filtering to GET /campaigns (draft/active/paused/completed, paused matches every paused_* variant, invalid values 400) and a new GET /campaigns-overview endpoint returning status and per-folder counts, with the campaigns API reference and endpoint scope map updated
2026-07-07 09:40:27 +02:00
Matthew Meszaros
13f193d91e
feat: unibox list filters - from now matches sender addresses by case-insensitive substring as documented, and a new uncategorized=true param returns only threads with no labels, documented in the unibox API reference
2026-07-07 05:56:47 +02:00
Matthew Meszaros
a20ba926cb
feat: add native Apple/Google sign-in to the backend - POST /auth/apple and /auth/google exchange provider-signed ID tokens for sessions, GET /auth/providers exposes configured providers for app discovery, with a JWKS-verifying idtoken package, auth config, stable error codes, and API/security docs
2026-07-07 05:56:35 +02:00
Matthew Meszaros
d4ead05456
feat: persist campaign sequence canvas coordinates with x/y columns (migration 000053) plus a bulk sequence-layout service/repo path that scopes by campaign owner and never bumps updated_at
2026-06-30 10:06:20 +02:00
Matthew Meszaros
73838cecf5
feat: add an unaudited automation node-layout endpoint handler/service/repo backed by an atomic jsonb x/y merge that leaves edges, config, and updated_at untouched
2026-06-30 10:06:19 +02:00
Matthew Meszaros
5e94b945ff
feat: add GetIdentity handler returning user, org, auth type, and granted scopes for GET /v1/me
2026-06-28 19:09:37 +02:00
Matthew Meszaros
9dd37b0d62
Merge pull request #52 from warmbly/referral-credits
...
feat: implement referral program with credit-based rewards
2026-06-28 09:12:57 +02:00
Matthew Meszaros
7e75394ab8
feat: decode the admin discount list and redemption cursors as opaque offset tokens, returning 400 on a malformed cursor instead of silently resetting to the first page
2026-06-28 05:58:25 +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
8bd3a1137e
feat: expose the JWT referral and applied-discounts endpoints with handlers and manage_billing-gated routes
2026-06-28 05:09:50 +00: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
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
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
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
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
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
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
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
3c040649c0
fix: changing your password now revokes every other session (keeping the current device), matching the security promise in the sign-in alert and docs
2026-06-11 12:39:24 +02:00
Matthew Meszaros
5bcc2baaa8
feat: implement the coming-soon security features — logged-in change-password (verify current, policy-checked, POST /me/password) with a real dialog, and new-device sign-in alerts (security notification category fired from the token service on an unrecognized OS+browser, delivered in-app and by email), removing the comingSoon stub helper and updating docs
2026-06-11 12:30:44 +02:00
Matthew Meszaros
39a9752d63
feat: real tokenized invite-accept link — public /invite landing page with safe preview (org, inviter, roles), accept-by-token plus the previously-broken accept-by-invitation-id, public preview + admin copy-link endpoints, login next-param redirect, and a Copy button that yields a working /invite?token link
2026-06-11 11:57:45 +02:00
Matthew Meszaros
19f66507b4
feat: fix multi-role review findings — atomic member+roles insert on invite accept (no partial-failure stranding), gate role deletion on the actor holding the role's permissions (blocks team-managers de-privileging admins), and hydrate+chip pending-invitation role sets
2026-06-11 11:32:57 +02:00
Matthew Meszaros
3473d09bcc
feat: fix review findings in the roles redesign — GetMembers role_id column (members endpoint 500), TransferOwnership role_id hygiene, accept-time role re-resolution, race-free in-use delete guard covering invitations, assignment anti-escalation with self-role-change block, canManage-gated members UI, colored RolePills, fresh currentOrganization on refetch, dev JWT_SECRET wiring for make realtime, docs corrections
2026-06-11 10:45:21 +02:00
Matthew Meszaros
edd4524007
feat: custom organization roles backend (organization_roles table with write-through member propagation, CRUD endpoints with anti-escalation and in-use guards, custom-role invites and assignment via role_id, audited as role entity)
2026-06-11 09:39:52 +02:00
Matthew Meszaros
8732805934
feat: replace signed click redirects with server-side link tickets (tracked_links store, internal resolver API, opaque /c/<id> URLs, layered anti-probe caches with miss budget and circuit breaker) removing TRACKING_LINK_SECRET entirely
2026-06-11 09:30:21 +02:00
Matthew Meszaros
fe96eff7b4
feat: audit-log coverage for teams, automations (typed entity), lead-sync sources, and manual meetings so the org activity trail and its realtime spine see every mutation
2026-06-11 07:47:29 +02:00
Matthew Meszaros
a6acb97dea
feat: key the worker-facing internal DEK endpoint by organization
...
The /api/v1/internal/dek route parameter is now :orgID to match the
org-scoped encryptedkeys store. Workers fetch the organization DEK for
the account they are operating on instead of a user DEK.
2026-06-10 17:16:07 +02:00
Matthew Meszaros
5954ac53c2
feat: add automation execution safeguards
...
Support chained automation execution from native actions, guard automation recursion depth, carry idempotency context through campaign-launched automations, allow team task assignment in backend action execution, and reject deletes while campaign steps still reference an automation.
2026-06-09 10:56:56 +02:00