Friday, May 8, 2026
CaseChat Notifications Reach Everyone, Smokeball Parity Complete
Three portal releases and one mobile release shipping together. The biggest thread: CaseChat notifications now work end to end. Client-sent messages reach the attorneys on the case (they did not before), home-screen badge counts stay in sync across every device you are signed in on, and notifications still reach users who do not have the mobile app via SMS and the in-app inbox. Smokeball reaches feature parity with Clio, Filevine, and MyCase. A pre-flight investigation surfaced a tenant-isolation bug that had been silently mis-routing phase notifications across firms; it is fixed, with the affected cases re-routing themselves on the next CMS import.
CaseChat Notifications Now Reach the Whole Case portalapp
Two stacked bugs in the CaseChat push path were dropping notifications on every client-to-attorney message. The receiver was bailing out when the sender was the room host (true for every primary-client message), and even past that, the recipient logic only ever notified the host themselves, never the attorneys assigned to the case. Result: when a client sent a chat message, no one on the firm's side got pinged.
Fixed at the receiver. Every CaseChat push now fans out to the full set of room members minus the sender. The deep link inside the push carries the case and room ID through correctly, so the mobile app routes to the right thread on tap. The firm ID propagates through the workflow so per-firm communication settings stay enforceable.
A coupled fix on the mobile side. Attorneys are now prompted to enable push notifications on first sign-in, instead of the prompt only firing on the client home tab. Without this, attorneys never landed a push token in their account, so even with the receiver fix above there was nothing to deliver to. Attorneys who initially decline get a one-tap "Enable Notifications" banner above the chat list to grant permission later, which hides itself once a token is registered.
Notifications Now Reach Users Without the App portal
CaseChat notifications used to be push-only. A user who had uninstalled the app, signed in via web only, or just had no working push token silently received nothing. The workflow now widens to push, SMS, and the in-app inbox, with the per-channel routing decided by the recipient's actual device state at trigger time:
- Has a working push token: push only, plus the in-app inbox entry.
- No working push token: SMS instead, still gets the in-app entry.
- Either way, the portal's notification bell stays accurate.
User notification preferences still apply on top, so anyone who has SMS off keeps SMS off. A second guardrail keeps the system from over-messaging. The existing "you got a push but did not read it" SMS nudge no longer fires for users without push tokens (they had nothing to mark read), and the timing on the nudge for users with push was bumped from about 45 seconds to 15 minutes, so it actually catches "did not see the first one" cases instead of arriving while the user is still in whatever context kept them from reading the first push.
Live Cross-Device Badge Sync portalapp
The home-screen badge count on iOS and Android now stays current even when the Quilia app is closed. Read a message on your phone and the badge updates on every other device you are signed in on. Read it on the portal and your phone's badge clears. The number on the app icon now matches the in-app counter the way iMessage, Slack, and RingCentral do.
- One source of truth, server side. The unread total lives in a single server-maintained record per user instead of being summed in each app from per-room counts.
- Carried in the push payload. Every CaseChat push now includes the recipient's running unread total as a badge override, so the icon is correct before you even open the app.
- Silent badge syncs across devices. When you read on one device, a silent push (no banner, no sound, just a badge update) goes out to your other signed-in devices to keep them aligned.
Tap-to-Chat Deep Links app
SMS and notification taps now land on the right CaseChat screen across push tap, SMS link tap, and the legacy quilia:// custom-scheme tap. Attorneys go straight to the case's chat. Clients land on the right case, or bounce through the case picker if they do not have a default. Multi-room cases route to the correct room, and in-flight notifications using the older URL shape continue to route correctly.
User IDs were also dropped from the SMS link body, so deep links can no longer leak account identifiers through cached or indexed link previews.
Honest Invite Confirmation for Salesforce, Litify, and Filevine portal
When firm staff click the "Invite to Quilia" custom button inside Salesforce, Litify, or Filevine, they land on a public confirmation page. That page used to render an unconditional "your client has been sent a text" panel the moment it loaded, regardless of whether the underlying invite actually went through.
The unconditional success message is gone. The page now tells staff what really happened and what to do next.
- Successful invites read "Invitation sent. Your client should receive a text shortly."
- A still-running invite reads "We're inviting your client. This usually takes under a minute," and updates live.
- Known errors map to friendly copy plus a fix-it link. An unmapped Practice Area, for example, says "Map your Practice Area in Integrations, then click the button again," with a deep link straight to the Practice Areas page for that CMS.
- Phone mismatches, missing-client matters, and unreadable matter IDs each get their own actionable message.
- If the page can't reach realtime status (some browsers block third-party cookies on the public route), it surfaces an "Open Quilia to confirm" CTA instead of falsely claiming success.
Litify and Salesforce see "Practice Area" labeling. Filevine and the others see "case type."
Smokeball Reaches Feature Parity portal
Three releases of Smokeball-actualization work landed in a row. Smokeball now matches Clio, Filevine, and MyCase across the surfaces firms actually use day to day.
- Multi-party matters import correctly. Smokeball matter import previously took only the first client and silently dropped every other party. All firm-side clients on the matter (co-clients on a multi-party PI case, husband and wife on an auto matter, parent listed alongside a minor) now land as case members, with the primary client treated the same as before. Co-clients without usable phones are logged and skipped rather than blocking the rest of the import.
- A "Quilia" folder on every matter. First upload finds-or-creates a folder named "Quilia" on the matter, and every subsequent upload reuses it. No duplicate folders, no documents drifting to the matter root.
- The case-types dropdown reflects the actual firm. It used to return either nothing or thousands of unusable rows because Smokeball's global matter-types endpoint is a state-suffixed template library, not a firm-scoped list. The dropdown now derives matter types from the firm's real matters and refreshes on Reimport, dropping load time from up to a minute to about five seconds.
- The Reimport button on the integration settings page works. It had been silently 500-ing for every firm with a valid OAuth connection because it was the only remaining caller of an old code path that read sessions from a legacy table. It now uses the same canonical session storage every other CMS integration uses.
- The Import Phases button is actually phases-only. It was previously re-running the full Reimport every time, walking matters paginated and re-hydrating every matter type before getting to the stage-sets call. It now imports only the phases. When Smokeball returns zero phases, the success message says exactly what is missing in Smokeball's setup and what to do next.
- The Smokeball import dialog surfaces real failures. When an import bailed because the matter had no client, the client had been deleted, or the client was a business contact instead of an individual, the dialog used to fill progress to 100 percent with a green checkmark even though no Quilia case was created. It now renders an actionable error box with the actual reason. A deleted contact gets a restore prompt. A business-contact client gets a reassign-to-individual prompt.
- Rate limiting and token refresh are handled. Smokeball's published 10-requests-per-second cap is now respected with internal pacing on bursty Reimport calls, and 429 responses retry with backoff. Expired access tokens refresh preemptively and retry on a 401 instead of failing every Smokeball call for the next hour after the token quietly expires.
- Webhook subscriptions auto-recreate after re-authentication. Smokeball wipes webhook subscriptions on OAuth re-auth, with a 30-day refresh-token TTL. The OAuth callback now lists, validates, and recreates webhook subscriptions on every reconnect, so firms do not silently lose webhook delivery a month after their initial connect.
Reliability and Stability
- Phase notifications now route to the right firm portal: a tenant-isolation bug had been silently mis-routing phase messages on 357 of about 22,000 cases (1.6 percent) since the first multi-firm CMS onboarding. Fixed; affected cases re-route cleanly on the next CMS import.
- Deactivated firms no longer send SMS portal: the deactivation flag was not cascading to the comms-guard layer, so a paused firm could still send push and SMS through several paths. Every comms exit point now respects the flag with highest precedence.
- Appointment activity log restored portal: appointment create and delete events were silently skipping the case Activity Log after a recent API migration. They are back.
- Continue to case button after a CMS import shows a spinner portal: it used to disappear into a multi-second navigation with no feedback. It now disables and swaps to "Loading case..." as soon as it is clicked.
- Stale-tab recovery after a deploy portal: the cryptic action error that used to fire when a user had an old tab open during a deploy is gone, with a client-side reload backstop for any residual mismatch.
- Filevine import-case responses parse safely portal when Filevine returns an empty body, an HTML error page, or non-JSON 5xx content. Previously this would throw and crash the import on a retry.
- Clio matter lookups for deleted, closed, or rotated IDs portal return cleanly instead of logging recurring errors. Real failures still surface.
- Neos sync retries transient gateway failures portal instead of aborting the whole sync task on a single bad response from the partner-login endpoint.
- CMS service initialization timeout raised from 10 to 15 seconds portal across all integrations, to accommodate normal cold-start token-exchange latency.
- Add New Case and manual Add are now opt-in for invites portal: sending the invite SMS now requires an explicit checkbox. The org-level "auto-invite" setting only governs webhook-driven CMS imports and external API consumers.
- Builder template stale links render the proper 404 page portal instead of a blank page with an opaque error.
- Sign-up nudges consumer-email signups toward the app portal: when someone signs up with a personal email (gmail, yahoo, icloud, and similar), an inline note points them at the mobile app download page. Submission is not blocked.
- iOS dark-mode splash screen renders full-screen app: cold launch was showing the Quilia logo as a small card on a mostly blank, light background. Dedicated dark splash asset.
- Dark mode polish app: a handful of screens that did not fully respect the system theme are corrected, including the CaseChat outside-hours banner (which is also now hidden for attorneys and legal staff).
- Medical provider search returns results again app: a safety guard added in the previous release was returning an empty list when filtering by case ID. Regression coverage was added.
- Android Play Store submission accepted app: an upstream library was injecting unused photo and video permissions into the merged manifest, and Google was rejecting submissions on that basis. Stripped at build time.
- Session reliability hardened at the wrapper app: stale-session permission errors that earlier releases patched per-caller now short-circuit cleanly inside the shared session-refresh wrapper, so every Supabase caller is protected automatically.


