@kernhq/module-hr 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/migrations/0004_policies.sql +89 -0
- package/migrations/meta/0004_snapshot.json +4035 -0
- package/package.json +1 -1
- package/src/contract/policies.ts +207 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
CREATE TABLE "mod_hr"."periods" (
|
|
2
|
+
"id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
|
|
3
|
+
"workspace_id" uuid NOT NULL,
|
|
4
|
+
"kind" text DEFAULT 'payroll' NOT NULL,
|
|
5
|
+
"legal_entity_id" uuid,
|
|
6
|
+
"starts_on" date NOT NULL,
|
|
7
|
+
"ends_on" date NOT NULL,
|
|
8
|
+
"status" text DEFAULT 'open' NOT NULL,
|
|
9
|
+
"locked_at" timestamp with time zone,
|
|
10
|
+
"locked_by" uuid,
|
|
11
|
+
"note" text,
|
|
12
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
13
|
+
);
|
|
14
|
+
--> statement-breakpoint
|
|
15
|
+
CREATE TABLE "mod_hr"."policies" (
|
|
16
|
+
"id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
|
|
17
|
+
"workspace_id" uuid NOT NULL,
|
|
18
|
+
"kind" text NOT NULL,
|
|
19
|
+
"name" text NOT NULL,
|
|
20
|
+
"config" jsonb NOT NULL,
|
|
21
|
+
"effective_from" date NOT NULL,
|
|
22
|
+
"effective_to" date,
|
|
23
|
+
"source" text DEFAULT 'custom' NOT NULL,
|
|
24
|
+
"pack_key" text,
|
|
25
|
+
"config_hash" text DEFAULT '' NOT NULL,
|
|
26
|
+
"archived_at" timestamp with time zone,
|
|
27
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
28
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
29
|
+
);
|
|
30
|
+
--> statement-breakpoint
|
|
31
|
+
CREATE TABLE "mod_hr"."policy_assignments" (
|
|
32
|
+
"id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
|
|
33
|
+
"workspace_id" uuid NOT NULL,
|
|
34
|
+
"policy_id" uuid NOT NULL,
|
|
35
|
+
"subject_kind" text NOT NULL,
|
|
36
|
+
"subject_id" uuid,
|
|
37
|
+
"effective_from" date NOT NULL,
|
|
38
|
+
"effective_to" date,
|
|
39
|
+
"priority" integer DEFAULT 0 NOT NULL,
|
|
40
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
41
|
+
);
|
|
42
|
+
--> statement-breakpoint
|
|
43
|
+
CREATE INDEX "hr_periods_idx" ON "mod_hr"."periods" USING btree ("workspace_id","kind","starts_on");--> statement-breakpoint
|
|
44
|
+
CREATE INDEX "hr_policies_ws_kind_idx" ON "mod_hr"."policies" USING btree ("workspace_id","kind","effective_from");--> statement-breakpoint
|
|
45
|
+
CREATE INDEX "hr_policy_assign_idx" ON "mod_hr"."policy_assignments" USING btree ("workspace_id","subject_kind","subject_id");--> statement-breakpoint
|
|
46
|
+
CREATE INDEX "hr_policy_assign_policy_idx" ON "mod_hr"."policy_assignments" USING btree ("workspace_id","policy_id");--> statement-breakpoint
|
|
47
|
+
-- Row-level security on the policy and period tables.
|
|
48
|
+
alter table "mod_hr"."policies" enable row level security;--> statement-breakpoint
|
|
49
|
+
alter table "mod_hr"."policies" force row level security;--> statement-breakpoint
|
|
50
|
+
create policy "policies_ws_isolation" on "mod_hr"."policies"
|
|
51
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
52
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
53
|
+
|
|
54
|
+
alter table "mod_hr"."policy_assignments" enable row level security;--> statement-breakpoint
|
|
55
|
+
alter table "mod_hr"."policy_assignments" force row level security;--> statement-breakpoint
|
|
56
|
+
create policy "policy_assignments_ws_isolation" on "mod_hr"."policy_assignments"
|
|
57
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
58
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
59
|
+
|
|
60
|
+
alter table "mod_hr"."periods" enable row level security;--> statement-breakpoint
|
|
61
|
+
alter table "mod_hr"."periods" force row level security;--> statement-breakpoint
|
|
62
|
+
create policy "periods_ws_isolation" on "mod_hr"."periods"
|
|
63
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
64
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
65
|
+
|
|
66
|
+
-- One assignment of a policy at a rung over a period.
|
|
67
|
+
--
|
|
68
|
+
-- Without this, two overlapping assignments at the same priority resolve arbitrarily: the ladder
|
|
69
|
+
-- has a tie it cannot break, and which policy applies depends on row order. That is the kind of bug
|
|
70
|
+
-- that shows up as two people on the same terms accruing differently.
|
|
71
|
+
alter table "mod_hr"."policy_assignments"
|
|
72
|
+
add constraint "hr_policy_assign_no_overlap"
|
|
73
|
+
exclude using gist (
|
|
74
|
+
policy_id with =,
|
|
75
|
+
subject_kind with =,
|
|
76
|
+
coalesce(subject_id, '00000000-0000-0000-0000-000000000000'::uuid) with =,
|
|
77
|
+
daterange(effective_from, effective_to, '[]') with &&
|
|
78
|
+
);--> statement-breakpoint
|
|
79
|
+
|
|
80
|
+
-- Two periods of a kind may not cover the same day for the same entity: "is this date locked" has
|
|
81
|
+
-- to have exactly one answer.
|
|
82
|
+
alter table "mod_hr"."periods"
|
|
83
|
+
add constraint "hr_periods_no_overlap"
|
|
84
|
+
exclude using gist (
|
|
85
|
+
kind with =,
|
|
86
|
+
workspace_id with =,
|
|
87
|
+
coalesce(legal_entity_id, '00000000-0000-0000-0000-000000000000'::uuid) with =,
|
|
88
|
+
daterange(starts_on, ends_on, '[]') with &&
|
|
89
|
+
);
|