Matthew Meszaros
|
60c9e316d9
|
feat: hosted lead-capture forms end to end: drag-and-drop builder with field settings, design panel, embed/share and submissions tabs in the dashboard, a public TanStack form app (forms/) served by the new standalone forms service (cmd/forms + internal/formserver) on FORMS_DOMAIN with per-form frame-ancestors CSP, honeypot/fill-time/Turnstile/per-IP submit protection and a same-origin JSON API proxying the backend internal API, form submissions creating contacts with categories and campaign enrollment plus realtime, audit, webhook and org-transfer coverage, migration 000114, seed forms, CI jobs, Dockerfile, systemd/nginx/compose manifests and docs
|
2026-09-01 01:17:51 -07:00 |
|
Matthew Meszaros
|
27630eec0a
|
feat: add website visitor tracking for issue #255 with migration 000106 (website_tracking_settings, website_visitors, website_page_hits, all registered in the orgtransfer spec), a consent-gated dependency-free tracking.js served by the Rust tracking service with a rate-limited, size-capped, prefetch-filtered POST /p ingest that forwards to a new backend internal page-hits endpoint for server-side user-agent and GeoIP enrichment, contact identification only through the click ticket the redirect appends to registered hosts, a per-workspace retention job, page_hit events with an expandable detail view in the contact Activity timeline, a Settings > Website tracking page for the snippet and consent, location and retention configuration, realtime PAGE_HIT fanout, and a website tracking guide plus endpoint, export and configuration docs
|
2026-08-29 03:25:50 -07:00 |
|
Matthew Meszaros
|
42ddb78e60
|
feat: make the realtime service survive a client that spams channel joins, and stop both clients from being that client: ws_join is now spent per phx_join in a shared RealtimeWeb.ChannelGuard that every channel runs BEFORE its Auth lookup (it was only ever spent on the socket handshake, so an established socket could issue unlimited joins and each one cost a Postgres query), handshakes move to their own ws_connect bucket so a reconnect storm cannot eat the budget a client needs to rejoin with, the retry_after_ms hint now points at the next window instead of shrinking as overage grew, every channel's join rejection carries the numeric code the API reference already promised (plus 4005 for a malformed topic), BulkChannel only pushes an event to the user who owns the operation instead of to anyone who guesses the id, and the web and admin clients treat a rate_limited join as transient (wait out the hint, keep the socket) while backing off per-channel rejoins on a decaying schedule rather than reconnecting on the 120ms floor forever; adds an ExUnit suite for realtime and a vitest suite for admin, both wired into CI
|
2026-08-26 21:14:34 -07:00 |
|
Matthew Meszaros
|
8bd2c2b57a
|
feat: make self-hosting work end to end and rewrite the guide around what was tested (#97)
|
2026-08-13 09:47:46 +02:00 |
|
Matthew Meszaros
|
4962765a79
|
fix: format the org_channel AI_DRAFT access_unibox clause to satisfy mix format --check-formatted (Elixir CI)
|
2026-07-15 06:47:07 +02:00 |
|
Matthew Meszaros
|
56de65380b
|
feat: inbox agent that drafts a suggested unibox reply on inbound human replies for human approve/edit/discard - paid + per-org opt-in (organizations.inbox_agent_enabled) feature where the consumer's reply hook, on a non-automated reply, detaches a goroutine (panic-contained, never blocks ingest) that checks entitlement, dedupes via ai_thread_drafts partial unique indexes (one pending per thread, unique source_message_id), pre-checks balance, grounds a reply in the thread history + org voice + skills via generation.Provider.Complete, reserves a draft row then charges 5 credits (idempotency inbox_agent:<draft.ID>, row unwound on a fresh context if the charge fails so no unpaid draft lingers), and emits an org-scoped AI_DRAFT_READY event gated on access_unibox; the agent never sends - only a human POST to /unibox/agent-drafts/:id/approve sends through the normal reply path, claiming pending->approved before send with an approved->pending revert on send failure, alongside list + discard endpoints; plus the unibox awaiting_agent_draft badge + agent_drafts search scope, an AgentDraftCard in the thread view with inline-editable approve-and-send/discard, the workspace settings opt-in toggle, CanUseInboxAgent paid gate, migration 000065, and docs (inbox-agent guide, endpoints, realtime)
|
2026-07-14 06:13:27 +02:00 |
|
Matthew Meszaros
|
f48d51bf16
|
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 |
|
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
|
e190571696
|
feat: harden the live channel with an is_map payload guard, byte-bounded chat/id/resource strings, a per-surface permission gate that strips cursor-chat text, and a websocket max_frame_size cap
|
2026-07-02 20:33:44 +02:00 |
|
Matthew Meszaros
|
88cabf5cac
|
feat: cap the live:select ids payload before traversal so an oversized selection list is never fully walked by the realtime channel
|
2026-07-02 14:31:36 +02:00 |
|
Matthew Meszaros
|
02b25724f4
|
feat: extend the ephemeral live channel with a sanitized chat field on live:cursor frames and a new live:select kind that broadcasts a capped node-id list for canvas selections
|
2026-07-02 07:40:06 +02:00 |
|
Matthew Meszaros
|
3ffd4416a2
|
feat: add a generic live:patch channel kind that fans out a small sanitized scalar map for ephemeral collaborative-state hints
|
2026-06-30 10:34:14 +02:00 |
|
Matthew Meszaros
|
248c886290
|
feat: add an ephemeral live:cursor/live:node channel path to the realtime org channel that bypasses the Redis ws limiters and the sequenced resume buffer via an in-process token bucket and broadcast_from fan-out
|
2026-06-30 10:06:19 +02:00 |
|
Matthew Meszaros
|
b83aa51921
|
feat: make CUSTOM_EVENT fire-event signals an explicit allow on the org channel and return structured {code, reason} errors on a failed channel join
|
2026-06-14 11:02:12 +02:00 |
|
Matthew Meszaros
|
799e5f10ef
|
feat: surface WebSocket connection-rejection reasons to the client as a structured {code, reason, retry_after_ms} payload (Discord-style 4003/4004/4007/4009/4010) instead of a bare 403, and fix the rate-limit 3-tuple match
|
2026-06-14 11:02:12 +02:00 |
|
Matthew Meszaros
|
4552ab4e31
|
feat: make the org realtime channel a resumable gateway — assign a monotonic per-org sequence + buffer each event in a capped Redis stream (Realtime.EventLog) before broadcast, advertise the current seq in the HELLO and stamp it on every event, and replay the missed gap (re-filtered) on reconnect via resume.last_seq or signal a full resync when the buffer no longer covers the client
|
2026-06-13 11:23:07 +02:00 |
|
Matthew Meszaros
|
c5ced50868
|
fix: apply mix format to the realtime service (supervisor child-list indentation in application.ex + org_channel.ex) so the Elixir CI format check passes
|
2026-06-12 17:45:32 +02:00 |
|
Matthew Meszaros
|
3cbfc06bc4
|
feat: add WebSocket intents (selective event-family subscription) and a HELLO-style org join reply advertising heartbeat cadence, and correct realtime docs on connection rejections and at-most-once delivery
|
2026-06-12 07:17:09 +02:00 |
|
Matthew Meszaros
|
4f1ac8c273
|
feat: enforce org team-presence privacy in the realtime OrgChannel — gate Presence.track on show_online, strip viewing/editing detail when show_activity is off, and re-track/untrack live on PRESENCE_POLICY_UPDATED
|
2026-06-12 05:59:01 +02:00 |
|
Matthew Meszaros
|
70064e9e1d
|
fix: define OrgChannel.handle_out/3 so presence_diff broadcasts are pushed to clients instead of crashing the channel — the missing callback was terminating the org channel and dropping every websocket connection in a reconnect loop
|
2026-06-11 13:47:11 +02:00 |
|
Matthew Meszaros
|
371fe0c0a3
|
feat: add Phoenix.Presence org collaboration layer (online members, viewing/editing/replying activity) with permission-gated org event fanout in the realtime service
|
2026-06-11 07:51:34 +02:00 |
|
Matthew Meszaros
|
ce870a15b3
|
ci: fix Elixir formatting / Elixir version / missing pnpm lockfile
- realtime/: `mix format` applied; long Logger calls reformatted across
config/runtime/application/connections/user_channel/user_socket/
endpoint. CI's "Check formatting" step now passes.
- CI Elixir bumped from 1.16 → 1.18 (with OTP 27) to match mix.exs's
`~> 1.18` requirement. Phoenix 1.8.7 + plug 1.19 also expect this.
- web/: generate + commit pnpm-lock.yaml so actions/setup-node@v4's
pnpm cache step + `pnpm install --frozen-lockfile` can resolve.
|
2026-05-23 16:17:27 +00:00 |
|
Matthew Meszaros
|
141bc54974
|
Add sample auth UI theme
|
2026-02-10 19:30:47 +01:00 |
|
Máté Mészáros (Laptop)
|
ed35ab2dbc
|
Realtime Updates
|
2026-01-30 15:32:58 +01:00 |
|
Máté Mészáros (Laptop)
|
6adb4cdd5a
|
Organization, Subscription, Inqueries, limits.
|
2026-01-27 05:55:48 +01:00 |
|
Máté Mészáros (Laptop)
|
5ac159d2f8
|
Realtime, api keys & more
|
2026-01-26 16:04:42 +01:00 |
|