Repository navigation
Asset Type Profiles Design
Status: agreed - Part A built (see Asset type layouts and its developer guide); parts B, C and D to follow. This page sets out what I am building for issue #200, and why. It was written before any code so the approach could be checked first, and @Dr4inder reviewed it on the issue on 22 October 2026. Their clarifications are folded in below and summarised in Where we landed. The decisions are in section 8.
The request, from issue #200 (raised by @Dr4inder):
"The asset detail view remains strongly oriented towards computers. Other asset types can display fields and tabs that are irrelevant to their purpose. For example, a monitor does not normally need Windows-specific information or a Device Manager tab."
FreeITSM already lets you decide which custom fields each asset type records - a monitor can have Screen size and Resolution, a printer can have Toner model. What it does not let you decide is which of the built-in details and tabs a type shows. Every asset, whatever its type, gets CPU, memory, operating system, build number and BIOS version on its Key info tab, and a Devices and a Software tab beside it. On a monitor those are always empty, and an empty box cannot tell you whether the information does not apply, was never collected, or was collected and really is empty.
The request has four parts. In order of priority:
- Asset type profiles - per type, choose which built-in sections and which tabs are shown. A monitor gets a focused page; a computer looks exactly as it does today.
- Inventory freshness - for each inventory section (software, disks, network adapters, devices), say which tool supplied it, when it was observed, and whether it is current, stale, empty or never collected.
- Connected assets - a monitor connected to a computer, visible from both ends, with where the connection was seen and its history.
- Reconciliation you can review - ambiguous matches and protected manual values shown to a person, rather than handled silently.
Each part is useful on its own and can ship in its own release.
After review on the issue, the direction is agreed: section switches rather than a field designer, tab ordering, editable presets, profiles as presentation only, and the order A, B, C, D, with Part A the priority and not held up by the others. Five clarifications changed the design, and each is reflected in the section it touches:
| # | Clarification | What changed |
|---|---|---|
| 1 | Hidden is not "not applicable". A team may hide Software on computers to keep the page simple and still collect and use that inventory | A hidden section or tab is described as hidden by this profile, never as not applicable, and the profile is never used to decide what an asset has. Collection and freshness stay available when hidden details are shown (section 3, section 4) |
| 2 | No second serial number. A required custom Serial number field would duplicate the built-in one that imports and reconciliation use, and the two could disagree | The custom-field workaround is withdrawn. Required built-in fields are deferred; any later completeness check refers to the built-in field and never refuses an inventory report (decision 2). The service tag moves into Identity, so it can never be hidden |
| 3 | Freshness needs an outcome per source and section. A successful empty result, a skipped section and a failed attempt are three different things | Each source and section stores its last outcome - succeeded, empty, skipped or failed - with the last error and when it was tried, beside the last good data and its original observation time. The agent reports every section explicitly, because one that skips empty sections can never establish "reported empty" (section 4) |
| 4 | Connections keep source boundaries | A REST source may refer to an asset that is already resolved, by its id, subject to company and access checks. A missing or incomplete observation never disconnects anything, and no source replaces another source's observations or a person's confirmation (section 5) |
| 5 | Merges keep everything | A reviewed merge keeps linked records and each source's identity, as well as both histories (section 6) |
Where reasonable people would choose differently, the choice is a setting in Assets β Settings, with today's behaviour (or the agreed default) as the starting point: how an asset says it has hidden details (Part A), and the staleness window (Part B).
This was the first question I asked of the request, because the risk with a feature like this is real: a "profile" that grows its own field designer, its own required-field rules and its own layout engine would be a second custom-fields system bolted beside the first, and the two would disagree. That is the outcome to avoid.
It does not have to go that way, because every part of the request lands on something that already exists:
| The request | What it extends | Why it fits |
|---|---|---|
| Fields per type |
Custom fields are already per type - a field goes in a set, a set goes on a type (asset_type_field_sets) |
Profiles add the built-in half to the same per-type settings. Custom fields do not change at all |
| Tabs per type | The asset page's fixed tab strip | A list of tab switches per type, stored the same shape as the type's field sets |
| Inventory freshness |
asset_inventory_sections already stores observed_at and imported_at per source and section (#194, 3.12.0). The "Inventory sources" panel was an agreed follow-up from #194 |
The data is already being recorded for REST sources; this shows it, and teaches the agent to record it too |
| "Hidden by this profile" | Nothing today | Comes from part 1 - and is only ever a display state. A hidden tab is not a claim that the asset has no such data (see Where we landed, point 1) |
| Connected assets | Nothing that fits (see section 5) | A new, small table - deliberately separate from custody and from the CMDB |
| Reconciliation |
The resolver already refuses to guess - resolveAssetIdentity() will not pick between two assets sharing a serial, and will not let a reused hostname write a new serial onto an old laptop (developer guide) |
The judgement already exists; what is missing is a list a person can review |
So the rule for the whole design is: profiles decide what is shown, never what is stored, never what is required, and never who may write. Fields stay in one system (custom fields), required stays where it is (on a field's place in a set), permissions stay in roles, and inventory keeps writing whatever it reports. A profile is presentation only.
Mapped from the code at 3.13.0, not from memory:
| The request needs | Today | Verdict |
|---|---|---|
| Custom fields chosen per type, reusable across types | Fields, sets, sets on types, sets on single assets; required per placement; values kept when a set is removed (Custom asset fields) | β Have it |
| Hide built-in fields per type | Key info always shows Manufacturer, Model, Service tag, Name, CPU, CPU speed, Memory, Operating system, Feature release, Build number, BIOS version, First seen and Last seen | β Fixed for every type |
| Choose and order tabs per type | Key info, Financial, Devices, Software, Tickets, Contracts, (Projects), Documents - the same strip on every asset | β Fixed for every type |
| Add dialog without computer fields | The Add dialog already leaves out the hardware details the agent reports, and shows the chosen type's custom fields | β Have it |
| Required built-in fields | None are required except the name | |
| Inventory source per row | Software and disk rows show their source; network adapters and physical disks do not | |
| Observed and imported time per section | Stored in asset_inventory_sections - for REST sources only. The agent writes none, so for most installs the table is empty |
|
| Whole-asset freshness | First seen, Last seen, "Never reported", amber after 7 days | β Have it, per asset not per section |
| A failed section recorded | The REST import answers failed for a section in its response; nothing is kept |
β Not stored |
| "Devices: 0" vs "never collected" | The tab count is 0 either way | β Indistinguishable |
| Connected assets | A custom field of type Link to something else can point at another asset - one way, read-only on the page, no history. The CMDB's "connects to" relationship links configuration items, not assets | β Nothing fits |
| No merging on weak identifiers | Serial first; a hostname match only if it cannot contradict the serial; two assets sharing a serial are never guessed between | β Have it |
| Ambiguous matches visible |
resolveAssetIdentity() returns ambiguous, but no caller shows it to anyone |
β Flagged, never surfaced |
| Protected manual values | A hand-edited Manufacturer or Model on a reporting machine is overwritten by the next sync; the page warns when you edit it (#1143) | β None |
| Normalised manufacturer names | None | β None |
Assets β Settings β Asset types, open a type, and a new Layout section beside its name and icon:
- Sections shown on Key info - a tick per built-in section, in a fixed order:
| Section | Built-in fields in it |
|---|---|
| Identity | Name, Asset tag, Service tag (the serial number), Type, Status, Location, Company (always shown - see below) |
| Make and model | Manufacturer, Model |
| Hardware | CPU, CPU speed, Memory |
| Operating system | Operating system, Feature release, Build number, BIOS version |
| Reporting | First seen, Last seen (and Never reported) |
| Storage | Logical drives and physical drives |
- Tabs - a tick per tab (Financial, Devices, Software, Tickets, Contracts, Projects, Documents, and Connected once part C exists) and drag to reorder. Key info is always first and always shown.
Custom field sets carry on exactly as now, attached under Settings β Custom fields. Nothing about them changes. The Layout section links there ("This type also records 2 sets of custom fields") so the whole picture of a type is one click away.
A new type, and every existing type, starts with everything ticked, so no install looks any different until someone changes a type (acceptance criterion 9). A Start from menu fills the ticks from a sensible preset - Everything (today's page), Peripheral, Network equipment, Mobile device - which is a shortcut for ticking boxes, not a hard-coded restriction: the result is just ticks, and you can change any of them.
| Preset | Key info sections | Tabs hidden |
|---|---|---|
| Everything | all | none |
| Peripheral (monitor, dock, headset, keyboard) | Make and model | Devices, Software |
| Network equipment (switch, router, firewall, access point) | Make and model, Operating system, Reporting | Devices, Software |
| Mobile device (phone, tablet) | Make and model, Operating system, Reporting, Storage | Devices |
The request asks to "arrange fields into meaningful sections and control their order". I am proposing fixed sections you can switch on and off, not a designer where any built-in field can be dragged anywhere, for three reasons:
- It is the Frankenstein line. A designer that moves built-in fields around, mixes them with custom fields and renames sections is a second field system. Custom fields already have sets for grouping and ordering - that is the place to arrange things.
- The built-in fields come in natural groups. Nobody wants CPU without memory, or the operating system without its build number. Switching the group answers the monitor case completely.
- Every surface that shows a built-in field would have to learn the layout. The asset page on the desktop and on a phone today, and anything that prints an asset later. Section switches are one check each; a free layout is a renderer each.
If a single built-in field genuinely needs hiding on its own later, a per-field switch inside a section can be added without redoing this.
- Presentation only. Hiding a section or tab never deletes, blocks or ignores anything. The agent, Intune and REST imports write exactly what they write today, and the REST API returns every field whatever the profile says. Acceptance criteria 4 and 8, and the request's own "must not silently stop authorised inventory imports".
- Identity is never hidden. Name, asset tag, service tag, type, status, location and company are how an asset is found, scanned, matched and reported on. The service tag is the serial number that imports and reconciliation match on, so it lives here rather than under Make and model.
- "Hidden by this profile", never "not applicable". A profile is a display choice and says nothing about what the asset has. A team can hide Software on its computers to keep the page simple and still collect and use that inventory.
- Hidden data is never invisible data. If an asset holds values in a section or tab its type hides - a computer given the wrong type, a monitor somebody typed a model into under Hardware, or Software hidden on computers that still report it - Key info shows one quiet line naming what is hidden, "Hidden by this type's layout: Software (214) - Show them". Show them puts every hidden section and tab back for that asset, each marked hidden by this profile, so nobody mistakes a revealed tab for part of the normal layout.
- A setting for how loud that is. Assets β Settings β Asset types, When an asset has details its type hides: Say so on the asset (the default, the line above) or Only offer a Show hidden link (a small link at the end of the tab strip, for teams who chose their layouts deliberately and find the line noisy). Either way the way back is always on the page.
- The table view is not affected. It lists every type at once, and its columns are each person's own choice. A profile decides what one asset's page shows, not what the estate table offers.
- Changing an asset's type changes which sections and tabs it shows, and nothing else. The values stay (criterion 4). This also settles one of the open questions on the custom fields developer guide for built-in values.
- Companies. A profile belongs to the type, so a global type has one layout for every company, and a company that wants a different layout makes its own type - which is how types already work for multi-company installs.
- Permissions. Editing a type's layout uses the existing asset types right. Nothing new.
One small table, the same shape as asset_type_field_sets:
asset_type_layout
asset_type_id INT -> asset_types.id, cascade
item_kind 'section' | 'tab'
item_key 'hardware', 'devices', ... (a fixed list in code)
is_shown TINYINT
sort_order INT
UNIQUE (asset_type_id, item_kind, item_key)
No row means shown, so existing installs need no migration and a tab added in a later release appears on every type until someone hides it.
The asset page, on the desktop and on a phone (one page, asset-management/index.php). Search, the table, exports, handover columns, the REST API and the dashboard are deliberately not affected (they are estate-wide or machine-facing). A built-in field added to the page later goes into one of the sections, so it is covered by the same switch.
The Devices, Software and Key info Storage areas each get a one-line status above their list, and Key info gets an Inventory sources panel listing each source that reports this asset:
The states are worked out per source, from what each source last did, and never from the type's profile:
| State | Shown as | When |
|---|---|---|
| Never collected | "No device information has been reported for this asset" | No source has ever sent this section |
| Collected, empty | "Reported empty by the agent, 3 hours ago" | A source's last attempt succeeded with no entries |
| Skipped | "Not included in the agent's last report (3 hours ago)" - the earlier data stays, with its own age | A source's last report left the section out |
| Current | "From the agent, observed 3 hours ago" | Observed within the staleness window |
| Stale | The same, in amber | Older than the window |
| Failed | "The last import of this section failed: ..." in red, beside the last good data and its original observation time | The last attempt for this section failed |
Several sources can report the same section, and each keeps its own row, so one source succeeding never hides another failing: the panel lists each source's state.
If the type's profile hides the tab, none of this is lost: Show them (part A) brings the tab back with its status line, and the Inventory sources panel on Key info always lists every source and section whatever the profile hides.
This is what makes "Devices: 0" honest: the badge shows a dash for never collected and 0 only for a real empty report.
The staleness window starts at 7 days, the same as Last seen and Watchtower, and is a setting in Assets β Settings for teams whose sources report less often.
-
The agent records its sections in
asset_inventory_sections, as REST sources already do. This is the "one implementation, for now two" follow-up from #194. The agent observes what it reports at the moment it reports it, so its observed and imported times are the same - which is correct. - The agent reports every section explicitly. Today it leaves out a section that has nothing in it, which makes "reported empty" and "not reported" look the same. It will send an empty section as an empty list, and leave a section out only when it did not collect it - so empty and skipped can be told apart.
-
Each attempt's outcome is stored:
last_outcome(succeeded,empty,skipped,failed),last_errorandlast_attempt_atonasset_inventory_sections.observed_atand the fingerprint keep describing the last good data, so a failure or a skip never makes old data look new and never throws it away. -
Importing an old observation never makes data look new: the panel shows
observed_at, never the import time, as the age. This is already how #194's import stores it. - A failed, skipped or partial scan is never treated as "everything was removed". Only a section that succeeded replaces that source's rows; a failed or skipped one leaves them as they were.
- A Link to something else custom field is a property: one asset pointing at one other, set by hand, no history, one direction. It is the right tool for "replaced by" or "spare for". A monitor that moves between desks and is reported by a scanner needs history, a source and both directions - turning a field into that would bend it out of shape.
- The CMDB's relationships are between configuration items and carry impact ("if this fails, that is affected"). The request is explicit that "an observed peripheral connection should not automatically imply a service outage relationship", and assets are not CMDB items.
So connections get their own small table, and each of the three ideas keeps one meaning: a link field is a fact about an asset, a CMDB relationship is a service dependency, a connection is a physical attachment.
A Connected tab (switchable per type in part A) on both assets: "Connected to DESKTOP-0142 - reported by the agent, last seen 2 hours ago" on the monitor, and the monitor listed on the computer. Each row says whether it was confirmed by a person or observed by a source, and "last observed connected to" is worded as exactly that, never as a current assignment. Connect and Disconnect buttons for manual connections, and a history of every connection and disconnection.
asset_connections
asset_id the computer (or switch, or dock)
connected_asset_id the monitor (or phone, or printer)
source 'manual' | 'agent' | 'rest:<name>'
first_observed_at, last_observed_at
connected_at, disconnected_at (NULL = still connected)
confirmed_by_id the analyst, for a manual connection
Each row belongs to one source: the same monitor seen by the agent and confirmed by a person is two rows, and each source only ever updates its own.
Connections and disconnections also write to each asset's existing history.
How a source names the other asset. A REST source can refer to an asset that is already resolved - by its FreeITSM id - so an integration that has matched a monitor once does not have to rematch it by serial every time. The id is checked exactly like any other write: the asset must exist, be in a company the source's key may write to, and be one the caller may reach. Otherwise the source names it by serial (a monitor's EDID serial), matched with the same resolver and the same refusal to guess - an unmatched or ambiguous peripheral is listed for review (part D), never created silently.
What never disconnects anything:
- A missing or incomplete observation. A report that does not mention a connection leaves it as it was; only a report that explicitly says the peripheral is gone, from the source that saw it, closes that source's row. Old rows simply age, and show last observed with their date.
- Another source. No source closes or rewrites another source's row.
- A source, against a person. A manual confirmation is only changed by a person; a source disagreeing with it is shown beside it, not over it.
Custody (who holds an asset, handover) is untouched: a monitor can be connected to a computer and signed out to a person, and the two never update each other.
The matching rules stay exactly as they are - they already refuse to merge on a hostname alone and refuse to guess between twins. What is added is visibility:
-
A Review list (Assets β Settings β Review, or a Watchtower card) of the cases the resolver already detects and nobody currently sees: two assets sharing a serial, a reused hostname (
hostname_reused, today a history line only), an ambiguous match, and an unmatched peripheral from part C. Each one can be resolved explicitly - these are the same asset (merge), these are different, or ignore. A merge is only ever made by a person, and keeps everything both records had: both histories, every linked record (tickets, contracts, documents, projects, custody, connections, custom field values), and each inventory source's identity for the asset, so every source still recognises the merged asset on its next report. The merge itself is recorded in the history of the asset that remains. - Protected values. A padlock beside Manufacturer, Model and the other built-in fields a source writes. A protected value is never overwritten by an import; the import's value is kept beside it and shown as a conflict ("The agent reports HP; you set Hewlett-Packard"), with Release to let the source win again. This replaces today's warning when you edit a reporting machine's Model.
- Manufacturer and model names - a small mapping list (HP Inc., Hewlett-Packard β HP), applied when values are shown and filtered, with the reported value kept as it came.
This is the largest and least urgent part, which is why it is last. Imports keep updating only their own information throughout.
| # | Criterion | Where |
|---|---|---|
| 1 | Standard fields, sections and tab order per type, in the existing settings | Part A - sections and tabs; field arrangement stays with custom field sets (section 3) |
| 2 | A monitor with a focused view | Part A |
| 3 | Custom fields and sets reusable | Unchanged |
| 4 | Profile or type changes keep values and history | Part A rules - presentation only |
| 5 | Connected assets from both ends, with source and history | Part C |
| 6 | Missing, empty, stale and failed distinguishable | Part B |
| 7 | Conflicts and protected values reviewable | Part D |
| 8 | Validation, company boundaries, permissions | Existing rights; profiles never touch writes |
| 9 | Existing installs unchanged until configured | No row means shown; nothing ticked off by default |
All agreed on the issue on 22 October 2026.
| # | Decision | Agreed |
|---|---|---|
| 1 | Field-level layout: fixed sections switched on and off, or a designer for individual built-in fields | Sections, for the reasons in section 3. A per-field switch inside a section can follow if anyone needs it |
| 2 | Required built-in fields per type (the request asks for these "where appropriate") | Deferred. Required belongs with validation, not presentation, and a built-in field is written by four routes (the page, the import, REST and the agent); an agent report must never be refused. A required custom Serial number field is not the workaround - it would duplicate the built-in serial that imports and reconciliation use. Any later completeness check refers to the built-in field itself and flags rather than refuses |
| 3 | Presets: shipped profiles, or blank | Shipped Start from presets that only fill the ticks, so nothing is hard-coded and existing types stay fully ticked |
| 4 | Staleness window for part B | 7 days by default, the same as Last seen and Watchtower, as a setting in Assets β Settings |
| 5 | Where agent-reported monitors come from for part C | REST sources first (a scanner can already report them as a section). Teaching the PowerShell agent to read monitor EDIDs is a separate agent change |
| 6 | Merging two assets in part D | Yes, but only by a person from the Review list, keeping both histories, linked records and source identities, and recording the merge. Never automatic |
| 7 | How an asset says it has hidden details (part A) | A setting: say so on the asset (default), or only offer a Show hidden link |
- Part A - profiles. Built - Asset type layouts. The highest priority in the request and the smallest real change: one table, one settings section, and the asset pages checking it. Ships in its own minor release.
- Part B - freshness. The agent reports every section explicitly, each attempt's outcome is stored, and the panel and per-tab status are added. Independent of part A's switches - a hidden tab keeps its status for when it is shown.
- Part C - connected assets. A new table, a tab, manual connections first, source-reported ones after.
- Part D - review and protected values. Builds on the resolver and on part C's unmatched peripherals.
As the request says, hardware-component inventory (individual RAM sticks, CPUs as records). Also: no duplicate asset records, no parallel asset system - every part above adds to the one asset record and the one settings screen.
- Assets Β· Recording anything - custom asset fields Β· Custom asset fields - Developer Guide
- Asset reconciliation - Developer Guide - the resolver part D builds on
-
REST API: custom asset fields, inventory import and change evidence - design (#194) - where
asset_inventory_sectionscame from - Who holds what, and handover documents - custody, kept separate from connections
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
-
Architecture
- β³ π§Ή Root folder tidy (URL routing)
- β³ π Database Integrity (FKs & constraints)
- β³ π οΈ Database Verification β Developer Guide
- β³ π§© Service Layer (UI + API share code)
- β³ πͺ€ Code traps (the TRAP: comments)
- β³ π Commenting for the Engineering wiki
- β³ π οΈ Engineering wiki scanner - Developer Guide
- β³ π Service-Layer progress
- π€ Contributing (read before a pull request)
- π§ͺ Developer tests
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- π Date & Time Formats
- π± Currencies
- π§ The sidebar (optional module rail)
- π§© Preference templates
- π Display order (modules, Watchtower cards) β Developer Guide
- Theming & Dark Mode
- ποΈ Recent β getting back to what you were doing
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
-
MobileβFriendly
- β³ π« Mobile: Tickets
- β³ π» Mobile: Assets
- β³ π Mobile: Calendar
- β³ π Mobile: Knowledge
- β³ π¦ Mobile: Service Status
- β³ πΌ Mobile: Watchtower
- β³ π§© Mobile: Problem Management
- β³ π Mobile: Change Management
- β³ πΏ Mobile: Software
- β³ β Mobile: Tasks
- β³ π Mobile: Forms
- β³ π Mobile: Contracts
- β³ π Mobile: Domains
- β³ π Mobile: People
- β³ π Mobile: Projects
- β³ ποΈ Mobile: Files
- β³ π Mobile: LMS
- β³ πΊοΈ Mobile: CMDB
- β³ πΊοΈ Mobile: Network Mapper
- β³ π§ Mobile: Process Mapper
- β³ βοΈ Mobile: Workflow
- β³ π₯οΈ Mobile: System
- β³ π Mobile: Reporting
- β³ π Mobile: System Wiki
- β³ π Mobile: Self-Service Portal
- β³ π§° Mobile: Techniques & Tricks
-
Security
- Layer 1 β which modules you can enter
- β³ π§© Module Access Control
- β³ π οΈ Module Access β Developer Guide
- Layer 2 β what you can administer
- β³ π Roles & Permissions
- β³ π οΈ Roles β Developer Guide
- β³ π€ Why capabilities are constants
- Layer 3 β the System module
- β³ π Admin Access Control
- Hardening
- β³ π Security review response 2026-08
- β³ π‘οΈ Security hardening 2026-08
- β³ π οΈ Security hardening 2026-08 β Developer Guide
- β³ π‘οΈ Round three β plain English
- β³ π οΈ Round three β Developer Guide
- β³ π‘οΈ CSRF protection (S4) β Developer Guide
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
- π CardDAV contact sync
- Browser Extension
- API Reference
-
π REST API β how it works
- β³ π Proposal: custom fields, inventory import and change evidence (#194)
- β³ π οΈ Custom fields, evidence + inventory - review (#195-#197)
- β³ π οΈ Long forms in a task's Work view - review (#198)
- β³ π« REST API: Tickets
- β³ π» REST API: Assets
- β³ π΄ REST API: Problems
- β³ π REST API: Changes
- β³ π REST API: Knowledge
- β³ β REST API: Tasks
- β³ ποΈ REST API: CMDB
- β³ π REST API: Contracts
- β³ ποΈ REST API: Calendar
- β³ πΏ REST API: Software
- β³ π REST API: Domains
- β³ π¦ REST API: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ π·οΈ REST API: Cost centres
- β³ π§βπΌ REST API: Analysts
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ π Rota copy and paste β Developer Deep Dive
- β³ β Checklists & SOPs
- β³ βοΈ Mandatory fields
- β³ π§Ύ Custom ticket fields
- β³ π·οΈ Ticket categories
- β³ π₯ Assigning tickets to a team, and escalation
- β³ π’ One board across every company
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ π Attachment size limits and large emails
- β³ Basic IMAP mailboxes
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
-
β³
βοΈ Telegram channel - β³ β CSAT company scope and filters β Developer Guide
- β³ π₯ Microsoft Teams channel
- β³ π¨οΈ Mattermost channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ β Record previews
- β³ π Ticket notes: internal or shared
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ π¨ Telling the analyst a ticket is theirs
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π’ Ticket numbering
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ π Confidential tickets
- β³ π₯ Portal managers
- β³ π Who has seen a ticket
- β³ π Reading long tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ ποΈ The folder pane
- β³ π½ Just my tickets, or no closed ones
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- β³ π Case reports - a ticket and its work as one PDF
- β³ π Scheduled work in your own calendar
- Problem Management
- Tasks
- π Projects
-
Assets
- β³ π’ Moving an asset between companies
- β³ π Shared asset locations
- β³ π§βπΌ Assigning assets to analysts
- β³ π Warranty and lease alerts
- β³ π Leases
- β³ π Saved table views
- β³ π¨οΈ Recording anything, and importing it
- β³ π§© Asset type layouts
- β³ π·οΈ QR asset labels
- β³ π Who holds what, and handover documents
- β³ π₯οΈ The inventory agent (PowerShell)
- β³ ποΈ Proxmox VE servers
- β³ βοΈ VMware Cloud Director servers
- β³ π Linking equipment to tickets
- β³ βοΈ Follow-up tasks on a ticket
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
-
Forms
- β³ π¨ The form designer β Developer Guide
- β³ π Layout & the grid β Developer Guide
- β³ ποΈ Collections β grouping submissions
- β³ π Submissions as PDFs
- β³ β‘ What happens next β a form's own actions
- β³ π οΈ Sections & conditional logic β Developer Guide
- β³ π οΈ Lookup fields β Developer Guide
- β³ π‘οΈ Catalogue request approvals
- People
- Domains
- ποΈ Files
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
- CMDB
- Network Mapper
- Workflows
- Issue trackers (Jira, Azure DevOps)
- System
-
Overview
- β³ π Progress tracker
- β³ Concepts & vocabulary
- β³ Email routing & mailboxes
- β³ Settings: global vs per-company
- β³ Users & self-service
- β³ Staff cross-company access
- β³ π’ One board across every company
- β³ Worked examples
- β³ Pitfalls & gotchas
- β³ Scope: what it's for
- β³ π οΈ Developer Guide (make a module multi-company)
- β³ ποΈ Case study: CMDB (a linked graph)
- β³ π§ͺ Test harness (prove it's isolated)
- What this is
-
π Bugs resolved
- β³ π Escaped text could leave its attribute
- β³ π Task descriptions were not cleaned
- β³ π Task documents ignored company scope
- β³ π Repeating tasks ignored company scope
- β³ π¬ #183 Mailbox checks overlapped
- β³ π #188 Transfer lock shown off when unknown
- β³ β #184 Subtask names and Overdue
- β³ π§© #186 Teams: the buttons did nothing
- β³ π Text in a change could run script
- β³ π AI settings changed without the AI permission
- β³ πͺ #178 Deleting an analyst failed
- β³ π« A team with no departments showed 0 tickets
- β³ π Projects: adding a phase did nothing on Save
- β³ π Leavers could still sign in
- β³ πΌοΈ Logo and courses broke on Apache with PHP-FPM
- β³ π’ Chat tickets ignored your ticket numbering
- β³ π Dates shown as a dash, or in server time
- β³ π Assets β Users showed people from other companies
- β³ π Restricted analysts could read other modules' data
- β³ πΌοΈ Replies with a picture in the thread failed to send
- β³ π Reply attachments never reached the customer
- β³ π οΈ Outbound email attachments β Developer Guide
- β³ π A global SSO provider was missing from the portal
- β³ π Behind a proxy, the SSO redirect said http
- β³ βοΈ The portal tagline moved when you saved it
- β³ π¨ The portal settings screen forgot what you saved
- β³ π‘οΈ The approvals inbox said "Error" and nothing else
- β³ π A table's answers were missing from the PDF
- β³ β A single-select column let you tick every option
- β³ π The portal ignored a form's field widths
- β³ π The tasks board stopped taking clicks
- β³ ποΈ #121 The index list is out of date after upgrading
- β³ π #133 The calendar subscription was empty
- β³ π #131 Tasks always reopened on the board
- β³ π₯ #129 Every page returned HTTP 500 after upgrading
- β³ π³ #127 A PHP warning above the System page
- β³ π #126 Notes stamped with the server's clock
- β³ π Storing every date in UTC
- β³ πͺ The portal was down for everyone signed in
- β³ βοΈ #120 Workflow notes could never be written
- β³ βοΈ #123 Three errors when running Database Verification
- β³ π #122 The description box was a stub in the corner
- β³ π£ Demo data deleted real accounts
- β³ π #117 Sign-in redirected to the wrong address
- β³ π¨ #108 The priority dot was invisible
- β³ β±οΈ #116 Time logged from the right-click menu
- β³ π #114 API keys refused by our own guard
- β³ ποΈ #110 Assigning a task told nobody
- β³ πͺ #107 Signed out while still working
- β³ π #103 "Share with Requester" reached nobody
- β³ π #102 Search found nothing for hyphens
- β³ πͺ #101 Source code editor opened behind
- β³ βοΈ #88 Subtasks could not be ticked off
- β³ π» #84 Asset deep link selected nothing
- β³ π« #79 A new ticket arrived with no status
- β³ π§ #79 A ticket from email did not say so
- β³ π #78 Bell opened to nothing
- β³ π¬ #77 Mail only collected from Inbox
- β³ π #74 The default password could not be changed
- β³ π¦ #70 Renaming an impact level
- β³ π€ #67 App-only mailboxes could not send
- β³ π #45 Verify only ever worked for Microsoft
- β³ π #45 IMAP reported as not authenticated
- β³ βοΈ An email template stopped escaping itself
- β³ π The portal dashboard showed the wrong time
- β³ π’ The folder said 99 and the list showed 96