Put the onboarding checklist where the file is
Some checks failed
CI / Lint, Typen, Tests, Build (push) Failing after 6m24s
CI / Integrationstests (echtes Postgres) (push) Failing after 5m51s

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:
2026-08-17 15:40:02 +02:00
parent bd990b7f2c
commit 82d07f0d95
9 changed files with 800 additions and 8 deletions

View File

@@ -479,6 +479,35 @@ export type Database = {
};
Update: Partial<Database["public"]["Tables"]["om_positions"]["Insert"]>;
};
// Die Onboarding-Checkliste: je Person und Punkt eine Zeile. Welche
// Punkte es gibt, steht in lib/onboarding.ts — nicht hier.
onboarding_tasks: NoRelationships & {
Row: {
id: string;
employee_id: string;
item_key: string;
erledigt: boolean;
wert: string | null;
kommentar: string | null;
created_at: string;
updated_at: string;
updated_by: string | null;
updated_by_name: string | null;
};
Insert: {
id?: string;
employee_id: string;
item_key: string;
erledigt?: boolean;
wert?: string | null;
kommentar?: string | null;
created_at?: string;
updated_at?: string;
updated_by?: string | null;
updated_by_name?: string | null;
};
Update: Partial<Database["public"]["Tables"]["onboarding_tasks"]["Insert"]>;
};
// Kostenstellen. Die Zuordnung hängt an der Planstelle, nicht an der
// Person: der Sitz kostet Geld, auch wenn niemand darauf sitzt.
cost_centers: NoRelationships & {
@@ -585,6 +614,8 @@ export type Database = {
create_position: { Args: { payload: Record<string, unknown> }; Returns: string };
update_position: { Args: { payload: Record<string, unknown> }; Returns: void };
set_position_cost_center: { Args: { payload: Record<string, unknown> }; Returns: void };
set_onboarding_task: { Args: { payload: Record<string, unknown> }; Returns: void };
start_onboarding: { Args: { payload: Record<string, unknown> }; Returns: number };
delete_position: { Args: { payload: Record<string, unknown> }; Returns: void };
is_valid_svnr: { Args: { p_svnr: string; p_birth_date?: string | null }; Returns: boolean };
apply_due_pending_changes: { Args: Record<string, never>; Returns: number };