← HR Cluster

Changelog

Operational and technical updates to the HR Cluster platform.

Types of changes
Added New functionality or modules.
Updated Improvements or changes to existing functionality.
Core Major architectural, platform-wide, or operational changes.
Deprecated Features scheduled for removal.
Removed Features or functionality removed.
Fixed Bug fixes and issue resolution.
Security Security improvements or vulnerability fixes.

2026

— continued

Messaging • Worked in the last 12 months now means assigned to a shift

The Worked in the last 12 months filter on a group message, introduced earlier today, now counts people who were assigned to a published shift that started in the last 12 months, rather than people who clocked in. An assignment that was declined, cancelled or a no-show does not count, and neither does a clock-in without an assignment. A future shift counts only under Has an upcoming shift. The catch-all choice in the filter now reads Any role, and the hint under the filters states the rule. On a sent message's page, the message and its Recipients card are now spaced apart like every other page.

Technical focus: Both shift filters now read shift assignments against the account's local time; clock-in records are not consulted.

Suppliers • Edit a supplier in the same dialog as the other edits

On a supplier's page, Edit now opens the same larger dialog used elsewhere, titled Edit supplier with the supplier's name under it, with the same fields as before. If a change cannot be saved, for example because the organisation number already belongs to another supplier or the name is missing, the dialog stays open with what you typed and says why, instead of reloading the page. Saving reloads the page with the message Supplier saved. Links to the old edit address still open the dialog. The quick edits for internal notes and the incident email are unchanged.

Technical focus: Creating and editing a supplier share one form and one dialog shell, so the two cannot drift, and a refused save answers inside the dialog while an ordinary form post still redirects.

Messaging • Send to several groups and filter who receives it

Under Messages, New message, Send to Group now lets you tick any number of groups from a searchable list. Ticking a parent group includes its subgroups, and a person in two of the chosen groups gets the message once. When sending to group members you can narrow the recipients with optional filters, and all the filters you choose must match. Age keeps people of at least 16, 18, 20, 21 or 25 today, from the date of birth on their profile; people with no date of birth are left out when an age filter is set. Worked in the last 12 months keeps people who clocked in at all, or on a shift in a chosen role. Has an upcoming shift keeps people assigned to a published shift that has not started, in any role or a chosen one. A line above Send shows how many of the group members match and how many were left out for having no date of birth, and a filter that matches nobody is refused. The message page and the message list name every group a message went to, and the message page shows the filters used. Anyone who can already send messages can use this.

Technical focus: One resolver computes the recipients for the live count, the preview and the send, so what is counted is what is sent. Filters only ever narrow; an unknown role or another account's group is refused rather than dropped, and an unknown date of birth fails the age filter. Each message records every group addressed and a snapshot of its filters, with role names as they were when sent.

Catering • Food slots and plan rows agree on meal, notes and responsible people

A Meal row added on the Production Plan or in the Sheet now gets its meal from its title, so a row called Lunch lands under Lunch. When the title does not name a meal, the serving time decides: before 10:30 is Breakfast, before 15:30 is Lunch, and later is Dinner. A row with no time is Other. This is set once, when the row first appears in Catering; the meal can then be changed in the food slot dialog. A food slot's notes now show on its card under the heading, as a plan row shows its notes, and a responsible person who cannot open the Production Plan is marked on the card, as on the plan. The notes field in the food slot dialog is now a single line, like the plan's own.

Technical focus: The meal is inferred once, when the food slot extension is first created, from the title in the account's language and in English, and never re-inferred afterwards. The card reuses the plan's notes line and the plan's one no-access marker.

Vehicles • Edit a vehicle in a dialog on its page

On a vehicle's page, Edit now opens a dialog titled Edit vehicle, with the registration under the title, instead of a separate page. The fields and what is saved are unchanged. Saving reloads the vehicle's page with the message Vehicle updated; if a change cannot be saved, for example because the registration was emptied, the dialog stays open with what you typed and says why. Links to the old edit page open the dialog on the vehicle's page.

Technical focus: Creating and editing a vehicle share one dialog form file, so the two cannot drift, and a refused save answers inside the dialog while an ordinary form post still redirects.

Production Plan • The row's comment field is now called Notes

The free-text field on a Production Plan row is now labelled Notes, in the inline editor, the Sheet and the add row. Only the name changed: what is stored, the CSV import and export, and the Need field are the same as before. The comment asked for when a work run starts or closes keeps its own name, Comment, because it is a different field. Help uses the new name in all four languages.

Technical focus: A label change only: the row field reads its own translation key, separate from the work-run comment, and no column, payload or importer column changed.

Catering • Pick responsible people by name, and see overlapping allergies in the summary

The Responsible field in the food slot dialog is now the same person picker used to assign people to a shift: search by name and each person you pick is added as a chip, so a slot can have several responsible people. The picker offers the people the Production Plan allows as responsible, and marks anyone who cannot open the plan. A responsible person already on a slot stays when you save, even if the picker no longer offers them. The Add and Edit dialog is now wider, with groups and departments side by side under Who is included. The Catering summary PDF now has the same Related and overlapping records section as the Food & allergies summary, so people with a combination of allergies and dietary needs are grouped together, still without names.

Technical focus: The responsible picker reads the Production Plan's one picker scope, and stored responsibles are drawn from the slot itself rather than from what the picker offers, so narrowing the scope never drops someone on save. The summary's overlap section uses the same helpers as the Food & allergies summary.

Deliveries • Proposal emails link to Deliveries only for people who can open it

The email telling a supplier's responsible person about a proposed delivery, and the email telling a member their information request was answered, used to carry a button into Deliveries for everyone, which led someone without Deliveries access to a page they could not open. The button now appears only for a recipient who can open Deliveries; anyone else gets the email with a sentence explaining why there is no link.

Technical focus: The link is judged per recipient against access to Deliveries, the module it opens, never against the Suppliers access that made the person responsible.

Incidents and Suppliers • Owner and responsible pickers follow module access again

Incidents and Suppliers no longer have a setting for who can be picked, and no longer mark people without access. The incident owner picker again offers the people who have access to Incidents, and the supplier responsible picker, including the responsible list in a supplier's delivery setup, offers the people who have access to Suppliers. A choice saved in either of the two removed settings earlier today no longer applies. The Production Plan keeps its setting for who can be picked as responsible, and Risk assessments keeps its setting for the responsible leader and participants, with their No access markers. In those settings a parent department or group now shows as partly ticked while some of its children are ticked and it is not.

Technical focus: For Incidents and Suppliers the person picked administers the module, so the module's own permission decides who can be picked; a separate population setting with different rules would be harder to understand. The shared picker scope now serves the Production Plan and Risk assessments only, and the two withdrawn modules' stored settings were deleted.

Accreditation • Edit a record in the same dialog as New accreditation

Opening an accreditation record now shows it in the same dialog used to create one, titled with the person's name, instead of a separate page. Archive and Restore are in the dialog's footer, and Archive asks for confirmation first. Saving closes the dialog on the records list with the message Accreditation updated; if a change cannot be saved, the dialog stays open with your edits and says why. Links to a record's old page open the list with that record's dialog open. People who can view accreditation but not manage it can still open a record to read it, without Save or Archive.

Technical focus: Creating and editing a record share one dialog and one form file, so the two cannot drift, and a refused save answers inside the dialog while an ordinary form post still redirects.

Catering • The PDFs show the time arrow

The catering Summary and Detailed PDFs printed a question mark between the start and end of a serving time, such as 12:00?14:00. They now show the arrow, as the other PDFs do.

Technical focus: The PDF font set has no arrow character, so the arrow is drawn as a shape, the same rule the Production Plan PDF uses.

Catering • Add food slots for several dates and serving times at once

Add food slot now works like Add shift: pick several dates and add several serving times per day, each with its own meal and optional name, and one food slot is created for every date and time. The location, responsible people, notes and who the meal is for are shared by all of them. If any row is not valid, such as a serving end before its start, nothing is created, so a batch is never saved halfway. The serving end now follows the start: changing the start moves the end by the length last set, one hour to begin with, and a new serving time starts where the previous one ends. Editing a food slot still edits that one slot.

Technical focus: Every row in a batch is validated before any is written, so the batch saves whole or not at all; the end-follows-start behaviour is a form convenience only, and the server still refuses an end that is not after its start.

Catering • The food slot dialog shows its Save button again

For a few hours on 27 September the Add and Edit food slot dialog on the Catering page opened without its Cancel and Save buttons, so a food slot could not be saved from it. The dialog now shows both buttons.

Technical focus: The dialog finds its title and footer inside the first element of the loaded form, so that element must wrap the whole form; a check now reads the real dialog and asserts it.

Incidents, Suppliers, Production Plan and Risk assessments • People without access are marked, not hidden

The incident owner picker and the supplier responsible picker, including the responsible list in a supplier's delivery setup, now offer every active member within the scope set under Settings, not only people who have access to Incidents or Suppliers. A person without access to the module can still be picked, and is marked, for example No Incidents access. The same mark now appears beside Production Plan responsibles and beside risk assessment responsibles and participants who cannot open those modules, in the pickers and wherever the person is shown. Being assigned never gives access: an admin grants it under Settings. Notifications still reach such a person, without a link into the workspace and with a sentence saying why.

Technical focus: Assignment and authorization are separate: pickers and writers judge active membership only, and module access is shown as a marker from one shared helper, never used to hide a person. On the plan the marker travels with the row data, so a live refresh cannot drop it. A notification to someone without access carries no workspace link rather than a link that would refuse them.

Vehicles • Types open in one dialog

On Vehicles, Types, New type, Edit and Customize now open the same dialog, laid out like the accreditation type dialog, and each loads the type as it is stored. The fields and what is saved are unchanged. If a change cannot be saved, the dialog stays open with what you typed and says why. Links to a type's old address open the Types list with that type's dialog open.

Technical focus: New, edit and customize share one dialog that loads one form file from the stored row, so the three cannot drift, and every save answers through one path that keeps a refusal inside the dialog.

Accreditation • Edit a type in the same dialog as New type

On the Accreditation Types list, clicking a type's name or its Edit button now opens the type in the same dialog used to create one, titled with the type's name, instead of a separate page. The fields, the access restrictions, the status and what is saved are unchanged. If a change cannot be saved, for example because the name was emptied, the dialog stays open with your edits and says why. Links to a type's old page open the Types list with that type's dialog open.

Technical focus: Creating and editing a type share one dialog and one form file, so the two cannot drift, and a refused save answers inside the dialog while an ordinary form post still redirects.

Catering • Food slots with live headcounts and allergy counts

Food & allergies has a new Catering tab for planning meals, available when the Production Plan module is on. A food slot is one serving period, such as Lunch 12:00➜14:00 in the main tent. It is a row of the new type Meal on the Production Plan, so it has a date, a serving window, a location, a responsible and departments like any other row, and it appears in the plan, the checklists, the morning briefing and Plan Live. A Meal row added on the plan shows up in Catering too; it is one record, edited on either page. Add food slot opens a dialog where you choose the project, the meal (Breakfast, Lunch, Dinner or Other), the serving time and who the meal is for: groups, departments, or both, matching people in any of them or only those in both. Sync meal plan to shifts, on by default, counts only the people with a published shift in that project that touches the serving time, and Include shifts close to serving time widens that by a tolerance, 15 minutes by default. Each slot shows the headcount and how many are vegetarian, vegan, have an allergy or have not answered, and it expands to list the people. The headcount follows the roster as shifts change. You can view one project, several or all of them, and the period bar opens on today. The Summary PDF is the caterer's order sheet with counts only and no names; the Detailed PDF and CSV list the people. Export one slot from its card or tick several. A slot with shift sync off and no groups or departments counts every active member, so Catering says so and asks you to confirm before saving. Viewing Catering follows the Food & allergies view permission, adding and editing food slots needs Production Plan edit access, and the exports need the Food & allergies export permission. Help is in all four languages.

Technical focus: A food slot IS a Production Plan row of one platform-seeded Meal type with a one-to-one extension (migration 663) for what the plan has no column for; departments stay the plan row's own junction, and shared fields go through the plan's own writers, so the page carries no plan SQL. Who eats is never stored: one resolver computes the population and counts for the page and both exports on every read. Shifts count only inside the slot's own project, and the rules fail narrow: deleting a selected group narrows a slot rather than widening it, and the everyone case needs an explicit confirmation.

Suppliers • Picking another project in a module setup shows that project's phases

On a supplier's Vehicles and Accreditation tabs, choosing another project in the Configuration form used to leave the saved project's phases on screen, so phases could be picked from the wrong project. Choosing a project now reloads the form on that project: its phases are offered, and on Vehicles the locations narrow to that project. A newly chosen project starts with no phases or dates ticked, and locations already stored stay in place. Other unsaved changes in the form are lost when the project is changed, so choose the project first.

Technical focus: Only a project from the account's own list is honoured when the form is reloaded on it, and a failed accreditation save keeps the project that was picked the same way.

Accreditation • New type opens in a dialog

New type on the Accreditation Types list now opens the type form in a dialog over the list, instead of a separate page. If the type cannot be saved, the dialog stays open with everything you typed and says why. Older links to the add page open the same dialog. Editing an existing type is still its own page. Saving a type without a name now says the type needs a name, where it used to ask for a first and last name.

Technical focus: The dialog renders the same form file as the edit page, so the two cannot drift, and a refused save answers in the dialog through one refusal path while an ordinary form post still redirects.

Incidents, Risk assessments and Suppliers • Choose who can be picked as responsible

The setting that decides who the Production Plan offers as responsible is now available in three more modules. Under Settings, Modules, Incidents the Incident owner card decides who the incident owner picker offers. Under Settings, Modules, Risk assessments the Responsible and participants card decides who can be picked as the responsible leader and as an internal participant, in the workspace and on the public SJA form. Under Settings, Modules, Suppliers the Responsible person card decides who can be picked as a supplier's responsible person, including in the delivery setup. Each offers everyone, anyone in a department, or only the people in the departments and groups you select, and each starts at everyone, so nothing changes until an admin narrows it. Narrowing only changes who is offered: nobody already set as owner, responsible or participant is removed, and the incident owner picker still only offers people with access to Incidents.

Technical focus: All three modules read the ONE per-module picker scope introduced by changelog 665. The scope is spliced after each module's own permission filter and never replaces it, it applies to pickers only and no writer consults it, and a stored responsible stays selectable in the supplier form even when the scope no longer offers them. The retired Production Plan storage the scope was copied from has been removed.

Production Plan • Who can be picked as responsible is now a shared setting

The Responsible person card under Settings, Modules, Production plan works exactly as before and keeps the choice you had made: everyone in the account, anyone in a department, or only the people in the departments and groups you select. It is now built as one shared setting for deciding who a module's people pickers offer, so other modules can offer the same choice in the same way. The card's wording is clearer: selecting several departments or groups offers a person who is in any of them, membership is read every time a picker opens so someone added to a selected department or group later appears on their own, and people already assigned are never removed by narrowing the choice.

Technical focus: Which people a module's pickers offer is ONE capability keyed per module, with one reader, one writer and one settings card; the Production Plan reads through it unchanged. It is a picker eligibility rule only and never a write gate, the selection is a union across groups and departments that fails closed when it resolves to nobody, and the plan's earlier storage was copied, not moved, and stays inert until a later migration removes it.

Production Plan • Edit a delivery's description and instructions from the plan

On a delivery or return row of the production plan, the popover that opens from the row's title now also shows the delivery's own description and its delivery instructions, beside the row's title, comment and need, and you can edit them there without opening the delivery window. The two fields appear for people who may edit deliveries, that is with the Deliveries module on and permission to manage deliveries; everyone else sees the popover as before. When a delivery is shared by several rows, saving redraws the plan so every row of that delivery shows the new text. Help updated in all four languages.

Technical focus: The popover saves through a delivery_text endpoint that resolves the delivery from the plan ITEM, proved against the account and the project, and writes through the ONE delivery writer, whose presence rule leaves every other delivery field untouched; it is gated on the same module and permission as the delivery modal's Save. The row payload carries the raw description so the editor never prefills the stated-absence text. Guarded by a db-write guard mutation-tested against the permission gate.

Morning briefing • A shift removed from the schedule no longer appears

The morning briefing lists the shifts on each project's production plan, and the plan keeps its shift rows in step with the schedule. That step ran when somebody opened the plan, so a shift removed from the schedule could still appear in the 06:00 briefing if nobody had opened the plan since, and on one morning a deleted test shift was printed in the checklist as overdue. The briefing now brings each project's shift rows up to date itself before it builds, so a deleted or unpublished shift is gone from the checklist and the plans the same morning, whether or not the plan was opened. Nothing about which shifts, plans or people the briefing covers has changed.

Technical focus: The briefing builder runs the ONE canonical shift-mirror sync once per account and project per worker process, before any fetch, gated on the same show-shifts setting the plan page reads; it adds no sync logic of its own. The briefing delivery guard proves a mirror row whose shift was removed outside the plan is soft-deleted by the build and named in no document, mutation-tested with the call disabled.

12 changes · 1 added · 9 updated · 2 fixed

Vehicles 10 · Messaging 5 · Suppliers 3 · Production Plan 2 · Forms 1 · Users 1 · +2 more

Deliveries • The rejection email describes the delivery too

Earlier today the delivery decision email gained the delivery's description, location and gate control on an approval, and the rejection email was left without them. A rejection now states the same four facts, the description, the location, the gate control and the instructions, read from the delivery as it stands, which the rejection left unchanged, so the reader still sees which delivery the decision concerns and what is registered for it. Each is always stated, with Not registered when nothing has been written. A rejected proposal for a brand-new delivery has no delivery behind it yet, so that email states only the description that was proposed. Help updated in all four languages.

Technical focus: Both branches of the decision email read the delivery's description, location, gate control and instructions through the same helper over the delivery as it now stands; a rejection reads the unchanged delivery, an approval reads the delivery it wrote, and the rejected new-registration branch is the one that has no delivery to read and prints the proposed description only. The three guards that pinned the approval-only rule now assert this one, including end to end through the shipped writer and the dev mail log.

Deliveries • The proposal emails list what changes, field by field

The emails about a delivery proposal now say exactly what changed. The approval email lists the Changes the approval wrote, a rejection lists the Changes not made, and the two emails about a proposal that is still waiting, the one telling the office a supplier has proposed something and the one confirming an information request was answered, list the Proposed changes. Each is one line per field, reading Label: from ➜ to, with an empty side stated as Not registered, so the reader sees where the change was made rather than reading two descriptions side by side. A field that did not change is not listed, and a proposal for a brand-new delivery carries no list, since there is nothing to compare it with. Help updated in all four languages.

Technical focus: ONE pure source, delivery_proposal_changes(), derives the list from the proposal's baseline, its proposed payload and, for an approval, what the approval wrote (applied_json), comparing canonical forms so a pair that agrees is not a change; ONE formatter, delivery_proposal_change_lines(), renders it, called by each template inside its own with_lang() so labels and values follow the recipient's language. A fifth email about a proposal lists changes through the same pair rather than diffing fields itself.