Skip to content

v1.2.0

Latest

Choose a tag to compare

@github-actions github-actions released this 04 Oct 17:47

This release adds Registry grouping and generated PO line numbers, unifies
numeric input and line totals, and improves maintenance, CSV round trips and
procurement evidence handling. It is the first release under the Semantic
Versioning policy described in versioning policy.

Five migrations run automatically on startup. Before upgrading, keep a full
backup of the database, documents and configuration. Review the
upgrade guide for historical PO
line reconciliation, maintenance price corrections, custom upload extension
lists and integration changes.

Added

  • The sidebar identifies unreleased builds as previews with their branch and
    commit. Release-tag builds, and builds without Git information such as Docker
    images, show the version number.

  • Documents can be .lic license files and .msg Outlook messages. Existing
    native installations using the previous default extension list gain them
    automatically on upgrade. Installations with a customized
    ALLOWED_UPLOAD_EXTENSIONS value need to add .lic,.msg to it.

  • My Settings → Appearance has a per-user option to show or hide the Portfolio
    overview in the sidebar (shown by default).

  • Help and the user guide explain how to track SSL/TLS certificates, domain
    names and other renewable items with the Other type, Type Description and
    Renewable?.

  • Hovering or focusing the Expiring or Expired stage on the Licenses page shows
    a breakdown, for example "12 expiring · 5 renewal in progress · 1 retiring ·
    6 not started". A license with a renewal in progress that is also scheduled
    for retirement counts as renewal in progress. The stats API gained
    expiring_breakdown and expired_breakdown.

  • A small ⓘ next to License Type, in every form that has one, explains the
    difference between Maintenance and Service. Tooltips open on hover and on
    keyboard focus.

  • PO line numbers: every license and pending-order line with a PO number gets
    a generated, read-only PO line number, unique per PO (PO numbers are
    compared ignoring case and spacing) and never reused. The number appears in
    the API (poLineNumber), as a new last PO Line column in the license CSV
    export, and in the pending-order export. In the app it is shown as
    PO # · LINE n in License Details, as a Line column on pending orders and in
    the conversion screens, and as an optional PO Line column in the Registry
    (hidden by default, sortable and filterable). CSV imports of new records keep the file's line
    numbers when they are free; the preview shows any number that has to
    change. Existing records are numbered once during the upgrade, in creation
    order per PO; these historical numbers may not match POs issued before
    LicenseTrack, so reconcile them before relying on PO number + line for
    matching with other systems.

  • Before a new version changes the database schema, LicenseTrack saves a copy of
    the database in pre-upgrade/ next to the database file (newest three kept).
    Restarts after a failed upgrade reuse the first copy instead of replacing it.

  • Group the Registry by a column, with an optional second level (for example
    PO # then Publisher). Drag a column header onto the grouping strip or pick
    one from the list. Groups start collapsed and show their line count, line
    total per currency and earliest end date; purchase-order groups also show the
    Total PO Value and flag a manual PO total that differs from its lines. Saved
    views keep the grouping, and CSV export stays flat in grouped order.

Changed

  • A separately tracked maintenance line added next to a license is now
    pre-filled with "product maintenance" instead of "product
    maintenance/support". Existing records keep their description.

  • Forms show fewer permanent hint lines: background explanations (for example
    Supplier Contact, the manual PO total and several settings) moved into ⓘ
    tooltips that open on hover or keyboard focus. Hints that prevent a mistake
    stay visible.

  • The app uses Maintenance consistently where it said "Support" or
    "Maintenance / Support" (screens, alerts, emails, error messages, Help). For
    example, "Support due" is now "Maintenance due" and "Start support renewal"
    is now "Start maintenance renewal". Standalone support contracts, such as
    premium or third-party support, are recorded as a Service. API fields and
    routes, alert type keys and CSV headers are unchanged; older CSV headers are
    still accepted on import.

  • Help no longer lists the session timeout under My Settings: the session
    timeout and minimum password length are server-wide settings.

  • Opening a document preview in the Sourcing and Pending Orders document dialogs
    collapses the document list and shows a much larger preview; the Add License
    document list also collapses while a preview is open. The contract dialog
    opens with Linked licenses collapsed (with a count) and its document folders
    expanded.

  • Internal: updated brace-expansion (a dependency of the lint tooling) to
    5.0.12 to clear a published advisory. It is not part of the app bundle.

  • Added end-to-end tests that run the real frontend against a real backend for
    the core write paths.

  • The pending-order export's PO Line # column now contains the generated PO
    line number instead of the row's position.

  • Pull requests now include a single-owner audit: every rule a change touches
    names its one owner in code, and literal duplicates are caught by guard tests.

  • Added a maintainer invariants document listing the rules LicenseTrack
    guarantees on every entry point, and a pull request template. The architecture
    map identifies the shared calculation, linking, grouping and upload owners.
    Shared test cases guard currency-separated totals in reports, Registry groups
    and overview totals, including manual PO totals.

  • Internal: CSV import and export read their field list from one registry (no
    behaviour change). License updates, field patches and import updates share
    the notice-date reminder reset rule. Request schemas share the canonical money
    validation helper while preserving their field lists, validation timing and
    error messages. CSV import also uses the shared included-maintenance type set.
    Renewal actions refresh license statistics once through the shared
    invalidation group. Conversion defaults reuse the shared custom-field value
    map. Removed an unused session-cookie helper and the unused APScheduler
    runtime dependency.

  • The demo mirrors canonical-number validation and notice handling, including
    clearing handling state when the notice date changes.

  • Budget owners now receive Maintenance Ending and Maintenance Expired alerts
    for the included maintenance on their perpetual, OEM and freeware licenses,
    alongside license expiry alerts. These rows are marked "Maintenance" and show
    the maintenance dates.

  • Updated the frontend test tooling (Vitest 5, jsdom 30.1) and removed automatic
    test retries. Form workflow tests use atomic input changes and wait for
    asynchronous submission; report workflow tests load their sections before
    testing interactions.

  • API requests with fields an endpoint doesn't define are logged as a warning,
    naming the endpoint and the fields. Set STRICT_REQUEST_FIELDS=true to reject
    them with a 422 instead; this may become the default in a later release, so
    integrations should send only documented fields.

  • Line Total is always quantity × unit price. The separate Line Total input is
    gone from license, invoice and conversion forms, which show the calculated
    value instead, and the Registry has one Line Total column (formerly
    Calc. Total). For an invoice line that doesn't divide evenly, enter a precise
    or net unit price; for a negotiated PO total, use the manual PO total. In CSV
    imports a line total fills a missing unit price or is checked against it; a
    Total PO Price column is no longer imported.

  • The Registry's Total PO Value shows a lock icon when it comes from a manual PO
    total.

Deprecated

  • The totalPoPrice license API field. It is still accepted and returned but no
    longer used; it will be removed in 1.3.0.

Fixed

  • CSV import warns when a nonblank external reference matches an existing
    active license or an earlier row in the file, including records without PO,
    contract or dates. Confirm the warning to deliberately reuse a reference.

  • Converting merged co-term renewal lines requires an explicit cost-centre
    choice when their predecessor licenses had different cost centres, matching
    the budget-owner rule. The API enforces the same choice.

  • CSV imports require warning acknowledgement when a new row's currency is
    blank or missing. The preview identifies the affected rows and the currency
    used. Update rows without a currency keep the record's existing currency.

  • The Registry's column titles stay on top while the table scrolls. Only the
    select-all box stayed; the titles scrolled away with the rows.

  • A price cleared on a renewal line stayed cleared only until conversion: Convert
    to License refilled the previous term's unit price, maintenance unit price or
    maintenance cost. Prices now come from the renewal line only; starting a
    renewal still copies the previous price there as a reference.

  • Document file pickers offer exactly the file types the server accepts. They
    used their own lists: license and procurement pickers left out Excel, Word
    and CSV files, and the contract picker offered .doc, which the server
    refused.

  • Linking terms within one request follows one rule in both Set predecessors
    and Set next term: a line can't roll into an earlier-starting term, a link
    that would close a loop isn't offered, and lines that can't be linked are
    shown with the reason instead of being hidden or failing on save.

  • The Documents section opens expanded in every add, edit and conversion
    dialog. It started collapsed in Add License, Convert All and the single
    purchase-order conversion.

  • Convert All kept the PO line's estimated total as the license Line Total even
    when real unit prices were entered at conversion.

  • Subscriptions and SaaS with included maintenance could take their maintenance
    cost from an outdated stored total instead of quantity × unit price.

  • The Add Maintenance dialog stored the coverage cost as the unit price, so
    totals and reports multiplied it by the covered quantity. New records are
    correct, and existing records created this way are corrected on upgrade.

  • Unit prices are shown with every stored decimal (at least two), so 0.1234 no
    longer displays as 0.12; totals keep two decimals. The localized CSV export
    keeps unit price decimals too.

  • Reading or scrolling inside a focused document preview now counts as activity,
    so a long read no longer ends the session.

  • Database restores run in the background of the server process, so the app
    and /api/health keep responding (with status maintenance) during a long
    restore. Pre-restore safety copies are now kept in a pre-restore folder
    next to the database (newest three), and copies left next to the database by
    older versions are moved there on the next restore.

  • Application log messages (such as warnings about unknown request fields) are
    no longer silenced after the database upgrade that runs at startup, and keep
    following the LOG_LEVEL setting.

  • Maintenance linking:

    • A license can be changed into Maintenance from the edit form by choosing
      the license it covers in the same step.
    • Choosing "Separately tracked" coverage, in the edit form or with Edit
      coverage, offers a quick link to an existing maintenance record.
    • Maintenance records that already cover another license stay visible in
      link searches, marked "Currently covers", and ask before covering one more.
    • The Renewal Workbench's "Record existing support" now lists existing
      records to link.
    • All maintenance link dialogs search the same fields (including PO number,
      contract, dates and the covered license), and show how many retired
      records are hidden with an option to show and select them in Link existing,
      Edit coverage and the full edit form.
  • CSV export → import now preserves manual PO totals,
    maintenance pricing (per-unit and free), and which licenses a maintenance
    record covers (several allowed, separated by ";"). An exported lifecycle
    status is honoured: Legacy stays Legacy, and an active record that expired
    recently is no longer turned into Legacy. Update imports can correct an
    included maintenance period. The API export gained request and purchase
    dates, portal URL, maintenance fields and manual PO total, and its Line Total
    column is quantity × unit price.

  • One "same PO" rule: shared documents now match licenses whose PO numbers
    differ only in case or spacing (listing, downloads, counts and completeness).
    Email Supplier's "all matching licenses" includes only lines of the same
    purchase and supplier. Document scope labels and delete warnings describe
    the actual scope.

  • Maintenance coverage has one owner: a license's active maintenance record is
    always worked out from its linked records by date, on every path (linking,
    CSV import, renewals, the daily hand-over). Linking an older or future record
    no longer replaces coverage that is still running; an overlapping new term
    takes over when the current one ends. Undoing a link to a renewal that hasn't
    started yet now works. Disabling maintenance also removes planned terms.
    Changing between perpetual, OEM and freeware keeps included maintenance, and
    changing to another type keeps the old included period in history.

  • "Renewal in progress" means the same for licenses and maintenance: maintenance
    alerts mention it, licenses scheduled for retirement no longer appear in the
    maintenance renewal list, and a license with a renewal in progress can't be
    retired until the renewal is cancelled. Legacy licenses can't start a
    renewal, and a renewed status can't be cleared through a normal edit.
    Co-term merges require one license type and keep every covered license
    linked to the new maintenance term.

  • Numbers with three decimals are no longer multiplied by 1,000 under
    comma-decimal number formats (e.g. nl-BE, de-DE). This affected Registry
    inline edits, new pending-order lines, and conversion defaults. Stored
    values are never re-interpreted, and price inputs keep every decimal
    instead of rounding to two. Merging sourcing lines under these formats no
    longer turns a combined quantity such as 1500 into 1.5.

  • Typed amounts with thousands separators are read correctly, for example
    2,443.00 under the 1,234.50 number format (#82). Input that doesn't match
    your number format is refused with a message next to the field instead of
    being changed or cleared: under 1.234,50, 2,443.00 is refused rather than
    saved as 2.443. Every screen that takes a price, quantity, total or cost now
    uses one number input with one set of rules, shared with the server, and the
    API rejects numbers that aren't plain decimals (such as 1,5).

  • Under comma-decimal number formats, a number with a single dot and exactly
    three digits after it (e.g. 1.234) is refused as ambiguous, in number
    filters and CSV import too; type 1234 for a whole number or 1,234 for a
    decimal.

  • Export Current View (localized) writes numbers with the same separators
    the importer reads, keeping every quantity decimal, so the file imports back
    with the same number format. Before, a quantity of 1000 under 1.234,50 was
    written as 1.000, and Swiss formats used a typographic apostrophe.

  • CSV import reads an Item column as the PO line number. Purchasing exports
    (Flexera among them) use Item for the line and Description for the
    product. Earlier versions read Item as the software description; a file
    that uses Item for the product text needs that column mapped to Software
    Description (or renamed to Description) before import.

  • The database models and migrations now describe the same schema, including
    the unique OIDC identity index. A test fails the build if they drift apart
    again. Document categories fit their column on every database.

  • An active user is no longer logged out when their computer's clock runs
    behind the server's: session responses now include the seconds remaining,
    and the browser measures them on its own clock.

  • Procurement conversion:

    • Sourcing lines can no longer be added to a pending order that was
      converted or cancelled in the meantime.
    • Conversion can no longer change a line's currency while the order has a
      manual PO total; clear the total first.
    • A SaaS portal URL saved on a sourcing or PO line is kept at conversion.
    • An invoice uploaded with a conversion is stored together with the new
      licenses: if it can't be stored, nothing is converted and you can retry.
    • Older conversions whose invoice was lost now say to upload the invoice on
      the pending order and retry, instead of retrying automatically.
    • Evidence transfers can no longer run twice at the same time.

Security

  • Hardened request validation for signed-in browser sessions, including
    sign-out, outbound URL checks for webhooks and SSO discovery, and API tokens
    of accounts that must
    change their password. Scripts that write through a browser session cookie
    (rather than an API token) must now send the X-LicenseTrack-Request: 1
    header, including when signing out; API-token and bearer requests are
    unaffected.
  • SSO sign-in rate limiting now counts only failed sign-ins and bounds
    in-memory attempt tracking. Successful sign-ins release their tracking
    entries. The deployment guide documents FORWARDED_ALLOW_IPS for
    reverse-proxy setups, and Docker
    Compose passes it through.