📄 Release Notes — v1.6.0
Codename: Brand Identity
Release Date: September 17, 2026
[www.nineminds.com/alga-psa](http://www.nineminds.com/alga-psa)
🚀 New
-
🎨 Email Branding. Every system email AlgaPSA sends on your behalf (ticket updates, invoices, portal invitations, password resets) can carry your colors instead of ours. Pick one or two brand colors, or accept the palette suggested from your theme or portal branding, and a live preview shows each template repainted before anything is written. Apply to every template and language in one pass or choose the ones you want; hand-edited templates are left alone unless you opt them in. Enterprise adds your logo in the header and the option to drop the "Powered by AlgaPSA" footer. Behind a feature flag.
-
☎️ 3CX Phone System Integration. Connect a 3CX PBX and callers are identified against your contacts in the 3CX client, while finished calls journal as Call interactions on the contact and client, with the same auto-ticketing and unmatched-caller queue Teams Phone uses. Setup is one downloaded CRM template and one key. On 3CX Enterprise and AI editions with API access, a ringing extension pops an incoming-call card in AlgaPSA with the caller, client, open tickets, and recent interactions; any phone number in the app can dial through the PBX from the technician's own extension and journal against the ticket it was placed from; call history backfills from the PBX log on a schedule; contacts sync two-way with the 3CX company phonebook; and PBX transcripts and summaries attach to the call and open in the side drawer. Enterprise, Pro tier, behind a feature flag.
-
🔁 Xero Two-Way Sync. Payments and credit notes recorded in Xero now flow back into AlgaPSA. The sync polls Xero for invoice, payment, and credit-note changes, applies each exactly once (replays and reversals reconcile, and a replacement payment that settles the invoice keeps the net balance), and flags an invoice whose Xero total or number has drifted from what was exported without touching your invoice lines. Sync Now, health, and status follow the connected provider instead of assuming QuickBooks, the export dialog lists only connections for the adapter you picked, an ambiguous choice between two Xero organisations refuses to guess, and connection status reports a missing invoice-write scope or a refresh that needs a reconnect. Payments, credits, and voids made in AlgaPSA are not pushed to Xero and are recorded as unsupported rather than silently skipped.
-
🔗 Ticket External System Links. A ticket that started in GitHub, Jira, Slack, Discord, email, the portal, the API, or a system you define can now carry a clickable pointer back to its counterpart, labelled origin, mirror, or reference, with one origin per ticket. Links show in both ticket layouts and on the v1 API, including lookup by external id, so an integration can find the AlgaPSA ticket for a GitHub issue or Jira key without a mapping table of its own. Custom systems are managed under Settings → Ticketing → External systems. MSP-only; the client portal does not render them.
-
🔑 Keycloak Single Sign-On. Keycloak (OpenID Connect) is now a first-class SSO provider alongside Google and Microsoft. Tenants configure their own realm under Security → Single Sign-On, users are matched by email, and the sign-in button appears only when discovery says it should, so a misconfigured realm never strands a login page. Available in Community Edition, where it is the SSO option; Google and Microsoft SSO remain Enterprise.
-
🧾 Quick Invoice a Ticket. Bill a support ticket directly. Open Quick Invoice from the ticket, tick the approved unbilled time and unbilled products to charge, and a draft invoice tied to the ticket is created through the normal manual-invoice path, so tax, numbering, and totals behave as they always have. Each selected item is claimed in the same transaction, so a stale or concurrent selection can never bill twice, and the dialog lists the invoices already raised against the ticket.
✨ Improved
-
📈 Catalog Price Changes Reach Existing Contracts. A contract line now either keeps a custom rate chosen for that client or follows the catalog, and changing a catalog price opens a rollout dialog that shows which lines change, by how much, and from which effective date before you commit. Lines that predate this release bill exactly as they did until a Rate Review pass classifies them.
-
🧮 Invoices That Show Time by Ticket. Invoice layouts can present billed time as one row per ticket, built from a snapshot taken at generation so later edits never change what the customer received. A Standard Invoice By Ticket layout ships ready to use. Behind a feature flag.
-
📎 Comment Attachments That Reach the Customer. Files attached to a ticket comment go out with the notification email to every recipient, with a per-recipient delivery ledger; oversized files travel as a short-lived link bound to that recipient. Files on internal comments stay internal. Behind a feature flag.
-
👁️ Client Portal Visibility Controls. Contact-scoped visibility groups, board statuses portal users cannot select, and boards hidden from the portal entirely; all opt-in.
-
🗓️ Schedule Straight from the Ticket. Click an agent on a ticket to open their calendar, drag a slot to book the ticket, and move, resize, edit, or delete entries in place.
-
🔐 Password Vault Audit Log. A vault-wide Audit log and per-credential History show who revealed, changed, linked, or deleted what and when, never a credential value, behind a new credential:audit permission. Pro.
-
🔢 Usage and Seat Billing, Made Explicit. Usage lines distinguish dated entries from one replaceable period total, fixed lines distinguish a bundle allocation from seats billed at quantity times rate, and the invoice preview names any service with missing usage and offers to record it in place instead of quietly charging nothing. Authoring options behind a feature flag.
-
📅 Month-End Close. Generate a calendar-month arrears invoice on the last day of the month instead of waiting for the 1st, with server-side checks that the period is complete and today really is the final day in your billing timezone. Behind a feature flag.
-
📊 Tax Setup in One Place. Tax sources, regions, and rates now live together under Billing → Tax as one expandable table showing the rate each region carries today, with overlapping rates flagged and the Active switch finally exposed.
-
🧷 Date Tokens in Document Numbers. Numbering settings gain an optional date format, so an invoice can read INV-2026-09-000005 without touching the prefix or resetting the counter; every numbered record now issues through the same service.
-
📞 Interactions on the Calendar. Any interaction with a start time can be added to a calendar as you log it, or booked onto a colleague's calendar by anyone with the schedule permission; entries follow edits and deletions. Admins can pick the default interaction status in Settings.
-
🎥 Teams Meetings from Any Schedule Entry. Create a Microsoft Teams meeting from an existing calendar entry, including one occurrence of a series; the meeting follows reschedules and is retracted when the entry is deleted. Behind a feature flag.
-
🔎 Entra Connection Diagnostics. Run diagnostics on the Entra console's Connection tab walks a Direct or CIPP connection layer by layer, stops at the layer that fails instead of cascading red, names the fix alongside the AADSTS code, and produces a redacted support bundle. Tenant discovery can also be re-run from the Connection tab after setup. Enterprise and Pro.
-
🔑 TOTP Setup Without a QR. Password vault TOTP setup takes a pasted setup key and shows a live six-digit code with a countdown. Pro.
-
📋 Store-Only Service Requests. A service request definition can complete as a stored, immutable submission with no ticket or workflow, for questionnaires and intake forms that should be kept rather than worked. Behind a feature flag.
-
🌐 Custom Portal Domains in Community Edition. Self-hosted Community Edition installs can provision a custom client-portal domain out of the box;
TRUST_FORWARDED_HOST=trueis the one setting for a host-rewriting reverse proxy. -
🖼️ Wide Logo, Favicon, and a Rail That Knows Its Color. White-labeling gains a wide wordmark for the expanded side menu, a favicon for the MSP app and client portal, and logo variants that follow the actual rail color. Enterprise.
-
📨 Email Notification Templates, Edited Side by Side. The custom template editor shows subject, HTML, and text beside a live preview: click an element in the preview to select its markup, move the caret in the source to outline the element. The templates table opens on your default language, the saved palette can be applied from inside the editor, and tenant templates are readable and writable over a new v1 email templates API.
-
🧾 Quotes Carry Item Name and Catalog Description. Quote lines snapshot the catalog description at quote time, and the standard templates stack the item name over it in one cell; the designer offers both as separate fields. Totals-row colors saved in a quote or invoice layout are now editable in the designer, and recurring quote discounts land in the recurring group with correct grouped totals that survive duplication, revision, sales-order conversion, and invoice recalculation.
-
🧮 Xero Exports by Revenue Account. A Xero organisation with no Products & Services items can be invoiced through revenue accounts: each service mapping now targets either a Xero Item or a Xero Revenue Account explicitly, validated against the connected organisation when you save it.
-
🔍 Searchable Pickers, More Currencies. Accounting mapping pickers and every currency dropdown in the app are searchable; type "eur" instead of scrolling. Swedish Krona and South African Rand join the currency list with the right symbols on documents.
-
🧰 Bulk Actions on Services and Products. Select many rows in the service catalog or the products list and deactivate, activate, archive, restore, or delete them together; rows still in use are skipped and named in the toast instead of aborting the batch. The missing Billing → Service Categories screen is back, with importing the standard categories as its empty-state action.
-
🏠 Your Country by Default. Quick Add Client, the location dialog, contact phone entry, and CSV imports default to the tenant's own country rather than the United States.
-
📖 Documentation One Click Away. A "?" menu in the header opens Documentation and Contact Support in a new tab; the sidebar Support link stays where it was.
-
🤖 RMM Fixes Across Providers. Tactical RMM asset details, software inventory, and the Reboot Device action now work as intended (live vitals no longer read "Never checked in"). NinjaOne organizations larger than one page sync completely, and new NinjaOne alerts that arrive without an organization are resolved from device mappings before rules evaluate. Level.io webhooks authenticate correctly and group-scoped rules match again.
-
🧭 Appliance License and SSO Reporting. The appliance Manage tab shows the licensed edition from the token (a Pro license reads Pro, not "ee") and distinguishes an unreachable app from no license. Microsoft or Google SSO configured through a provider profile now reports as available and links correctly on appliances.
-
🗺️ Project Template Wizard Protects Your Work. Backdrop clicks, Escape, and the X on the Add Template wizard ask before discarding an unsaved template.
-
🧵 Tickets That Stay Readable. Long comments clamp with a Show more control, the timeline caps at about one and a half screens, threads past three replies fold behind "Show N earlier replies", and replying opens a sticky dock at the bottom instead of an inline composer that vanished below tall comments.
-
🏷️ Asset Types and Secrets Settings. The Asset Types table is reachable from the sidebar again and gains search, sorting, pagination, and row-click editing. Settings → Secrets, linked from the sidebar but never functional, now works: create, edit, and delete tenant secrets with an audit trail.
-
🧾 Deferred Revenue Reads Real Prices. The deferred revenue report values catalog-priced lines from the effective service price in the contract currency, so it agrees with billing for non-USD contracts.
🐞 Fixes
-
Fixed contract-scheduled recurring lines running out of service periods so due charges quietly disappeared from Ready to Bill: a nightly sweep now extends every active contract line's coverage 180 days ahead and backfills missed periods, without touching billed, locked, edited, or skipped periods and without generating any invoice on its own.
-
Fixed the ticket list blanking with "Ticket list filters are no longer valid" when an Assigned To filter carried an empty, stale, or "unassigned" token in the URL.
-
Fixed the v1 API returning
is_closed: falseand a nullclosed_atin the response to the very update that closed the ticket. -
Fixed Microsoft shared-mailbox outbound email failing with 403: sends now route through the authenticated user's mailbox or the shared mailbox as appropriate,
Mail.Send.Sharedis requested at connect time, and the Resend fallback keeps your display name and Reply-To. -
Fixed Alga's own ticket notifications being re-ingested as client comments when two connected mailboxes in one tenant emailed each other, without suppressing a genuine reply that quotes the notification.
-
Fixed inbound email from Gmail-hosted mailboxes failing sender authentication and landing on the default client; Google-format Authentication-Results headers now parse.
-
Fixed the reply parser cutting a message at the first inline quote (an Outlook quoted block mid-message could drop most of a request); only real quoted history is trimmed, and operators can now repair ownerless email comments.
-
Fixed scheduled comments never publishing on hosted tenants, so the client email and response-state change now go out on time.
-
Fixed a paused SLA workflow polling every minute and writing tens of thousands of history events per ticket, which was timing out and destabilizing the workflow engine.
-
Fixed quote template fields (including Terms & Conditions) never reaching a quote created from the template, and quote terms losing paragraph breaks in the PDF.
-
Fixed AMP spreadsheet imports failing with "File type not allowed", and two different sheets sharing derived row ids so one import could silently skip onto another's records; skipped rows now say which earlier package claimed them.
-
Fixed "Add Usage" failing with "Tenant context not found", usage dates shifting a day across the UTC boundary, same-named contract lines being indistinguishable in the picker, and Record Usage deep links opening on All Clients.
-
Fixed a recurring window whose lines produced no charges escaping duplicate detection and generating two invoices for one period, date-only invoice dates rendering a day early west of UTC, and month-end close stamping the server's date instead of the tenant's billing calendar.
-
Fixed invoice credit being applicable beyond the unpaid balance, tax threshold minima and untaxed gaps being ignored, overlapping open-ended tax rates being accepted, and compound tax previews disagreeing with the configured semantics.
-
Fixed changing a saved table's Source Binding in the invoice designer being silently dropped on save, and every preview failure collapsing to "Failed to render template using Wasm" instead of naming the missing binding.
-
Fixed document links pointing at a retired file id after a PDF re-render (404), and file-less documents in the ticket grid opening a download that could not exist.
-
Fixed the ticket conversation showing "Unknown User" for client-portal repliers and deactivated agents, email reply avatars showing "UU" next to a real name, avatars spinning forever when an image fails to load, and multi-line pastes stored as one paragraph that would not display.
-
Fixed editing an interaction opening with empty Type and Status, and interactions logged without an explicit status being created already closed.
-
Fixed personal email notification preferences on the MSP profile not saving.
-
Fixed Stripe payment webhooks from a tenant's own connected account never verifying (every delivery a 503): the tenant's endpoint secret is checked before the platform secret.
-
Fixed tenant onboarding silently skipping support-portal access when the customer's name already existed as a client, and matching an unrelated signup to another customer's client on company name alone.
-
Fixed calendar sync running against providers that never completed OAuth and flipping them to "connected" on an empty window; unauthorized providers now report an honest status with the real OAuth error, and the Microsoft calendar delta sync no longer calls a Graph path that does not exist.
-
Fixed the availability settings dialog: dropdowns that swallowed the next click, a dialog that drifted with the pointer after a release outside the window, Escape discarding unsaved edits, one technician's hours being overwritten by another user's pending save, split shifts treated as duplicates, and managers able to overwrite rows outside their scope.
-
Fixed all-day calendar entries losing a day through drag, resize, and Microsoft sync; overnight entries vanishing from the agent Week view; and a typed title being wiped when the entry editor re-rendered.
-
Fixed the workflow designer reporting an untouched expression three times on publish, keeping a stale "Invalid" badge after the fix was saved, and a control block missing a branch taking down validation with a 500.
-
Fixed a leftover unique constraint rejecting notification templates in a second language, which blocked per-language customization.
-
Fixed sidebar clicks intermittently doing nothing right after login while dashboard widgets fired a burst of actions, and a burst of server actions signing a working tenant out mid-click when the session check could not reach the database.
-
Fixed the accounting sync queue throwing on concurrent enqueues, a provider disconnect after reconnect never actually revoking the grant, and the legacy xero-csv v1 routes always denying.
-
Fixed Actual Hours on the task form looking editable when it is calculated from time entries, and date-format validation errors in numbering settings showing a generic "failed to save".
-
Fixed reference-data imports with a service-category rename conflict rolling back the whole import, and new installs shipping boards with no closable status.
-
Fixed manual invoice line-item edits resetting when an unrelated part of the page re-rendered, and duplicate Teams meetings for one schedule entry, which are now prevented at the database.
-
Appliance / self-host: fixed the Temporal connection binding being lost on the appliance, Entra contact sync failing with a read-only filesystem error when refreshing tokens, mobile push notifications never registering against self-hosted servers, and the mobile Start Timer endpoint returning 500 on hosted tenants.
🎨 UX & Polish
-
🌗 High Contrast, Legible. The high-contrast theme pair gets readable country-code badges and placeholder text that no longer reads as a typed value; the Actual Hours well and other read-only fields follow every theme pair instead of light-mode grays.
-
🪟 Dialogs That Behave. Escape inside a nested dialog closes only the inner one, a dialog drag ends when the mouse button is released outside the window, three notification dialogs got their headings back in the drag handle, and adding a contract from a client's Billing tab opens the quick-add and wizard as full-size modals instead of squeezing them into the drawer.
-
📅 A Steadier Schedule Page. The header toolbar no longer re-flows after first paint, the Configure Availability button paints immediately from the last known answer, and the agent calendar drawer opens wide enough for seven readable day columns with chips, gridlines, and dialog spacing tuned over several review rounds.
-
🧭 Tax Is Now Tax. The billing tab and sidebar entry are relabeled from Tax Rates to Tax in every locale.
🔐 Stability & Security
-
Accounting integrations are now governed by five purpose-specific permissions (catalog read, connections manage, mappings manage, exports execute, remote mutate), granted to Admin and Finance by default, and the settings screens hide controls the user cannot use.
-
QuickBooks and Xero OAuth callbacks re-authorize the live user against a single-use, server-bound state before storing anything; the Xero PKCE verifier no longer travels through the browser, default Xero scopes are reduced to what the integration uses, and provider error data is redacted end to end in logs, audit rows, and export metadata.
-
Accounting mapping resolution is realm-exact: a mapping only matches the QuickBooks company or Xero connection it was recorded against, legacy realm-less rows are quarantined for review instead of guessed, invoice voids are serialized against export mapping creation, and provider disconnects are durable, provider-first, and retryable.
-
Tenant secrets on the filesystem are written atomically with explicit 0700/0600 modes, anchored to directory handles, and symlinked or foreign-owned locations are refused; a repair script converges an existing store.
-
The permission catalog is now one source of truth (236 entries with per-product default grants), consumed by onboarding seeds, the AlgaDesk to AlgaPSA upgrade, and a one-time reconciliation that converges every existing tenant additively.
-
Client-portal callers are rejected at every MSP ticket write and at external-link mutations; board status configuration writes require the ticket-settings permission; workflow action inputs are redacted before persistence and run exports enforce ownership.
-
Maintenance fan-outs run only for tenants that have the integration configured, take a per-job lock so a slow run cannot be duplicated, and 53 permission checks moved inside their transactions to stop draining the connection pool.
-
Recordings fetched from providers store a fixed MIME type, and product-generated artifacts (AMP packages, invoice bundles, previews) are stored through a separate validator from user uploads, which fails closed.
-
Mobile: API-key last-used writes are throttled to once a minute per key, and a rotated access key gets a 30-second grace period so in-flight requests finish.
-
Dependabot burn-down: open alerts reduced from 166 to 17 across the root and fourteen standalone lockfiles.
📊 Dev & Infra
-
Production regression readiness. A new gate reconciles required test discovery against actual execution so a missing, skipped, retry-only, stale, or failed suite cannot produce a ready candidate. It adds production-built browser and API journeys, tenant isolation, billing and payments, provider emulators (including new Xero and 3CX emulators and 101 Microsoft Graph cases), PostgreSQL and Citus upgrades from a pinned v1.5.0, and an owned, expiring quarantine registry.
-
Faster integration suites. Test databases are cloned from a migrated, seeded template keyed by the migration source hash: about one second per file instead of 15 to 70 seconds of replayed migrations.
-
Microsoft Graph endpoint guard. Every Graph call in the codebase is validated against Microsoft's published CSDL metadata in CI, with a monthly repin that fails once the pin is stale.
-
API v1 additions. Email templates (list, read, write, reset per name and language), ticket external links (five routes plus lookup by external id), interaction statuses and interaction updates, scheduled ticket comments (schedule on create, cancel), ticket document thumbnail and preview routes, a mobile push-token test endpoint,
cap_amountandcurrency_codeon tax rates, Entra diagnostics routes, and catalog reads that split currentpricesfromscheduled_prices. OpenAPI and MCP registries regenerated. -
Nightly contract coverage sweep. Runs on the Temporal maintenance fan-out on Enterprise and as a pg-boss recurring job elsewhere, exactly one schedule per deployment, with a read-only coverage audit for operators.
-
CI hygiene. MinIO images from quay.io, parallel fresh-install image builds, a 120-minute integration budget, and the nightly appliance channel documented.
📱 Mobile App — v1.6.1 (build 34)
-
🎨 Your Theme on the Phone. The app renders the tenant's theme pair (all nine presets and custom pairs) from the server, caches it so a warm launch never flashes the default, and gains an Appearance setting for System, Light, or Dark. The comment editor and every remaining hard-coded color follow the pair, and the high-contrast pair draws bolder chrome.
-
📸 Multi-Photo Upload and Previews. Attach from Camera, Photos, or Files with multi-select; uploads run in sequence with batch progress and per-file retry. Image rows show server thumbnails and the preview opens an 800×600 variant with a swipeable gallery and share, instead of downloading every full-size file.
-
⏰ Send Later. Schedule a client-visible comment for a chosen time, see it badged in the thread, and cancel it before it goes out.
-
📞 Interactions. A drawer-level Interactions list with type, status, owner, and date filters, plus a detail sheet to close, reopen, or annotate. Tickets gain a Calls and emails section, and a call placed from a contact, client, ticket, or opportunity prompts you to log it with the elapsed time when you return to the app.
-
📝 Client Notes on Tickets. Field technicians can read and append the client's notes from a dispatched ticket.
-
🔔 Push That Registers. Push registration works against self-hosted servers, re-registers daily so a server-side reset heals, clears on sign-out or host change, and Settings gains Send test notification. Also fixed: the Start Timer 500 on hosted tenants and a client filter that stuck across relaunches.
Full Changelog: v1.5.0...v1.6.0
Full Changelog: v1.5.0...v1.6.0