Commit Graph

  • a57214ea73 docs: note the AI steps on the automations canvas in the readme feature list Matthew Meszaros 2026-07-21 18:22:55 +02:00
  • da19936442 Merge pull request #78 from warmbly/feat/ai-agent-steps Matthew Meszaros 2026-07-21 18:15:04 +02:00
  • a82ec44547 fix: allow the docs native build scripts so next build works after the workspace file Matthew Meszaros 2026-07-21 18:07:41 +02:00
  • d997a5fdbd fix: clear the js-yaml advisory in the docs lockfile too Matthew Meszaros 2026-07-21 18:02:40 +02:00
  • d4b201eef0 fix: bump axios and js-yaml to clear the trivy security scan Matthew Meszaros 2026-07-21 17:59:46 +02:00
  • f48ae60476 feat: build the ai step editors and smooth out the flow lines Matthew Meszaros 2026-07-21 17:35:11 +02:00
  • 66aaaa6584 feat: add an ai agent step to campaign sequences Matthew Meszaros 2026-07-21 17:35:11 +02:00
  • 93b64e2afa feat: add shared run time listing and arg resolving for ai agents Matthew Meszaros 2026-07-21 17:35:11 +02:00
  • a44b7b0215 feat: add the unified ai step and ai switch to automations Matthew Meszaros 2026-07-21 17:35:11 +02:00
  • ffc219a66d feat: clean up the dither charts and give them more room Matthew Meszaros 2026-07-21 17:35:11 +02:00
  • f898e4975f fix: show the real plan badge, mailbox tags and live sidebar stats Matthew Meszaros 2026-07-21 17:35:11 +02:00
  • b465f30d42 fix: scope account analytics by org id not user id Matthew Meszaros 2026-07-21 17:34:59 +02:00
  • 912a07b6e1 feat: make the sandbox seed a full realistic demo org Matthew Meszaros 2026-07-21 17:34:59 +02:00
  • bebc09289d build: cross compile the go images and fix realtime and the healthchecks Matthew Meszaros 2026-07-21 17:34:59 +02:00
  • 6bd53f532e ci: trim the workflows and speed up the build and push Matthew Meszaros 2026-07-21 17:34:59 +02:00
  • aeaa26d2d2 fix: use a valid local kms dev key and warn when sandbox port 8080 is taken Matthew Meszaros 2026-07-21 17:34:59 +02:00
  • 6227439952 Merge pull request #77 from warmbly/self-host/local-stack Matthew Meszaros 2026-07-20 11:59:27 +02:00
  • 8055c2f05f Merge remote-tracking branch 'origin/main' into self-host/local-stack Matthew Meszaros 2026-07-20 11:53:21 +02:00
  • 248347c8e6 feat: warn on the mailboxes page when too few mailboxes are warming for a healthy pool, with an add-mailboxes action and a cloud option Matthew Meszaros 2026-07-20 11:50:53 +02:00
  • 2af4bd084e copy: say largest instead of biggest across the marketing site Matthew Meszaros 2026-07-20 11:21:57 +02:00
  • 62b1384b7d docs: sharpen the readme documentation section and drop the em dashes Matthew Meszaros 2026-07-20 11:21:57 +02:00
  • 037779a78b docs: de-stale the local development guide for the no-cloud nats stack Matthew Meszaros 2026-07-20 11:12:37 +02:00
  • 2fdaa28887 docs: rewrite the sandbox guide for the one-command flow and the fuller seeded dataset Matthew Meszaros 2026-07-20 11:12:37 +02:00
  • 638c40c629 feat: make make sandbox a one-command demo stack and drop the stale kafka/localstack/worker-premium targets Matthew Meszaros 2026-07-20 11:12:37 +02:00
  • bbc1377a80 fix: point sandbox mailboxes at the worker that actually runs, seed that worker row, and wire in the analytics dataset Matthew Meszaros 2026-07-20 11:12:37 +02:00
  • 332851a0d3 feat: seed deliverability, contact activity, reply intents, suppression, mailbox errors, an audit trail, a teammate, an api key, and completed/paused campaigns for the sandbox Matthew Meszaros 2026-07-20 11:12:37 +02:00
  • af048b9d75 feat: restore the dovecot imap host behind a sandbox profile so seeded mailboxes really sync Matthew Meszaros 2026-07-20 11:12:36 +02:00
  • 58d7baf79d docs: cover the no-cloud setup and the PUBLIC_HOST knob Matthew Meszaros 2026-07-20 09:56:47 +02:00
  • 49ffaedc9f feat: run make dev on nats and make make up the one-command self-host Matthew Meszaros 2026-07-20 09:56:47 +02:00
  • 9590bd63fb feat: add a no-cloud docker compose stack Matthew Meszaros 2026-07-20 09:56:47 +02:00
  • a419bde824 build: make the docker images cgo-free and cache-mounted so builds are fast Matthew Meszaros 2026-07-20 09:56:47 +02:00
  • 3922333930 feat: run the tracking service on nats by default, kafka behind a cargo feature Matthew Meszaros 2026-07-20 09:56:29 +02:00
  • b1070ce097 feat: rip the cloud-provisioning and billing pages out of the admin ui Matthew Meszaros 2026-07-20 09:56:29 +02:00
  • 897da46e6c feat: drop the cloud-provisioning and billing admin routes Matthew Meszaros 2026-07-20 09:56:29 +02:00
  • 543d97f6f3 feat: wire the no-cloud providers into the consumer and worker Matthew Meszaros 2026-07-20 09:56:29 +02:00
  • ed51b081e6 feat: wire the no-cloud providers and billing-off into the backend Matthew Meszaros 2026-07-20 09:56:29 +02:00
  • 866e096a2b feat: add a billing-off mode that unlocks every feature Matthew Meszaros 2026-07-20 09:56:17 +02:00
  • fc91d71492 feat: make google, apple and turnstile optional at boot Matthew Meszaros 2026-07-20 09:56:17 +02:00
  • f94215d27a feat: move kafka behind a build tag so the default build is cgo-free Matthew Meszaros 2026-07-20 09:56:16 +02:00
  • fb853ea23d refactor: publish mailbox validation over the bus and drop the raw kafka producer Matthew Meszaros 2026-07-20 09:56:16 +02:00
  • 19f753e163 refactor: route worker events and tracking through the event bus Matthew Meszaros 2026-07-20 09:56:16 +02:00
  • e8de52ce30 refactor: put the task client behind a scheduler interface Matthew Meszaros 2026-07-20 09:56:16 +02:00
  • e38de91fec feat: add an in-process postgres task scheduler so delayed sends need no cloud tasks Matthew Meszaros 2026-07-20 09:56:02 +02:00
  • 8de314ae8b feat: serve public blobs from the backend and fix avatar uploads on filesystem Matthew Meszaros 2026-07-20 09:56:02 +02:00
  • 0f1886b9dd feat: add a filesystem blob storage backend Matthew Meszaros 2026-07-20 09:56:02 +02:00
  • 7e84da7f2a feat: add config helpers for the provider switches Matthew Meszaros 2026-07-20 09:56:01 +02:00
  • d90e07659e chore: remove the dead astra/cassandra code and deps Matthew Meszaros 2026-07-20 09:56:01 +02:00
  • 59d5cc4ca2 Merge pull request #76 from warmbly/feature/notifications Matthew Meszaros 2026-07-20 08:23:45 +02:00
  • 07c6ae0aa7 feat: kill the settings autosave PUT storm: useAutosave becomes single-flight (the change effect re-arms every render because save is an inline closure, and with the baseline only moving after the response every render during an in-flight save fired another request; concurrent callers now share one in-flight promise and a trailing loop picks up edits made while saving), the notifications settings page hydrates its draft from the server exactly once so refetches never stomp or re-trigger mid-save, and the preferences PUT writes its echoed envelope into the react-query cache instead of invalidating (no more refetch per save) Matthew Meszaros 2026-07-20 08:17:50 +02:00
  • 85ab4ad7b5 feat: replace the notification email cadence enum with a configurable bundling window and drop the instant mode entirely: email_digest_minutes (30 minute floor, 30 default, 1440 max, constants in config) replaces email_digest with no per-event option or NOTIFICATION_EMAIL_ALLOW_INSTANT escape hatch, the handler validates the range and email_delivery now returns min/max minutes so clients render the bounds, the web settings page offers window presets (30m/1h/3h/daily) plus a Custom minutes NumberInput and iOS swaps the cadence menu for window presets including the server value when it matches none, the repo clamps stored values on read, and the guide plus deployment guide describe the window and keep only the NOTIFICATION_EMAIL_DAILY_CAP env Matthew Meszaros 2026-07-20 08:01:22 +02:00
  • 682ef3ac24 feat: cost guards on the notification email channel: the per-event instant cadence becomes self-host opt-in (NOTIFICATION_EMAIL_ALLOW_INSTANT, default off - PUT rejects it, stored values read back as smart, holds degrade to smart) with the capability exposed as email_delivery on the preferences GET so web and iOS hide the option on hosted deploys, each user gets a rolling 24h budget of non-security notification emails (NOTIFICATION_EMAIL_DAILY_CAP, default 25, 0 unlimited) counted off sent rows with over-budget alerts skipped to the in-app feed while security sign-ins always send, and coalesced group emails re-verify org membership at flush time so a member removed during the hold is dropped from To; deployment guide documents the three envs and the guide notes both limits Matthew Meszaros 2026-07-20 07:44:43 +02:00
  • 5d930057d9 feat: harden the notifications settings page against version skew: normalizeNotificationPreferences mirrors the backend defaults merge on the client (missing billing_alert/team_activity/email_digest filled with defaults, invalid cadence coerced to smart) and the page normalizes the fetched preferences before drafting, so an older backend or cached response can no longer crash the category rows Matthew Meszaros 2026-07-20 07:36:17 +02:00
  • 0186ed5c78 feat: web notification center + digest settings: the bell dropdown becomes a real notification center with per-category icon chips and tones, Today/Yesterday/Earlier group headers, compact relative timestamps, unread accent styling, All/Unread filter pills, first-load skeleton, empty state and a settings footer link; the settings page gains Billing and Team category sections and an Email delivery section using the shared OptionSelect radio idiom (Instant/Smart with Recommended badge/Hourly/Daily) riding the same autosave PUT, with the read-in-app/security-immediate/shared-email note; the preferences model adds billing_alert, team_activity and the email_digest union, and OptionSelect labels widen to ReactNode for the badge Matthew Meszaros 2026-07-20 07:21:20 +02:00
  • 33b779a406 feat: iOS notification preferences catch up with the digest-first email channel: NotificationPreferences decodes via a dynamic keyed container so the new email_digest scalar no longer breaks the flat category-map decode (older servers get billing_alert/team_activity seeded with backend defaults), the settings screen gains an Account group with Billing and Team category rows plus an Email delivery section whose Menu picker sets the instant/smart/hourly/daily cadence through the same PUT as the toggles with revert-on-failure, and the feed inherits icons for both new categories via the shared meta mapping Matthew Meszaros 2026-07-20 07:20:33 +02:00
  • 74c32bfec6 feat: document the digest-first notification email channel in the notifications guide: the three delivery rules (read in-app means no email, unread bundles into one email, shared events send one email with every recipient in To), the four cadences with smart as default, the always-immediate security sign-in exception, the new billing and team categories with their defaults, and the permission-targeted routing callout Matthew Meszaros 2026-07-20 07:18:19 +02:00
  • a534ef1908 feat: notification email channel becomes digest-first: email-channel notifications queue as pending rows (migration 000076 adds group_key/email_state/email_due_at/email_attempts) with a due time from a new per-user email_digest cadence (instant/smart 15m/hourly/daily, security sign-ins always immediate), a 30s flush loop with SKIP LOCKED claims bundles a user's pending rows into one digest email and coalesces org-shared group_key events into a single email with every recipient in To, reading a notification in-app cancels its pending email, and NotifyOrg targets only members holding a permission (Slack fires once per group) with new producers: dead-worker downtime to manage_emails members (SetNX-deduped per incident), trial expiry to manage_billing members via new billing_alert category (replacing the direct owner email), and invitation accepts to manage_team members via new team_activity category Matthew Meszaros 2026-07-20 07:16:25 +02:00
  • a813096b8b Merge pull request #75 from warmbly/feature/compose-email Matthew Meszaros 2026-07-20 06:53:13 +02:00
  • 0ecaf008f3 feat: iOS From picker parity + tag-scoped Auto: the tag chip row becomes a native Menu filter offering every user tag (not just in-use ones) with color dots and checkmarks, filtering turns the Auto row into Auto in <tag> previewing the best in-tag candidate and picking it carries autoTagID into the compose send as from_tag_id (cleared by explicit picks), the From row reads Auto in <tag> with the best member email via account tags lifted into ComposeStore, and ContactPickerSheet swaps its category chips for the same compact menu idiom Matthew Meszaros 2026-07-20 05:33:06 +02:00
  • 847f3ba472 feat: document the From menu in the unibox guide: Auto scoring order, tag filtering, tag-scoped Auto picking within a mailbox group, and the from_tag_id API field Matthew Meszaros 2026-07-20 05:28:05 +02:00
  • 296e781ce5 feat: scoped Auto in the dashboard From menu: filtering by a mailbox tag turns the Auto row into Auto in <tag> previewing the best-scored member, the pick carries the tag through onChange into ComposeWindow state and the send request's from_tag_id, and the collapsed From row chip reads auto with the tag title while the resolved-signature preview resolves to the best mailbox within the tag Matthew Meszaros 2026-07-20 05:28:05 +02:00
  • f20300a280 feat: tag-scoped auto mailbox pick on compose: POST /unibox/compose accepts from_tag_id which restricts the automatic sender choice to active mailboxes carrying that tag (best-with-budget-first within the group, 400 when the tag has no active members, ignored with an explicit account; GetByTags is user-scoped so foreign tag ids resolve to no members) Matthew Meszaros 2026-07-20 05:28:05 +02:00
  • 91c12e91be feat: document undo send: the unibox guide gains an Undo send section (default 30s, 5-120s under Settings Profile, header countdown with cancel, scheduled and smart sends unaffected) and the unibox API reference notes instant sends hold for the undo window with scheduled_at reflecting it and DELETE /unibox/scheduled/:task_id cancelling inside it Matthew Meszaros 2026-07-19 18:56:55 +02:00
  • c53225e6f3 feat: undo send in the dashboard: instant compose and reply sends feed a new outbox store and an amber header pill counting down to the server scheduled_at with inline Cancel plus a portaled dropdown listing every pending send with per-row cancel, cancelling a compose reopens the docked composer from a full draft seed and cancelling a reply navigates to the thread and reopens the reply composer prefilled via a restore handoff, 404 collapses to Already sent, and the profile settings page gains an autosaved Undo window NumberInput (5-120s) wired to PUT /auth/me/send-preferences patching the cached /auth/me user Matthew Meszaros 2026-07-19 18:56:55 +02:00
  • 10217039f0 feat: undo send in the iOS app: instant compose and reply sends swap the sent toast for a dark UndoSendBanner capsule counting down to the server's scheduled_at with an Undo button that cancels via DELETE unibox/scheduled/:task_id, compose undo reopens the sheet through the draft-resume path with the full payload and reply undo re-presents UniboxComposer prefilled from a UniboxReplySnapshot, 404 collapses to an Already sent toast, expiry flips the capsule to Sent briefly, and the User model gains undo_send_seconds (default 30 when absent) Matthew Meszaros 2026-07-19 18:53:21 +02:00
  • db400ac086 feat: undo send window on the backend: migration 000075 adds users.undo_send_seconds (default 30, CHECK 5-120), emailsend queues instant sends (compose, reply, agent-draft approvals) that many seconds into the future so the existing DELETE /unibox/scheduled/:task_id cancel path can still stop them, the value rides /auth/me and a new JWT-only PUT /me/send-preferences updates it with bounds validation and user-cache invalidation Matthew Meszaros 2026-07-19 18:45:50 +02:00
  • e46fc1cd3e feat: make the composer picker search feel alive: contact searches debounce 300ms and keep previous results on screen while the next query loads (new useDebouncedValue hook + keepPrevious option on useSearchContacts), the browse panel and From menu ease their height with a ResizeObserver-driven AnimatedHeight instead of snapping, in-flight searches show a spinner in the search box plus shimmer skeleton rows on first load, FilterMenu closes itself on any outside click or Escape (its trigger lives inside a data-floating panel the shared hook ignores, so opening the sibling filter now closes the other), and the browse panel widens to 400px Matthew Meszaros 2026-07-19 18:36:31 +02:00
  • 038668ff51 feat: clean up the composer picker chrome: a new compact FilterMenu (quiet bordered trigger showing the active choice, portaled dot-row dropdown) replaces the chip rows — the From menu's tag filter becomes one small All-tags dropdown beside the search box, and the browse-contacts panel collapses its three header rows (search, category chips, sort row) into a single row with search plus category and sort dropdowns, hugs its content height instead of a fixed 380px, shows one category badge per row, and only reveals the Add footer once something is picked Matthew Meszaros 2026-07-19 18:15:56 +02:00
  • 7eb8510a89 feat: fix the composer's From tag chips and browse-contacts panel: the From menu now offers every defined tag (not just ones already on a mailbox, so a tag created in the bulk bar is immediately selectable), and the browse panel portals to the body with a viewport-anchored fixed position and flip (the compose window clips overflow, so the 380px panel was being cut off inside the To row and reading as a cramped overflowing box), matching the MailboxPicker portal pattern Matthew Meszaros 2026-07-19 17:06:00 +02:00
  • 2aeaa577c8 feat: iOS mailbox tag management: a reusable tag picker sheet (search, colored-dot rows, multi-select, inline Create-tag that POSTs /tags cycling the palette and refreshes the session), a Tags section on the mailbox detail Setup tab editing via the optimistic PATCH /emails/:id path, and bulk Add/Remove tags in the list's selection capsule driving the new PATCH /emails/tags endpoint with reload, select-mode exit, and a light haptic on apply Matthew Meszaros 2026-07-19 16:14:17 +02:00
  • 07315cb118 feat: iOS compose polish from simulator feedback: the AI menu now targets highlighted text (shared selection quick actions plus a Custom edit through the prompt bar's editing-selection mode, stale-range guarded), the From picker gains tag filter chips built from the account directory and the member's tag definitions (only tags actually in use are offered), and every recipient field gets a plus button opening a browse-contacts sheet with search, category chips, multi-select checkmarks, and already-added rows disabled Matthew Meszaros 2026-07-19 16:14:17 +02:00
  • 02a524616e feat: composer recipient upgrades: a user-plus button on the shared recipient field opens a browse-contacts panel (search, category filter chips, Recent/Name/Email sort, checkbox rows with category badges, already-added rows disabled, Add-N appends with case-insensitive dedupe) available in both compose and reply, and the docked compose window now auto-minimizes to the corner bar when you navigate to another page so the draft follows you without covering the destination Matthew Meszaros 2026-07-19 16:13:58 +02:00
  • 5fae462bb2 feat: bulk tag mailboxes from the list's selection bar: a Tags popover with an Add/Remove segmented toggle, tag search, checkbox rows with colored dots, an inline Create-tag row (POSTs /tags cycling the editor's palette and updates the profile cache), and an apply button that hits the new PATCH /emails/tags bulk endpoint, invalidates the emails queries, and keeps the row selection for chaining Matthew Meszaros 2026-07-19 16:13:58 +02:00
  • e1750d8988 feat: add PATCH /emails/tags for bulk mailbox tagging: add_tags/remove_tags set semantics across up to 1000 mailboxes in one transaction (ownership of both mailboxes and tags enforced in SQL so stale ids are skipped, composite-PK insert makes re-adds no-ops), naturally idempotent so no Idempotency-Key needed, one audit entry with account/added/removed counts riding the email_account spine, and the endpoint registered in the docs scope map under WRITE_EMAILS Matthew Meszaros 2026-07-19 16:13:43 +02:00
  • d21711523f feat: port the AI assistant to the iOS app: a sparkles button on the Home hero opens a full-screen chat that streams answers over SSE with live text deltas and tool-step chips, pauses on approval_required with Approve/Always allow/Deny, rehydrates persisted transcripts, and shows remaining credits or the free-model note; the history sheet groups conversations into Today/Yesterday/This week/Earlier with title search, swipe delete, clear-all behind a confirm, live refresh off the ai_session spine, and owner attribution when shared history is on Matthew Meszaros 2026-07-19 15:04:50 +02:00
  • b5515bef0f feat: bring the iOS reply composer to compose parity: To/Cc/Bcc swap their plain text fields for the shared chip recipient fields with contact autocomplete and category filters, the AI surfaces gate on the Use AI permission instead of manage_campaigns, and the duplicated schedule sheet gives way to the shared ComposeScheduleSheet Matthew Meszaros 2026-07-19 15:04:50 +02:00
  • 06ad6cf51b feat: port the compose experience to the iOS app: a Gmail-style FAB on the inbox opens a new-email sheet with a scored From picker (Auto pick with the live recommendation, auth dot, today budget, history reasons), chip recipient fields with category-aware contact autocomplete, a suppression warning strip, instant/smart/scheduled sends through POST /unibox/compose, autosaved drafts (client-generated id, debounced idempotent PUT, close keeps the draft, send deletes it) with a Drafts drawer row to resume or swipe-delete, and a grounded AI draft bar that can return a clarifying question answered inline, with grounding and usage on the review card Matthew Meszaros 2026-07-19 15:04:42 +02:00
  • 0c6ef58bd8 feat: iOS core plumbing for the AI + compose port: APIClient gains a native SSE stream method (Bearer-attached byte stream with one refresh retry on 401, data:-line parsing, 600s timeout for long agent runs, task cancellation aborts the run server-side), OrgPermissions gains the Use AI bit (32768), and the realtime spine maps the ai_session audit entity to a new ai invalidation domain Matthew Meszaros 2026-07-19 15:04:35 +02:00
  • ccbb6b068c feat: soften the dither charts for the white theme: tones drop from 600 to 500-level hues (slate-900 to slate-600), dither fill dots render at ~84% alpha so they blend into the page while lines and hovered elements stay fully opaque, legend dots match, and the campaign overview legend swaps its dark active pills (which read as a black background with every series on) for the light slate-100/white style the other pages use Matthew Meszaros 2026-07-19 14:17:11 +02:00
  • 03634358de feat: compose all metrics on one graph: DitherMultiAreaChart draws a smoothed line per series with nested dithered bands (per pixel the smallest containing band wins so overlaps read as layers) and a shared crosshair dot-per-series tooltip; the shared chart becomes MultiTrend, and analytics, campaign overview, and deliverability swap their single-metric switcher for legend toggles with tone dots that show/hide series in place (deliverability starts with sent hidden so failure signals stay readable, and at least one series always stays on) Matthew Meszaros 2026-07-19 14:13:24 +02:00
  • 71e04c00dd feat: roll dithered charts across the dashboard: the shared DailyBars becomes DailyTrend (smoothed dithered area graph) powering campaign overview, analytics, and deliverability over-time charts with per-metric tones, deliverability provider placement rows use DitherStack, the mailbox warmup chart becomes a dithered bar chart with target ghost bars and tap-to-pin day selection, API-key traffic uses DitherColumns, and the content score, campaign send progress, credits meter, and unibox queue bars all move to DitherMeter Matthew Meszaros 2026-07-19 14:01:53 +02:00
  • 7502b0f2b4 feat: grow the dither kit for the analytics surfaces: a violet tone, area-chart tooltips anchored to the hovered dot (flipping below near the top edge), ghost reference bars + tap-to-pin selection on DitherBarChart, DitherColumns stacked vertical columns with per-part tones and hover callback, and DitherStack horizontal share bars with a left-to-right reveal Matthew Meszaros 2026-07-19 14:01:53 +02:00
  • e7144a439d feat: upgrade the AI usage view: the daily bars become a smoothed dithered area graph with a 7d/30d/90d range switcher (breakdowns follow the range, previous data held while the new range loads so nothing flashes), and limit cells drop the boxy stepper input for a big inline-editable value with a dashed-underline affordance, the dithered slider, quiet text presets, and a No cap idle state Matthew Meszaros 2026-07-19 13:50:03 +02:00
  • e4ad9e3661 feat: make billing tabs real URL paths: the route becomes billing/:tab? with /app/settings/billing/plans, /ai-credits, and /payment slugs (unknown slugs normalize to the overview), Stripe checkout and topup return URLs point at the tab they left from, the header credits meter deep-links to /ai-credits, the settings topbar subtitle matches nested billing paths, and the document title covers the sub-paths Matthew Meszaros 2026-07-19 13:50:03 +02:00
  • f0b9c5f49c feat: add DitherAreaChart to the dither kit: a monotone-cubic smoothed line with a dithered area fill fading to the baseline, left-to-right draw-in reveal, and a hover crosshair with dashed guide, line-anchored dot, and tooltip — a real graph, not bars Matthew Meszaros 2026-07-19 13:50:03 +02:00
  • 7524d1ea37 feat: redesign the AI spend-control experience: each workspace and per-member limit is a cell with an animated expand, a dithered slider with window-sized presets and an exact number field, and a live spent-vs-limit meter; edits collect into a floating Reset/Save bar instead of writing eagerly; the 30-day chart, spend stats, and breakdowns move to dithered canvas fills with tooltips and animated counts, the credits balance ring goes dithered, and the ai-credits guide notes the new tab and limit controls Matthew Meszaros 2026-07-19 13:39:07 +02:00
  • 587bda2039 feat: split the billing settings page into browsable tabs (Overview, Plans, AI & credits, Payment) with an animated sky underline and per-tab fade transition, sync the active tab to ?tab= so Stripe topup returns land back on the AI tab and the header credits meter deep-links to it, route the current-plan button to the Plans tab, and render the usage rows with dithered meters and animated counts Matthew Meszaros 2026-07-19 13:39:07 +02:00
  • 98cb220147 feat: add hand-rolled dithered canvas primitives in web/src/components/ui/dither.tsx: Bayer-4x4 ordered-dither bar chart with staggered entrance and hover tooltip, progress meter with a dithered leading edge, donut ring with a dithered sweep tip, a pointer+keyboard slider on a dithered track, and a rAF AnimatedNumber — the dither-kit look with zero new dependencies and prefers-reduced-motion fallbacks Matthew Meszaros 2026-07-19 13:39:07 +02:00
  • f7a1027367 feat: add workspace-shared assistant history: a manage_settings toggle on the organization (assistant_shared_history, off by default) makes every conversation visible to and continuable by every member with the use-AI permission — the service resolves a session to its owner's rows so open/continue/approve/delete all work cross-member while credits still charge the acting member, the org-wide listing joins owner names for attribution in the history rail, the workspace settings page gains the AI assistant section with the toggle and an explicit exposure warning, and the assistant guide's access and privacy sections describe both modes Matthew Meszaros 2026-07-19 13:22:56 +02:00
  • 68e3ca6b6b feat: extend the per-member AI limit to all three windows: member_limit_daily and member_limit_weekly join the monthly ceiling on org_ai_settings, MemberSpentInWindows sums the acting member's debits per window in one query, checkSpendLimits enforces day/week/month member ceilings with window-specific 429 messages, and the billing card's Per-member limits row grows the same three fields as the workspace caps Matthew Meszaros 2026-07-19 13:22:56 +02:00
  • 458234cd5d feat: add clear-all assistant history: DELETE /ai/sessions wipes every conversation the member owns in the workspace (transcripts cascade, count returned, audited as an ai_session delete with clear_history metadata), the history rail gains a Clear history footer action behind the in-app confirm that also closes all session-backed tabs, and the assistant guide documents access gating, per-member limits, privacy, and both delete paths Matthew Meszaros 2026-07-19 11:05:18 +02:00
  • f4014b8b73 feat: add a per-member monthly AI credit limit to the org spend controls: new member_limit_monthly on org_ai_settings flows through the settings repo, PATCH endpoint, and billing UI (its own Per-member limit field on the AI usage card), and checkSpendLimits enforces it by summing the acting member's debits this calendar month via the ledger's actor attribution (new MemberSpentSince query on the partial index from migration 000073), returning a 429-mapped member-limit error while unattributed scheduled work stays exempt Matthew Meszaros 2026-07-19 11:05:18 +02:00
  • 7ef7d90d8c feat: introduce the Use AI organization permission (bit 15, the last of the 16-bit mask) gating every AI surface: assistant session routes, generation write/edit, and the compose and reply draft endpoints get a member-permission layer (API keys re-check their existing bit), migration 000073 backfills the bit onto all existing roles and member overrides so nobody loses access, defaults grant it to admin and manager but not viewer, and the web mirrors it in the permission catalog with gating on the header spark button, Cmd+I, the panel itself, and the AI drafting caret (plus team-roles and endpoint-map docs) Matthew Meszaros 2026-07-19 11:04:58 +02:00
  • bacbf5552f feat: upgrade the assistant's full-screen history rail: conversations group under Today/Yesterday/This week/Earlier sections, a search field filters them by title, each row gets a hover (always-visible on touch) delete action behind the in-app confirm that also closes the conversation's open tab and invalidates the list, the New chat button shows its Alt+N kbd chip, and the guide documents deletion and search Matthew Meszaros 2026-07-19 10:50:33 +02:00
  • 2de973df68 feat: add DELETE /ai/sessions/:id so members can remove an assistant conversation: repository delete scoped by org and user with the transcript cascading via FK, not-found on zero rows, an ai_session delete audit entry (which the existing realtime spine turns into live history refreshes), and the endpoint registered in the docs scope map Matthew Meszaros 2026-07-19 10:50:33 +02:00
  • 459d423bb5 feat: document the assistant's live streaming behavior in the guide: answers stream in word by word and each tool step appears the moment it starts Matthew Meszaros 2026-07-19 10:42:10 +02:00
  • 8eb2824ac4 feat: render the assistant's stream like a live agent and surface its keybindings in the panel: text_delta chunks append to a live-flagged trailing block that the closing full-text event replaces, the trailing block of a running turn types itself out through a rAF SmoothText typewriter with the blinking caret so even chunky providers read as continuous generation, and the empty state gains kbd chips for toggle, new chat, pop out, and minimize plus an all-shortcuts link into the shortcuts dialog Matthew Meszaros 2026-07-19 10:42:10 +02:00
  • 4e576daddf feat: stream the dashboard agent's text token by token: the OpenAI-compatible provider now runs chat completions with stream=true whenever a listener is attached, forwarding content deltas as a new EventTextDelta (SSE text_delta) while stitching tool-call fragments by index, capturing usage via stream_options with a sticky compatibility fallback, tolerating backends that ignore streaming, and always closing each block with the authoritative full-text event (now also emitted for commentary alongside tool calls) Matthew Meszaros 2026-07-19 10:41:45 +02:00
  • ab938575d3 feat: give the AI assistant a floating window mode on desktop: pop out via the header button, Alt+P, or tearing the docked header off its edge, then drag it anywhere by the header and resize from any edge or corner (360-920 wide, min 400 tall, always clamped fully on screen), with the geometry persisted alongside side and width, a dock-back button targeting the remembered edge, and the assistant guide updated Matthew Meszaros 2026-07-19 10:31:20 +02:00
  • 633615c341 feat: move the compose-drafts invalidation from useMutation onSuccess into the mutationFn promise chain, because closing the composer fires the save and unmounts in the same tick and observer callbacks are skipped after unmount, which left the rail's Drafts list stale until a full reload Matthew Meszaros 2026-07-19 10:31:20 +02:00
  • b866d2b99d feat: harden the From menu's tag filter and search field: tag chips now derive from the store's mailbox directory sorted by position instead of the candidates fetch (so they show even while candidates load), the search input gets a real slate border instead of the invisible white-on-white fill, and the panel clamps against clientWidth so its right edge cannot slip under a scrollbar Matthew Meszaros 2026-07-19 10:21:25 +02:00