Release notes — Version 2.2

What changed in each version 2.2 release, newest first, as published with the release.

v2.2.6

Released 2026-09-24

  • Manual step (operator, in a maintenance window): after the update run the root setup step from the installed tree, then switch on tenant separation (scripts/maintenance/tenant-dialplan.sh on). Until then internal dialling works as before.
  • Tenant separation: after the switch a phone reaches only the extensions of its own customer (and of users in the same PBX pool). The endpoint context of every device changes from voiplix-from-internal to voiplix-from-internal-<user id>. New installations are separated by default.
  • This release contains database migrations: the update makes a database backup first and takes longer.
  • Update: the automatic database backup made before an update can no longer be deleted by its own clean-up; old backups are ordered by version number and folders without the update marker are never touched.
  • Voicemail and other Asterisk prompts play in the language of the device or DID: German, French and Italian sound packs are installed by the root setup step (the release is about 7.5 MB larger).
  • Internal calls are free (phone to phone, phone to ring group or queue, the leg of a member): price 0, no deduction, the call stays in the call list.
  • Call transfers are billed as follows: a transferred incoming DID call stays free and the part to an outside number gets its own row; a transferred paid outside call is charged for the whole time the outside party stays connected; ringing time is not charged.
  • Calls from devices or via providers with Anti-Resale Auto-Answer (or a pre-dial announcement in answer mode) are charged from the moment the provider answers; busy or unanswered attempts show 0 seconds.
  • Emergency and service numbers (112, 144, 116117 and others) can no longer be used as the number of a device, ring group or queue; an existing entry is left out of the dialplan and reported.
  • Incoming DID calls to a device follow its call forwarding (busy, no answer, unreachable, before call); the forwarded part is billed to the owner of the device, an internal forwarding target is free.
  • Voiplix's own Asterisk files move to /etc/asterisk/voiplix.d/ (root setup step, once per system); only Asterisk and Voiplix can read them.
  • Quickforward DIDs work: a known caller is forwarded and billed; unknown callers and callers without a forward number are rejected without answering (902/903) and listed in Calls with price 0.
  • Balance, remaining time and call rate announcements: when a word is missing from every bundled sound pack, only the number is spoken as in v2.2.5; for unlimited time or a rate of 0 that part is skipped.
  • Call limit: prepaid only the balance, postpaid balance plus credit limit; unlimited only with credit -1.
  • IVR "dial extension" reaches only devices in the IVR owner's area.
  • pjsip_extra per section of a device ([endpoint], [aor], [auth], [identify]); extra lines for the global transports as a system setting (admin only, applied with an Asterisk restart). Results of Asterisk checks are shown in the user's language.
  • Time periods for "before call / no answer / busy / failed to voicemail" use the time zone of the device owner; new page "Personal details" for the own time zone.
  • PBX pools, with pool 1 "Global"; users in the same pool reach each other. A pool that a reseller created earlier under number 1 gets a new number.
  • Phone keys for transfer and recording work on Asterisk 21 after the root setup step (blind transfer ##, attended transfer *2, disconnect *0, recording *1).
  • The Docker installation runs the application as a normal user instead of root.
  • Device and DID language codes are checked when saving.

v2.2.5

Released 2026-09-23

  • Access control now applies to every signed-in account, not only to system logins. A page that a role must not open now redirects to the no-access page instead of relying on each page to say so itself.
  • Fixed: the Profit page had no permission check at all and could be opened by resellers, partners and end customers by typing its address, although the menu never offers it. For partners and end customers it showed the operator own purchase price, and therefore the margin. The same applied to Loss-making calls and Users finances.
  • The Languages page is open to every signed-in account again - it lists your own languages. Only the default-language setting still needs the settings permission.
  • The Default device settings page now needs the device permission (which resellers, partners and accountants have) instead of the settings permission.
  • Recordings: a recording you hid in your portal can no longer be played or downloaded through its direct address. A recording removed by the cleanup still answers 410 gone, not 403.
  • IVR free-text fields now accept only a fixed list of Asterisk variables and reject anything else with a message that says what is allowed, instead of silently stripping it.
  • XML/REST interface: a partner account no longer receives every DID of every tenant and can no longer create or assign DIDs. NOTE: the interface always answers HTTP 200 - a script that only checks the status code will not notice the change.
  • XML/REST interface: an accountant account can now terminate, close, free and stop the subscription of a DID, and can use the location-rule methods.
  • XML/REST interface: admin accounts whose user id is not 0 can use the DID and location-rule methods at all - until now they silently found nothing.
  • The LCR list on the location-rule form now shows only the LCRs of your own tenant.
  • Music on hold, monitoring and server settings now require an operator-level account, not only the matching permission.
  • New automated release check: 21 places that hide passwords and keys are pinned, so a later change cannot remove one unnoticed.
  • An automated write-path check now also asks whether a write addressed by a row number ever loads that row.
  • The installer now switches off the Asterisk modules func_shell, func_curl and func_env. NOTE: this takes effect only after a full Asterisk restart.

v2.2.4

Released 2026-09-22

  • Three settings on the device form — "Send recording to email", "Recordings email" and "Keep recordings on disk after sending by email" — are saved but have no effect today, because sending recordings by email is not connected yet. The form now says so in plain words instead of looking like a working switch. Nothing is removed: the value you set is kept and will start working once email sending is in place.
  • "Hide all" and "Show all" recordings for a customer now work in blocks instead of one single statement. On the larger installation this was one instruction over 831,581 rows on the busiest table of the system, while calls were running. Each block is now a short step of its own, the run reports how many entries it really changed, and if it runs out of time it says so and the next click continues where it stopped.
  • Recordings that were automatically cleaned up are now left alone by "Hide all" and "Show all". Their audio file is gone; the entry stays in the list as a record, exactly as promised in the previous release, and is no longer rewritten.
  • It is recorded in the audit log who hid or showed recordings, and how many. Until now there was no trace at all: on one installation, tens of thousands of recordings were hidden from the customer, and nothing said whether a customer asked for that or whether staff simply made them invisible.
  • A recording that was automatically cleaned up can no longer be deleted by hand, neither one at a time nor as a selection. The previous release promised that such an entry stays in the list as proof; the delete button could take that promise back.
  • A recording whose audio file was empty — a 44-byte file header with no sound in it — no longer claims a file that is not there. New ones are marked at the moment the empty file is discarded. For the entries that already exist there is a separate run that we start by hand on each installation, in a quiet window, after asking you: it checks every file before it touches anything and leaves every entry whose file is really there.
  • The XML interface no longer hands out cleaned-up recordings. Its answer is capped at 5,000 entries, and entries without a file were taking places away from real recordings the longer the nightly clean-up had been running.
  • The recording permissions page now has page navigation. Until now it showed the first 100 customers and the rest were simply not reachable — on the page where the retention period is set, and that period deletes files.
  • The same page now shows, for each customer, how many of their recordings are hidden from them and how much disk space those take. There is deliberately no delete button next to it: for the existing entries it is not established who hid them, and for the larger part nobody did — the device setting "show recordings to the user" decided it when the call ended.
  • A new report, started by hand, counts recording files on disk that have no database entry at all, with their age and their size. It only counts. It deletes nothing and proposes nothing; what happens with those files is your decision, and this report is there so that the decision rests on a measured number.
  • Two new checks now run in every release build. One refuses any future version that writes to the large tables — calls, call attempts, recordings — without a provable limit. The other refuses a form field that is saved but read by nobody: exactly the kind of defect that made the retention period look like it worked for a year while nothing was ever deleted.
  • That second check immediately found three more fields of this kind that nobody had noticed: two announcement settings on the device form, and a minimum charge on the customer form. They are listed for you to decide on individually; nothing about them was changed in this release.

v2.2.3

Released 2026-09-22

  • Prices now take effect at the moment you set them. Until this release a price change became active two hours early: a rate set for "1 October, 00:00" already applied from 30 September, 22:00. The cause was the time zone of the database session, which could differ from one installation to another, and the price lookup silently followed it.
  • The same correction applies to the SMS price and to the provider (cost) price, not only to the customer price. Both are used to decide which rate wins, so both could pick a rate that was not valid yet.
  • Nothing changes retroactively. Across every existing call checked, not a single one falls into the affected two-hour window, so no invoice, no price and no balance moves because of this release. The defect would have shown itself at the next rate change, not in the existing data.
  • A new automated check now refuses any future version that compares a stored time against the clock without saying which time zone it means, so this class of error is caught before release instead of showing up only for a customer.
  • "Recalculate invoices" can no longer lose an invoice. It used to delete every unpaid invoice in the selected date range and then rebuild only the exact period you chose, so an invoice covering a shorter period inside that range was deleted and never rebuilt. Deleting and rebuilding now happen together, per customer, and only for the period that is really rebuilt. If one customer fails, that customer's old invoice stays untouched.
  • An invoice run no longer stops at the first problem. If one customer cannot be invoiced, the run continues for everyone else, and the result names the customer that was skipped. Before, a single failure left all remaining customers without an invoice and said nothing about it.
  • Invoices for the customers of a reseller no longer sit in the send queue for ever. They are still not sent, because they would carry the wrong brand, but they are now marked "not sent - reseller customer" in the invoice list and recorded in the action log, instead of being retried every hour with no effect.
  • If an invoice run is interrupted, the invoices it has already created are still sent. Previously the "send by e-mail" marker was written only after the whole run had finished, so an interruption left finished invoices in the database that nobody would ever send.
  • Scheduled actions that fall due at the same time now run in the order of their priority. The priority was saved but never read, so the order was left to chance - including the order of a tariff change and an invoice run on the same date.
  • Saving a scheduled task whose start date lies in the past no longer starts a real invoice run. The date is moved forward to the next valid time and the screen says that this happened. Until now, changing only the name of such a task could trigger a full invoice run with consecutive invoice numbers.
  • A long invoice run that exceeds the web timeout no longer reports a failure that did not happen. It now says that the run continues in the background and where to look for the result.
  • The search for the next invoice number is now a single database query instead of loading every customer and every invoice number into memory. The result is identical; it simply no longer grows with the number of invoices.

v2.2.2

Released 2026-09-20

  • Recordings retention per customer now actually works. The field 'keep recordings for' existed since the first release and was saved correctly, but nothing ever read it — setting it had no effect whatsoever. A nightly run after 23:00 local time now removes recordings older than the configured number of days, per customer.
  • Nothing is deleted until you choose a retention. Every account on every installation is set to 'unlimited' today, and both 0 and the unset value mean unlimited, so the first night after this update removes nothing anywhere. Deletion starts only when an administrator deliberately enters a number.
  • A cleaned-up recording stays in the list. It no longer disappears; the row remains and says 'Automatically deleted on <date>' instead of offering a player. Before this release the list filtered such rows out, so a customer searching for the recording would have found nothing at all and no explanation.
  • The retention field is now readable. Instead of a bare number box it offers 1, 3, 6 or 12 months, unlimited, or a custom number of days, and it states the unit. The customer list also shows how much disk space each customer's recordings occupy, so the decision is made with the number in view.
  • Changing a retention is now written to the audit log. As of this release that field deletes customer audio permanently, and until now it was the only destructive setting in the product with no record of who changed it.
  • Files are only reported as freed when they really were. The run measures each file before removing it and counts 'removed', 'was already gone' and 'failed' separately. A row whose file could not be removed is deliberately left unmarked so the next night tries again, instead of claiming the recording was cleaned up while it is still on disk.
  • New: the server clock is watched. Invoice periods and the retention cutoff are both derived from the local calendar day, but no installation had its timezone written down anywhere — it was inherited from a system file, while a second system file on three of four machines claimed UTC. The background service now compares its own clock against the billing timezone, in both daylight-saving states, and raises an alert if they ever disagree.
  • Housekeeping with teeth: fourteen stale copies of update and installer scripts (about 305 KB, nine of them executable, including three copies of apply-update.sh) had been shipping inside every release tarball. They are out of the tree, the packaging now excludes that whole class of file, and the gate that is supposed to enforce a single version of those scripts now detects such copies itself.
  • Corrected: the acceptance output claimed the release build ran a database probe. It never did — the only mention was inside a comment. The gate now ignores comment lines and states plainly that no probe runs during the build.
  • The billing timezone is now written down instead of inherited: both services run with it set explicitly, the background service checks its own clock against it twice a day and raises an alert if they ever disagree, and the installer sets it for new installations. Measured proof that this matters: with the timezone unset, the first of September resolves to midnight UTC instead of midnight local time, which moves every call between 22:00 and 24:00 on the last day of a month into the wrong month's invoice.

v2.2.1

Released 2026-09-20

  • Scheduled invoices: a monthly Generate_Invoice action now creates its follow-up run. Before this release it ran exactly once and then stopped silently, reporting success — no error, no log line.
  • Scheduled actions: leaving 'valid until' empty now means unlimited instead of ending immediately, and the field is no longer pre-filled with the current time. These two changes are what made the point above possible.
  • Scheduled invoices: the billing period is taken from the scheduled run time instead of the clock, so a repeated run after midnight or across a month boundary bills the same period as the first run instead of a different one.
  • Invoices: period start, period end and issue date now carry the calendar day that was chosen. Before, choosing September stored the invoice as starting on 31 August. The calls counted into the invoice are unchanged — only the dates printed on it were wrong.
  • Invoices: a second invoice for the same customer and period is now rejected by the database, so two simultaneous runs can no longer produce a duplicate.
  • Invoices: the header amount is now the sum of the rounded line items, so an invoice always adds up. Measured on a real month, the header read 9873.22 while the line items added up to 9873.23.
  • Invoice run: totals are summed in the database instead of loading one row per call into memory. Measured with 1.2 million calls: 2357 MB down to 1 MB and 12.0 s down to 0.3 s.
  • Invoice run: the background service no longer restarts during an invoice run. Its memory limit is 1500 MB and the previous code passed it at about 715,000 calls — the largest account already had more than that.
  • Scheduled actions: times are shown in local time instead of UTC. Opening a scheduled action and saving it without changes no longer moves it two hours later each time.
  • No existing invoice is affected: all four installations held zero invoices when this was built.
  • Database migration: one new unique index on invoices (user, period start, period end).

v2.2.0

Released 2026-09-19

  • Finances: the operator account (user 0) is no longer listed in its own customer finance list.
  • Finances: an admin account other than user 0 (for example voiplix_support) now sees the finance list instead of an empty page.
  • Live calls: the destination channel is recorded again, so the SIP tracing panel no longer shows an empty column.
  • No database migration in this release.