Put the onboarding checklist where the file is
The list existed on paper: one printed sheet per entry, twenty-five
boxes. What is on it is known only to whoever holds the sheet — it
cannot be searched, cannot be covered for while someone is away, and
says nothing about who ticked what.
Not every box on the sheet is a checkbox, and the differences carry
meaning, so the field kind is derived from the thing rather than
flattened:
Haken — the normal case. The Meldezettel is there or it is not.
Ja/Nein — Prämienanspruch had *two* boxes on the sheet, and that is
not decoration: "nein" is a finding, "not asked yet" is not.
One checkbox cannot say both.
Text — shoe, shirt and trouser size. The value is the point;
ticked off it would be worthless.
Every item takes a comment, and every item records who last touched it
and when — the part the sheet could never do.
Saved on click, not on submit. A checklist is worked through over days,
between other things; a save button at the end is where half a morning
goes missing.
The items live in lib/onboarding.ts, not in a table: a checklist is a
company process, not a master record. Stored per person is only the
answer, under the item's key — so an item dropped later leaves its old
answers standing instead of taking them along, and a file from back then
stays readable.
A list is created by hire and rehire, in the same transaction as the
hire itself: a hire without a checklist would be a half-recorded hire.
Rehire only adds what is missing and never clears an old tick — what
genuinely has to be redone is HR's call, and a program deciding it would
be guessing. People hired before this feature have no list and get a
button to start one.
Checked against the real database end to end: hire creates 25 open
items; checkbox, ja/nein, size and comment all land; a comment-only edit
leaves the tick alone; rehire tops the list up and keeps what was done.
The probe employee was removed afterwards — audit rows first, since the
log has no delete policy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -89,6 +89,13 @@ export async function loadEmployeeDetail(tx: Tx, id: string, today: string = tod
|
||||
e.selectFrom("position_assignments as pa").select("pa.position_id").where("pa.employee_id", "=", id)
|
||||
)
|
||||
).as("costRows"),
|
||||
jsonArrayFrom(
|
||||
eb
|
||||
.selectFrom("onboarding_tasks")
|
||||
.select(["item_key", "erledigt", "wert", "kommentar", "updated_by_name"])
|
||||
.select((x) => zeitstempel(x.ref("updated_at")).as("updated_at"))
|
||||
.where("employee_id", "=", id)
|
||||
).as("onboarding"),
|
||||
// Die offenen Planstellen bleiben bei heute: sie gehören zur
|
||||
// Organisation, nicht zu dieser Person.
|
||||
jsonArrayFrom(offeneStellenAbfrage(eb, today)).as("open"),
|
||||
@@ -131,6 +138,7 @@ export async function loadEmployeeDetail(tx: Tx, id: string, today: string = tod
|
||||
placement,
|
||||
// Die Kostenstelle des Sitzes, auf dem die Person am Stichtag sitzt.
|
||||
kostenstelle: placement ? (kontierungZum(g.costRows as KontierungsZeile[], asOf).get(placement.positionId) ?? null) : null,
|
||||
onboarding: g.onboarding,
|
||||
openPositions,
|
||||
byId: new Map(relatedRows.map((e) => [e.id, e])),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user