Repository navigation
Financial Approvals Design
Status: proposal - nothing built yet. This page sets out what I plan to build from the latest reply on issue #160, and why. It was written before any code so the approach can be checked first. @bigtrodat - please read it and answer the questions near the end on the issue. Anyone else with a view on how purchases get approved where you work is welcome to join in: the whole point of this design is that it should fit more than one organisation.
The request, from @bigtrodat on issue #160:
"Catalogue Item owner can approve, cost center responsible approves that there is enough budget, supervisor approves if employee is eligable to receive this item. Approval order should be adjustable by workflow design."
"When order value is higher than xyz as specific person (management board?) for approval."
The same reply also asks for cost centres in form lookups, for a main and substitute responsible person on each cost centre, and for an order value made from an item's price and a quantity.
That request names four people: the catalogue item owner, the cost centre owner, the supervisor and the management board. Other organisations will have different people in a different order, and many have no cost centres at all. If FreeITSM built those four roles it would fit one way of working and get in the way of the rest.
So this design does not build four roles. It builds four general parts, and those four people become how one form happens to be set up.
| Part | What it does | Size | Useful on its own? |
|---|---|---|---|
| A. Cost centres in form lookups | A form question that picks a cost centre, starting on the requester's own | Small | Yes |
| B. An owner and a deputy on each cost centre | Who answers for a cost centre, set from the cost centre or the person, and kept in step with finance by import or API | Small to medium | Yes, as a record of who is responsible |
| C. Approval steps | A form's approval becomes an ordered list. Each step says who decides and when the step applies | Large | Yes, this is the heart of it |
| D. Calculated answers | A form works out a number, such as price times quantity, and any step can use it | Medium | Yes |
Four rules run through all of it:
- Nothing changes on upgrade. A form with no steps set up behaves exactly as it does today.
- A request never approves itself. If FreeITSM cannot work out who decides, or cannot read the amount a step depends on, the request waits for a person. It is never waved through.
- FreeITSM records what was asked and who agreed. It is not a finance system. The cost centre owner decides whether there is budget. FreeITSM does not hold budgets, raise purchase orders, convert currencies or post anything to an ERP.
- Choosing, not typing. Every setting here is a dropdown, a tick box or a row in a list. There are no formulas or rule languages to type.
| Asked for | How it is met |
|---|---|
| Cost centres in the forms lookup | Part A |
| Main and substitute person, set from either side | Part B |
| Catalogue item owner approves | Part C: a step with A person or A team. No new "owner" field is needed |
| Cost centre owner approves | Part C: a step with The owner of a cost centre |
| Supervisor approves | Part C: a step with The requester's manager, using the Manager field FreeITSM already keeps and directory sync already fills |
| Order is adjustable | Part C: drag the steps into any order, per form |
| Item value times quantity gives an order sum | Part D |
| Above a certain value, somebody else approves | Part C: a step with Only when Order total is more than 5,000, using the same conditions forms already offer for showing and hiding questions |
The last row is the one that shows the shape. The threshold is not a feature of its own. It is a condition on a step, and the amount is an answer on the form.
This is the test of whether the design is general enough. Each row is set up with the same parts, and nothing below needs extra code.
| Organisation | Their approval | How it is set up |
|---|---|---|
| Small firm, no cost centres | The line manager agrees. The IT manager agrees as well over 500 | Step 1 The requester's manager. Step 2 A person, only when the total is more than 500 |
| School or charity | One budget holder, chosen per request | Part A question, step 1 The owner of a cost centre, deputy covers absence |
| Four-eyes finance | Two of three budget holders must agree | Step 1 A team, 2 approvals needed. This already works today |
| Managed service provider | The customer's manager, then the provider's own account lead | Step 1 The requester's manager, who signs in to the portal. Step 2 A person from the service desk |
| Free items need no sign-off | Only spending is approved | Every step only when the total is more than 0. A free request goes straight through |
| Access requests, no money at all | The manager, then the security team | Steps 1 and 2 with no calculated answer anywhere. Parts A, B and D are never touched |
The last row matters most. Approval steps are not really a finance feature. Finance is the first thing to need them.
| Already there | Not there |
|---|---|
| Lookup questions, from one list of searchable sources | Cost centres as a source |
| Cost centres per company, with a hierarchy, import, export and API sync | Anybody responsible for a cost centre |
| Approval by a person, or a team with a set number of votes | More than one step |
| Votes, Stuck, Move and Override, with a full record | Anybody who is not staff approving anything |
users.manager_id, filled by hand or by directory sync |
Anything routing a request along it |
| Number questions, table questions and conditions such as is more than | A number worked out from other answers |
| Forms carrying their own actions through new versions | |
| One money system: formats, favourites, a default currency | Money on the portal, which does not load it yet |
Anybody who is not staff approving anything is the gap that shapes the design, and section 6.3 explains why.
Forms are not multi-company yet, and this design does not need them to be. A form is shared by the whole install, so on a multi-company install every company gets the same steps, the same named people, the same thresholds and the same currency. The steps that depend on the requester still follow each company, because The requester's manager and The owner of a cost centre are worked out from the person asking. A company that needs different named approvers, thresholds or a different currency needs its own copy of the form, offered to its people through Who can request this form. Making Forms multi-company is a separate piece of work.
A new Cost centres choice under Search which records on a lookup question.
- Finds by code or name, and shows both: 0010 - Logistics. Two companies can both have a 0010, so a code alone is not enough.
- Offers active cost centres only. One that goes inactive later stays on old requests, the rule cost centres already follow.
- Scoped to the company: the requester's own on the portal, the ones they can reach for staff. Somebody with no company gets the Default company's list, as lookups already do.
- Off for customers until ticked, like every other lookup. A cost centre is safe to offer on the portal, but that stays the form owner's decision.
- New tick box: Start on the requester's own cost centre. They can change it if the purchase belongs elsewhere.
The answer keeps both the id and the label, as every lookup does, so a renamed cost centre leaves old requests reading as they did.
Two new boxes on a cost centre: Owner and Deputy. Both are optional. Each is a person from the people directory (Tickets -> Users), not an analyst and not a team. Decision 5 sets out why, and what that leaves out.
| Where | What |
|---|---|
| System -> Cost Centres | Edit them, with an Owner column to sort and filter by |
| A person's page | Responsible for lists their cost centres, and a cost centre can be added from there. Both screens write the same record, so they cannot disagree |
| Import and export | Owner email and Deputy email columns |
| REST API |
owner_email and deputy_email, on POST /cost-centres/sync as well |
Rules:
- The owner and deputy must be in the cost centre's company. The same rule Part C needs, so nothing can route across companies.
- People are matched by email address in import and sync, because that is what an ERP or HR system can supply. An address with no match is refused and listed in the preview, never guessed.
- A column left out of a file changes nothing. An older import, or a sync that only knows codes, must not wipe the owners.
- An owner who has left is kept and flagged, on the list and in the leaver's record, rather than removed without trace.
Approval settings, the existing window on a form's shield icon, gains a list of steps. Today's choice between a person and a team becomes what one step holds, so an existing form opens showing one step, set up as it already was.
| # | Name | Who decides | Only when |
|---|---|---|---|
| β Ώ 1 | Catalogue owner | A person: Priya Shah | Always |
| β Ώ 2 | Cost centre owner | The owner of: Cost centre | Always |
| β Ώ 3 | Line manager | The requester's manager | Always |
| β Ώ 4 | Management board | A team: Board, 2 approvals needed | Order total is more than 5,000 |
Rows are dragged to reorder. The name is shown to the approver and the requester.
Who decides is a dropdown:
| Choice | Who that is | Status |
|---|---|---|
| A person | A named member of staff | Today |
| A team | Any member, with a set number of approvals and rejections | Today |
| The requester's manager | users.manager_id |
New |
| The owner of a cost centre | The owner and deputy of the cost centre in a chosen question, or of the requester's own | New |
This list is built to grow. Each choice is one small function that answers "who may decide this?", so a later The owner of the chosen configuration item is one more row rather than a redesign.
Only when uses the condition builder forms already have: a question, a comparison and a value. All conditions, or any.
- Steps run one at a time, in order. A step's approvers see the request when it reaches them.
- Any rejection ends it. Later steps never run, the requester sees Declined, and the form's When rejected actions run.
-
When the last step passes, the request is approved, and everything that happens today happens then: the ticket, the When approved actions, the
catalogue_request.approvedevent. Once. - "Only when" is decided at submission, because the answers cannot change after that. A step that does not apply stays on the record as Skipped, Order total was 3,000, so an auditor can see why it was skipped.
- A condition that cannot be read means the step runs. If the amount is blank, a threshold step applies. Getting this backwards would mean a broken total skips the board.
- The step list is fixed when the request is made. Changing the form affects new requests only, the rule approvals already follow. Who counts as the owner or the manager is checked at every decision, the rule team membership already follows, so a leaver cannot approve and their replacement can.
- The owner and deputy are equals. Either can decide, and the first to do so settles the step.
- The requester never approves their own step. If they own the cost centre, the deputy decides. If there is no deputy, it is Stuck.
- Nobody found means Stuck, never skipped. No manager on the record, or no owner on the cost centre, marks the request Stuck. An administrator then Moves it or Overrides it, as today.
- Move and Override act on the current step. Overriding one step does not wave through the rest.
Today only staff can approve, because approvers are analysts. Managers and budget holders are usually not staff in that sense. They are people in users, and FreeITSM stores their Manager field against that table. So a requester's manager step cannot work at all unless a person who is not a service desk analyst can decide. Giving every budget holder a service desk account is the wrong answer: it is a second password and a lot of screens for somebody who approves a few laptops a month.
So the self-service portal gains an Approvals page, beside Team tickets.
- It shows requests waiting on the signed-in person, with every answer, and Approve and Reject.
- Each read and each decision checks that this person may decide this step, right then. A request id in a web address grants nothing.
- Decisions are recorded against the person, in the same request history as staff decisions.
- Named staff and teams keep deciding in Forms -> Approvals. That page does not change for them.
- A budget holder who is also staff approves from the portal, signed in as themselves. A person's right to approve comes from the sign-in, never from two records happening to share an email address.
This needs a person to be able to sign in to the portal. Approval settings warns when a cost centre owner has no email address. Directory and SSO sign-in already cover most people in an organisation large enough to have cost centres.
Approvers are not told anything today unless somebody builds a workflow rule. One step could live with that. A chain cannot, because every step would wait silently for somebody who does not know it has arrived.
So reaching a step tells its approvers, through the portal bell and by email, with a link to the request. The email is sent from a mailbox chosen under Forms -> Settings. There is no approve button inside the email, because forwarding that message would hand over the decision.
The requester's Your requests panel shows where it has got to: Waiting for Cost centre owner, step 2 of 3.
The request says the order should be adjustable "by workflow design", and the steps do live on the form rather than as boxes on the Workflows canvas. Two reasons:
- The workflow engine runs straight through. It has no way to stop, wait days for a person and carry on. Teaching it that is a large change to the most depended-on code in the product, and the approval engine already handles waiting, votes, Stuck, Move and Override.
- Forms are versioned. A workflow pinned to a form stops matching when the form gets a new version. That is why a form's own actions already live on the form.
Workflows still see everything. The existing events stay, and a new A catalogue request passed a step event lets a rule do something between steps.
A catalogue item in FreeITSM is a form, so there are three shapes an order can take. All three are one new question type, Calculated, built by choosing rather than typing.
| Shape | Example | How the total is worked out |
|---|---|---|
| The form is the item | A New laptop form at a fixed price | A fixed amount times the Quantity answer |
| The form offers a few items | A dropdown of models | The value on the chosen option times Quantity |
| The form is a basket | A table question, one row per item | A value column times a quantity column, added up down the rows |
To make the second and third work, dropdown and choose-one options can carry a value. A new optional box appears beside each option: Standard laptop, 900.
The Calculated question has:
- a list of lines, each chosen from dropdowns, added together;
- a currency, chosen from the same list as everywhere else, starting on the install's default;
- Show this to the person filling in the form, on by default. Some organisations would rather staff did not see prices. It is worked out either way.
Rules:
- The server works it out. The browser shows a live total as a courtesy, but what the browser sends is ignored. Otherwise anybody could post a total of 1 and skip the board.
- Hidden questions do not count. A question hidden by a condition adds nothing.
- The total is frozen on the request, as a stored answer. Changing a price next month does not change last month's request.
-
It is an ordinary answer. The CSV, the PDF, conditions, and
{{submission.fields.Order total}}in workflows all work with no extra code. - One currency per total. Amounts are never added across currencies or converted, the rule Projects already follows. A threshold on a step is in that total's currency.
- Exact amounts. Amounts are stored as exact decimals to the currency's own places, and shown in each reader's own format, so 1.234,56 and 1,234.56 are the same number.
A New laptop form has a dropdown of models (Standard 900, Pro 1,500), a Quantity, a Cost centre lookup, and an Order total in euros. It has the four steps in section 6.1.
- Tom asks for 2 Pro laptops on cost centre 0010. The form shows Order total: 3,000.00 β¬. FreeITSM recalculates it, keeps it, and marks step 4 as skipped: it is below 5,000.
- Priya, the catalogue owner, is staff. She approves in Forms -> Approvals. The bell and an email tell the next person.
- Cost centre 0010 has an owner and a deputy. The deputy gets to it first and approves in the portal.
- Tom's manager approves in the portal. That was the last step, so the ticket is raised with the answers, including the total and the cost centre.
- Tom watched it move through Your requests, and the request's record shows every decision, the skipped step and why it was skipped.
Had Tom asked for 4 Pro laptops, the total would have been 6,000 and step 4 would have run.
| Left out | Why |
|---|---|
| Holding budgets and checking the balance | The owner knows the budget. A second copy of it in FreeITSM would be out of date and would look authoritative |
| Purchase orders, invoices, goods received | That is the ERP's job |
| The CMDB as a price list | The CMDB records what is really in the estate. A catalogue of things that could be bought does not belong in impact analysis. See decision 2 |
| Out-of-office rules | Owner and deputy are equals, so there is nothing to switch |
| Approving by replying to an email | Forwarding a message must not forward the right to decide |
| Reminders and escalation after N days | Worth doing later, once a real chain shows where things get stuck |
| Order cost, depreciation and service bookings | Still on the issue's original list and still wanted, but a separate piece of work about assets rather than requests |
| # | Decision | Where I am leaning |
|---|---|---|
| 1 | Do people who are not staff approve in the portal? | Yes, as in section 6.3. Without it the manager and owner steps cannot work |
| 2 | Where do prices live? On the form, in a shared price list, or in the CMDB | On the form first. A shared price list later if people change the same price on ten forms. Not the CMDB |
| 3 | If one person is both the manager and the cost centre owner, do they approve twice? | Once, with the second step recorded as Already approved by. A per-form setting requires a different person at each step, for organisations that need it |
| 4 | A cost centre with no owner: Stuck, or climb to the parent's owner? | A per-step choice, starting on Stuck. Cost centres already have a hierarchy, so the parent option is cheap |
| 5 | Is a cost centre's owner a person, an analyst or a team? | A person from users, plus a deputy. See below |
| Owner is | For | Against |
|---|---|---|
A person (users) |
Budget holders and managers are already here, with their company, manager and cost centre, and finance systems and directories can match them by email | A member of staff who only has an analyst account needs a person record and a portal sign-in before they can be chosen |
| An analyst | Forms -> Approvals already works for them | Most budget holders are not service desk staff, so they would each need an analyst account |
| A team | The vote counting already exists, and it suits a finance team sharing the job | Teams hold analysts only, so it has the analyst problem. A team has no single person to answer for the money, which is what "responsible" means here |
I am leaning towards a person, with a deputy, because a cost centre needs one named person who answers for it. A step set to A team already covers a finance team deciding together, for every request on that form. What a person-only owner cannot do is send cost centre 0010 to one team and 0020 to another. If anyone needs that, a Team box can be added beside Owner later, without changing what is built here.
- What does a catalogue item look like for you: one form per thing, one form offering several things, or one form as a basket? Part D handles all three, but it tells me which to build first.
- Is a form-level price enough? Or do you keep prices that change often and appear on many forms?
- After approval, what should the cost centre do? Today it would be an answer on the request and on the ticket's text. Tickets have no cost centre of their own. Should an asset bought this way pick it up, or is the record of the approval enough?
- Is your manager and budget holder data in Active Directory or another directory? If so, the Manager field fills itself, and the portal sign-in is ready for them.
- Should the deputy decide at any time, or only when the owner cannot? This design says any time.
- Does the fixed order work for you, one step at a time? Or do some of your approvals need to run side by side?
- Who owns your cost centres: always one named person, or sometimes a team? Are any of them people who only have an analyst account?
Each piece ships and is useful alone.
| Order | Piece | Depends on |
|---|---|---|
| 1 | A: cost centre lookup | Nothing |
| 2 | B: owner and deputy, screens, import, API | Nothing |
| 3 | C1: steps with A person and A team, Only when, telling staff approvers | Nothing. Already gives "IT manager, then finance" |
| 4 | C2: the portal Approvals page, then the manager and owner choices | C1, and B for the owner choice |
| 5 | D: option values and Calculated answers | Nothing, but it is what makes a money threshold possible. A plain number question works until then |
The shape, so the size can be challenged. Exact names are settled in the build.
| Where | What | Why |
|---|---|---|
cost_centres |
owner_user_id, deputy_user_id, foreign keys to users
|
People, not analysts. See section 6.3 |
forms |
approval_steps JSON, NULL by default |
NULL means today's single policy, so no migration and nothing half-migrated. The lesson of submission_actions. JSON so a new Who decides needs no schema change |
form_submissions |
approval_steps snapshot, approval_step_no, approver_user_id, approval_decided_by_user_id
|
Exactly one of each analyst or user pair is set, as submitted_by and submitted_by_user_id already work |
form_submission_votes |
analyst_id nullable, new user_id, a second unique key |
analyst_id NULL, the existing key stops nothing, so user votes need their own unique key on submission, round and user |
π The existing snapshot columns always hold the current step's policy. Passing a step copies the next step into approver_id, approval_team_id and the two numbers, and increments approval_round. Votes are already counted per round, so catalogueApprovalProgress(), Stuck, Move, Override and the row lock in catalogueLockSubmission() all keep working with no second code path. The developer guide already called approval_round the starting point for this.
catalogueFinishDecision() then splits: the last step finishes as it does today, and any other step advances. The advance happens inside the same transaction and lock, so two final votes cannot advance twice.
| Trap | Rule |
|---|---|
| Settings that Save deletes |
approval_steps must go through copyApprovalPolicy() and createVersion(), and every new field setting through the form copy. This has bitten twice |
| Half a trigger | The new step event needs both its dispatch() and its availableTriggers() entry |
formLogicTestRule() on a blank |
is more than on a blank answer is false, which would skip a threshold step. Step conditions need a wrapper that treats an unreadable answer as "applies" |
| Losing an option's value | Option values live in config, keyed so that renaming an option does not lose its value, because conditions compare on the option's text |
| Five type lists | A new field type goes in the service, the AI generator's list and prompt, the JS evaluator and the builder. tests/forms-lookup/run.php says which was missed. It also needs both renderers, forms/fill.php and self-service/catalogue.php, and the task form embed |
| Lookup registry | Cost centres need two new abilities in LOOKUP_SOURCES: a fixed filter (active only) and a label from two columns. The filter must apply to the search and the submit check, or the list offers something the submit refuses |
| Company on submit | The cost centre chosen must be re-checked against the requester's own company on the server, and must be active, because it now decides who approves |
| Two identities, one person | A person with both a staff and a portal account must not vote twice in a team step. Compare email addresses to refuse a second vote, never to grant one |
| Money on the portal |
Money::scriptTag() and money.js are not loaded on any portal page yet |
| The analyst lifecycle map | Any new column pointing at analysts must go on the map in includes/analyst_lifecycle.php, and the leaver flow should show cost centres somebody owns |
When this is built: Catalogue Request Approvals (What this version does not do), Portal Request Catalogue (limitations), Cost centres, Forms, the in-app help for Forms and System -> Cost Centres, and REST API: Cost centres.
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
- β³ π Switching modules off
- β³ π οΈ Module availability β Developer Guide
- β³ π Module availability β design (#217)
- 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
- β³ π οΈ Inbox.js map β Developer Guide
- β³ π οΈ Floating windows & the file viewer β Developer Guide
- β³ π οΈ Tickets settings β Developer Guide
- β³ π Simpler ticket and task forms - design (#218)
- β³ ποΈ The ticket workspace
- β³ π The ticket table
- β³ π 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
- β³ π Inventory freshness
- β³ π Linked configuration item
- β³ π Connected assets
- β³ π Asset review
- β³ π·οΈ QR asset labels
- β³ π Who holds what, and handover documents
- β³ π₯οΈ The inventory agent (PowerShell)
- β³ ποΈ Proxmox VE servers
- β³ βοΈ VMware Cloud Director servers
- β³ πͺ Hyper-V and Failover Clusters
- β³ π 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
- Starters & leavers
- Domains
- ποΈ Files
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
- CMDB
- Network Mapper
- Workflows
- Issue trackers (Jira, Azure DevOps)
- π‘ Zabbix (monitoring)
- π¬ Microsoft Teams alerts
- π 3CX (phone system)
-
System
- β³ π οΈ Preferences β Developer Guide
- β³ π Finding people in the Analysts list
- β³ πͺ When an analyst leaves
- β³ π οΈ System β Branding β Developer Guide
- β³ π©Ί Page health (D019) β Developer Guide
- β³ β Feature Bingo
- β³ π·οΈ Cost centres
- β³ π· Photo Album
- β³ Demo Data
- β³ π οΈ Demo Data β Developer Guide
-
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
- β³ π« #227 A mailbox could not be deleted
- β³ π« #226 A picture on a note could not be closed
- β³ π» #222 The Assets page never loaded in 4.3.0
- β³ βοΈ #214 A "contains" condition did not match capitals
- β³ βοΈ #216 A workflow email from a chosen mailbox always failed
- β³ π³ The Docker image was missing PHP extensions
- β³ π A failed DNS lookup read as a missing record
- β³ π A link could change data
- β³ π Access outlived its removal
- β³ π Knowledge articles could run scripts
- β³ π Knowledge writes ignored permissions
- β³ π Company boundaries (Oct 2026)
- β³ π Smaller gaps (Oct 2026)
- β³ π 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