Workflow
Cases & speak-up
The intake front door: someone raises something — a question, a grievance, a protected disclosure, a data request — and it is acknowledged on a clock, worked through a confidential thread, and answered on the record. The registers that already exist (Investigations for fact-finding, Discipline for consequence) are the back half; this module is how a concern gets in.
This is the guide HumanR users read inside the product, published as-is. It is written for someone with the screen in front of them, so it describes buttons you cannot click from here — which is rather the point: you can check how the product behaves before you commit to it.
What this module is
A case is one record of one concern: who raised it (or that nobody is
named), what kind of concern it is, the thread of messages both ways, the files, and how
it ended. Each case filed gets a reference — CASE-… — and the register is
the list of those references, filtered to what you are allowed to see.
One lifecycle serves all four kinds; what differs is visibility and the clocks. That is deliberate: a grievance that turns out to be a misunderstanding and a question that turns out to be serious both stay in the same machinery, and nothing needs to be re-filed to change grade.
The four kinds of case
A query is the helpdesk grade — "how many leave days do I have left", "my payslip looks wrong". A grievance is a formal complaint about treatment, conditions or conduct. A protected disclosure (whistleblowing) is a report of wrongdoing made in the expectation of protection — it has its own anonymous channel and its own officer-only visibility. A data request is a GDPR-style subject-access request: export my data, correct it, or erase it.
Staff raise queries, grievances and data requests from the portal under their own name. A protected disclosure is never an ESS form: a named report of wrongdoing is simply a grievance, and the disclosure type exists for the protected channel where the reporter controls whether they are named at all.
Who sees a case
Queries open at the register grade (hr-cases.view). Data requests and
grievances are handler business (hr-cases.manage). Protected disclosures
require the officer key (hr-cases.whistleblower) — holding every other
permission in the system does not open one, because the handler population is exactly
who a reporter may be reporting.
For a grievance or a disclosure, the case page carries an access list. The moment the first name goes on it, the case narrows to the named handlers: everyone else's register stops showing it, their search stops finding it, their dashboards stop counting it. An empty list means the whole grade sees it. The list narrows, it never grants — you cannot list someone the matrix would not admit anyway.
Narrative fields — the summary, the thread, the resolution — additionally sit behind
sensitive.cases for the general grades: a register user without it sees
the row but a masked narrative. For a disclosure the officer key is the
clearance. Admins pass every gate, as everywhere in HumanR; an instance that wants a
sealed channel names its officers deliberately and keeps the Admin role short.
The statutory clocks
Two dates are stamped at intake and shown on every case: acknowledge by — 7 days for everything, per the EU Whistleblower Directive's Art 9(1)(b) — and answer by: 3 months for a grievance or disclosure (Art 9(1)(f)), 30 days for a data request (GDPR Art 12(3)), none for a query.
The nightly scan chases what is late: handlers get a digest naming the overdue
references, and only handlers the case is visible to — an access-listed case chases
its listed names alone, a disclosure chases officers alone. The day counts are
config-overridable (HrCases:AckDays and friends); the defaults are the
compliant ones and nothing stops a tenant outside these regimes from relaxing them.
The life of a case
Open → acknowledged → in progress → resolved → closed, with withdrawn available while it is open and reopen afterwards. Acknowledging posts a reporter-visible line ("your report has been received…"), which is what the first clock measures. Messages to the reporter land on their thread — the portal page for a named case, the token page for an anonymous one. Resolving requires the resolution text: it is the record, and the reporter reads it verbatim.
The trail is write-once. There is no edit and no delete on an event, ever — a case history that could be tidied to match its outcome would be worthless the one time it matters.
The anonymous channel — /speak-up
/speak-up works logged-out, is linked from the login page and the portal,
and files a protected disclosure with no name attached — being signed
in changes nothing, and the page says so. Identity fields exist but are optional, and
what is volunteered is shown only to officers, with every look audited.
Filing shows a key, exactly once. The key is the reporter's whole identity: whoever holds it can read the status, see the acknowledgement, and write on the thread — so the page offers copy, print and select-on-focus, and the key is never shown, emailed or logged again. A lost key cannot be recovered; the recourse is to file again and say so.
A wrong key gets a plain not-found page — the same one every time, so guessing reveals nothing, not even whether a case exists. The key keeps working for as long as the case is open, and for 90 days of read-only access after it closes. An officer can rotate a key if it may have leaked; the old one goes dark instantly.
Data-subject requests
Staff pick the kind when raising: export and erasure file a case for HR to fulfil with the tools that already exist (reports, the document library, the employee page); the case records what was done and when, which is the accountability trail the regulation actually asks for. Correction doesn't file a case at all — profile corrections already have their own approval flow on the profile page, and the form points there.
Resolving an erasure requires one extra field: what was kept, and on what lawful basis. Payroll and statutory records survive an erasure request (Art 17(3)(b)), and writing the retention story down is the difference between a defensible refusal and an awkward one.
Escalating to an investigation
When a case needs fact-finding — statements, evidence, an outcome that may reach the
discipline register — Escalate creates a draft investigation carrying
the case's substance and links the two. It needs both sides' permissions: the case
grade to act here, investigations.manage to create there. For a protected
disclosure the created investigation deliberately does not carry the
reporter's identity — only the substance travels. Withdrawing or deleting the
investigation later leaves the case standing.
What staff see
Cases in the portal lists what they raised — never anyone else's, and never anonymous ones, even when a volunteered identity names them. A case shows the status timeline, both due dates, the thread (handler messages appear as "HR" — never a name), their own files, and the resolution verbatim. Internal events — who was assigned, what was escalated — do not render on the portal side.
Permissions & gotchas
hr-cases.view— the register, and query detail.hr-cases.manage— act on cases: acknowledge, message, assign, resolve, escalate.hr-cases.whistleblower— see and act on protected disclosures; rotate keys.sensitive.cases— read the narrative fields on the general grades.
None of the three are granted to any role by default — not even HR. An instance turns the module on and then names who handles cases, and the officer grant in particular is a named-person decision, not a role convention.
Gotchas: protected disclosures never appear in global search, webhooks, exports or the demo data — no surface exists from which to infer one. Grievances leave the search index entirely once you use access lists (search cannot honour a per-case list, so they are not indexed at all). And the access list narrows visibility but never widens it — removing the last name reopens the case to the whole grade.