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