Commit Graph
60 Commits
Author SHA1 Message Date
Matthew Meszaros 0ae4db2c41 feat: make self-hosted auth work without a mail relay by rewriting the platform SMTP transport with real AUTH and TLS (it did neither, so SMTP_USERNAME/SMTP_PASSWORD were dead and every documented relay was unreachable), adding MAIL_TRANSPORT=smtp|log|ses with a log transport that prints codes so a fresh install can sign in with no relay, demoting the emailed login code to AUTH_LOGIN_CODE=always|new_device|off (off on self-host, per NIST SP 800-63B and OWASP ASVS), claiming the first owner through a single-use setup link or WARMBLY_BOOTSTRAP_* instead of register-then-psql, deriving every emailed URL from APP_URL rather than a hardcoded app.warmbly.com that leaked live reset tokens to the vendor, fixing the confirm hooks that read path params against paramless routes and broke login, register and reset confirmation in the dashboard everywhere, adding generic OIDC with PKCE, one-time state, verified nonce and (issuer,subject) identity binding, enforcing 2FA on the social paths that skipped it, adding a per-IP limiter and trusted-proxy handling to the unthrottled auth group, refusing boot on the published default secrets, and dropping mailpit from the default stack (#99) 2026-08-14 14:57:09 +02:00
Matthew Meszaros 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 2026-07-20 08:01:22 +02:00
Matthew Meszaros 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 2026-07-20 07:44:43 +02:00
Matthew Meszaros 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 2026-07-20 07:20:33 +02:00
Matthew Meszaros 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 2026-07-20 05:33:06 +02:00
Matthew Meszaros 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) 2026-07-19 18:53:21 +02:00
Matthew Meszaros 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 2026-07-19 16:14:17 +02:00
Matthew Meszaros 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 2026-07-19 16:14:17 +02:00
Matthew Meszaros 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 2026-07-19 15:04:50 +02:00
Matthew Meszaros 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 2026-07-19 15:04:50 +02:00
Matthew Meszaros 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 2026-07-19 15:04:42 +02:00
Matthew Meszaros 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 2026-07-19 15:04:35 +02:00
Matthew Meszaros 527f1f95a1 feat: upgrade the iOS unibox AI writing and label experience to web parity: thread-grounded Draft reply with staged shimmer status, typewriter reveal, and a Keep/Adjust/Retry/Discard review bar, selection and whole-draft rewrites through the fenced generation/edit endpoint with parity quick actions and a custom Editing selection mode, insert-at-cursor prompt generation, usage chips and 402/429 handling, plus a search-or-create label picker sheet with instant optimistic saves, removable chips, row context-menu labeling, and a bulk Label action with progress and toast 2026-07-18 17:00:56 +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 927da9805d feat: kind-aware campaign sequence preview in the iOS app - decode the conditions/action jsonb the steps endpoint already returns and render wait/action nodes with plain-language summaries plus per-step branch routes (if opened within 3 days, goes to step 4), keeping the read-only edit-on-web handoff 2026-07-13 16:11:00 +02:00
Matthew Meszaros 38f32abb91 feat: close the iOS realtime gaps against the web spine - route EMAIL_STATUS/EMAIL_ERROR to mailboxes+analytics, SUBSCRIPTION/PLAN/BILLING/LIMIT to billing, DEAL and BOOKING to CRM, refresh analytics on inbox arrivals, and add a foreground socket nudge so a suspension-killed connection recovers instantly instead of ~30s late 2026-07-13 16:10:47 +02:00
Matthew Meszaros b379be9732 feat: qualify self.task in the openSocket admission check - with the type-checker crash worked around, Xcode 26.6 surfaces the real diagnostic: the locked closure's bare 'task' resolves to the local declared later in the function and is rejected as captured before declaration 2026-07-11 10:44:57 +02:00
Matthew Meszaros 04cf24c98d feat: hoist the socket url resolution out of the guard condition entirely - across three CI crashes the Xcode 26.6 type checker dies whenever the async urlProvider closure property is bound or awaited inside a guard condition under StrictConcurrency, so the read, the await and the unwrap are now three plain statements 2026-07-11 10:41:26 +02:00
Matthew Meszaros da1a6efbf8 feat: make the websocket urlProvider a non-optional closure with a nil-returning default because the Xcode 26.6 type checker also crashes on referencing an optional async closure property, not just on optional-chained calls; behavior is unchanged (nil result still schedules a reconnect) 2026-07-11 10:37:33 +02:00
Matthew Meszaros e5f5623dc4 feat: unblock iOS CI - unwrap the websocket urlProvider in two steps because 'await urlProvider?()' crashes the Xcode 26.6 Swift type checker (works on 27), and build only the arm64 simulator slice in CI since the generic destination was doubling the compile for no extra signal 2026-07-11 10:34:07 +02:00
Matthew Meszaros 2d00ff2f69 feat: rename the Icon Composer icon to AppIcon.icon so Xcode 26's asset catalog linker finds the AppIcon.appiconset fallback (the Warmbly name built on Xcode 27 but failed LinkAssetCatalog on the macos-26 runner), and stop truncating the iOS CI build output so failures are diagnosable 2026-07-11 10:28:36 +02:00
Matthew Meszaros 56c3a2e988 feat: app icon becomes a native Icon Composer document matching the Figma branding 1:1 - Warmbly.icon layers the exact 1024px Logo frame render (sky gradient, clouds) under the plane glyph as a separate Liquid Glass vector layer positioned identically to Figma, replacing the flat AppIcon asset via ASSETCATALOG_COMPILER_APPICON_NAME 2026-07-11 10:13:44 +02:00
Matthew Meszaros 76e6ad2466 feat: iOS analytics becomes an air-hero drawer browser cover - the sky hero stays (circular hamburger and close, translucent 7d/30d/90d period chips, glass stat chips) while the web-style tab strip and card grids give way to a section drawer (overview/deliverability/warmup/accounts with issue-tinted counts) over flat native lists; Home now opens analytics and mailboxes as covers instead of pushes 2026-07-11 10:13:44 +02:00
Matthew Meszaros de85abc47c feat: iOS mailboxes rebuilt end to end - the list is a full-screen drawer browser cover (warmup status scopes with live counts, search pill, multi-select bulk warmup/remove, circular close) since pushing it fought the system back swipe; connecting is an air onboarding flow with real Google/Outlook brand logos, a web-style authorize step with scope bullets, working in-app OAuth via ASWebAuthenticationSession against the new warmbly:// callback, an SMTP/IMAP wizard, and a start-warmup offer on success; the detail screen becomes editable (warmup ramp steppers, sending window and weekday bitmask chips matching the Go scheduler's Sunday-first layout, sender profile, sending limits, disconnect) with debounced optimistic PATCHes 2026-07-11 10:13:10 +02:00
Matthew Meszaros c12a621d06 feat: iOS workspace creation is the air onboarding flow - two sky-chrome steps (name, optional invites) creating the org at the end so it works both as the zero-workspaces gate (Sign out is the only exit, like the web) and as a cover with a circular close wired through explicit onClose bindings; the org picker becomes a sky screen with workspace rows and a New workspace path 2026-07-11 10:12:41 +02:00
Matthew Meszaros 928e1924b2 feat: iOS session handling survives network blips and explains sign-outs - token refresh only drops the session on definitive rejections (network errors rethrow and keep tokens), a missing token now kicks cleanly to sign-in instead of hanging, and the auth welcome step shows an amber session-expired notice when the app signed the user out 2026-07-11 10:12:41 +02:00
Matthew Meszaros e6b0bd2918 feat: iOS More tab and CRM rebuilt in the flat browser language - the hub is one full-bleed list with a workspace header and cover rows, Deals/Tasks/Meetings become full drawer browsers (scope sidebars with sliding tone capsules, search pills, end markers), and billing/notifications/profile/security/team pages drop grouped cards for eyebrow-captioned hairline rows 2026-07-11 10:12:41 +02:00
Matthew Meszaros ac87d80604 feat: iOS campaign leads becomes a full drawer browser matching contacts - status scopes (all/processing/replied/bounced/queued/unsubscribed) with live counts in a sky-hero sidebar, advanced contact filters, multi-select bulk edit/remove with optimistic count bumps, an add-leads picker that locks rows already in the campaign, live detail re-derived from the store with presence claims, plus shared contact browser pieces (filters sheet, CSV import, bulk actions, sidebar) and keyboard-safe create-flow sheets 2026-07-11 10:12:09 +02:00
Matthew Meszaros 343fc33b1d feat: campaign schedule board supports multiple timeframes per day - the + button now drops each new window into a free gap kept an hour clear of its neighbours (so a second tap adds a distinct morning-and-afternoon window instead of merging into one), and tapping any bar opens a precise start/end editor sheet with 30-minute wheel pickers plus remove, which is how narrow windows are tuned exactly on mobile where a ~25pt bar can't be dragged pixel-accurately; bars still drag to move and merge when overlapped 2026-07-08 07:06:22 +02:00
Matthew Meszaros 3c8abbb713 feat: rebuild the iOS campaign schedule as an interactive board reimagined for mobile - each day is its own full-width horizontal 24h track (not a cramped 7-column grid) with draggable window bars: tap + to add, drag a bar sideways to move, drag its white left/right handle to resize, tap × to remove, long-press a day to copy it to all or clear it, snapping to 30 minutes, with presets, a timezone menu and today highlighted; writes the authoritative schedule_windows and supports multiple independent windows per day 2026-07-07 19:00:43 +02:00
Matthew Meszaros 80a0ece647 feat: make the iOS campaign Settings page fully editable instead of a read-only wall - sender strategy, rotation mode and ESP matching are inline menu pickers, ramp-up is an enable toggle with start/ceiling/step steppers, and lead flow has a new-leads-per-day stepper (0=off) plus a prioritize-new-leads toggle, all PATCHing optimistically; only CC/BCC lists and tracking-domain DNS stay read-only under an 'On the web' handoff 2026-07-07 17:33:31 +02:00
Matthew Meszaros 326a07d567 feat: rebuild the iOS campaign detail as a flat hub-and-spoke instead of a card-stacked overview - the sheet is now one full-bleed native surface (eyebrow captions, bare stat columns for open/reply/bounce rates plus a live 30-day chart, hairline rows) matching the inbox and campaigns list, with Manage rows pushing to Leads (searchable, count in title), a read-only Sequence with per-step HTML reader, and Senders, all carrying a web-handoff banner for editing that needs a big screen; Sending settings (daily-limit two-disc stepper clamped 1-100, stop-on-reply, open/link tracking) edit inline via optimistic PATCH, and new Schedule (day chips, daily window, timezone picker writing schedule_windows; custom per-day schedules stay read-only) and Settings (name/description, delivery toggles, read-only advanced, creator-only delete) pages 2026-07-07 17:14:44 +02:00
Matthew Meszaros 836f72129f feat: detail screens get a flat full-width underline tab bar replacing the chunky scrollable pills (every tab always visible, sliding accent underline, shared by campaign, mailbox, contact, and analytics details), the white sheet is now clipped so scrolling content can never bleed over its rounded corners, and the campaign create flow presents instantly by mounting the 40fps flight-scene canvas and raising the keyboard only after the cover's slide-up finishes 2026-07-07 10:28:46 +02:00
Matthew Meszaros 7143533bf5 feat: make folder-heavy accounts feel first-class - the create flow's folder page switches to a two-up chip grid with a search box once there are more than eight folders (with a no-matches state), and both the campaigns and unibox drawer cascades cap their per-row stagger so long folder, mailbox, or label lists never animate for seconds 2026-07-07 10:21:23 +02:00
Matthew Meszaros ac74b94c8d feat: campaign creation becomes a stepped sky onboarding flow like sign-in - full-screen cover with the flight-scene backdrop, step badge and progress segments, and three sheet pages: name plus description with live character count, sending pace presets (10/25/50 per day with conservative fresh-mailbox guidance) alongside stop-on-reply and open/link tracking toggles, and an optional skippable folder-filing page that only appears when the member has folders; the create body now carries daily_limit, rule toggles, and folder_ids 2026-07-07 10:02:20 +02:00
Matthew Meszaros 60e70515c0 feat: turn the campaigns tab into a unibox-style browser - hamburger in the search pill slides in a sky-hero drawer with status scopes and campaign folders (counts from campaigns-overview, sliding selection capsule, cascade-in rows, edge swipe to open), scopes and folders now filter server-side so every view has an exact found count and working infinite scroll, replacing the client-side underline tabs 2026-07-07 09:40:27 +02:00
Matthew Meszaros 500ef3419e feat: flatten the campaign detail overview tab from insetGrouped boxes to the flat full-width list - plain style on the system background with inline eyebrow section labels for performance, last 30 days, and per step instead of sticky gray header bands 2026-07-07 07:43:11 +02:00
Matthew Meszaros a5d18f5b3e feat: rebuild the campaigns tab in the flat Gmail language - search pill header with inline presence and a round create button replaces the nav title, underline scope tabs with live counts replace capsule chips, and the list becomes dense full-width hairline rows with a status-toned avatar disc, teammate presence dot, stats line, pulsing status, start/pause and delete swipe actions plus a context menu, and quick start/pause from the row via the new store toggle 2026-07-07 07:43:11 +02:00
Matthew Meszaros 9e77738c5f feat: keep users signed in through backend outages - bootstrap distinguishes a real 401 (clear token, show sign-in) from an unreachable or erroring server, which now lands on a sky unreachable screen that keeps the session and retries automatically every few seconds 2026-07-07 07:27:16 +02:00
Matthew Meszaros 9cfef4937c feat: eliminate white message bodies - plain-equivalent emails now render as native SwiftUI text instead of a webview, and rich-HTML messages get a hardened webview that reloads after web content process termination, retries failed or never-painted loads with a capped budget, and starts from a realistic frame 2026-07-07 07:27:15 +02:00
Matthew Meszaros d1ec6206e7 feat: full schedule-send control - the schedule sheet gains Gmail-style one-tap presets (later today, tomorrow morning/afternoon, Monday morning) with their concrete times shown, a month calendar, a dedicated hour-and-minute time row that was previously clipped at the medium detent, and a will-send summary line, all clamped to the server's scheduling bounds 2026-07-07 06:48:40 +02:00
Matthew Meszaros 2370c6e637 feat: selection-aware AI in the composer - highlighting text in the draft switches the AI dropdown to a Selected text section (rephrase, shorten, expand, more formal, fix grammar) that rewrites only that range via the editor selection binding, guarded against concurrent draft edits and covered by the same one-tap undo 2026-07-07 06:42:21 +02:00
Matthew Meszaros 1633c6274f feat: fix the blank-message-until-tap bug - the email webview now starts from a realistic frame instead of .zero, retries a first load that never committed (dropped mid navigation transition) on any SwiftUI update, and re-measures content height after layout settles 2026-07-07 06:42:21 +02:00
Matthew Meszaros d2613a01fe feat: composer power features - Bcc joins Cc behind a Gmail-style chevron on the To row and rides the reply request, the full-screen AI sheet is replaced by an inline prompt bar above the keyboard plus a rewrite dropdown (improve/shorten/formal/casual/grammar) with one-tap undo, and templates become an instant-insert dropdown with a searchable server-side browser for large libraries 2026-07-07 06:17:16 +02:00
Matthew Meszaros cc01ce900f feat: rebuild the reply composer Gmail-style - borderless full-width From/To/Cc/Subject rows separated only by hairlines, the draft editor fills the whole sheet, send moves to a toolbar paperplane with a when-to-send menu (now/smart/schedule with a graphical date sheet and an inline schedule banner), and AI/templates sit in a quiet helper bar above the keyboard 2026-07-07 06:07:58 +02:00
Matthew Meszaros 2961b4e120 feat: fix thread view bugs - message expansion and measured body heights move into the thread store so LazyVStack row recycling can no longer collapse an open message or blank its body, and the connector rail is drawn as segments that stop at the avatar edges instead of running through the translucent avatar fill 2026-07-07 06:07:58 +02:00
Matthew Meszaros fb7397e26a feat: iOS developer docs - README with project layout and DEVELOPMENT.md covering simulator setup, local backend wiring, and build/run workflow 2026-07-07 05:57:59 +02:00
Matthew Meszaros b4fde65a7d feat: iOS environment wiring - AppConfig backend/websocket endpoints, the observable AppEnvironment composing API/session/realtime/badges, and app entitlements for Sign in with Apple 2026-07-07 05:57:59 +02:00
Matthew Meszaros 29276fe056 feat: iOS analytics and settings - account analytics with charts and audit log, plus the more tab (profile, team, notifications, billing, security) in the air language 2026-07-07 05:57:44 +02:00
Matthew Meszaros eefa88adff feat: iOS mailboxes - account list with health/warmup state, connect sheet, and mailbox detail with settings, limits and deliverability tabs 2026-07-07 05:57:43 +02:00