@kernhq/module-hr 0.1.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/LICENSE +662 -0
- package/README.md +71 -0
- package/dist/contract/capabilities.d.ts +45 -0
- package/dist/contract/capabilities.d.ts.map +1 -0
- package/dist/contract/capabilities.js +114 -0
- package/dist/contract/capabilities.js.map +1 -0
- package/dist/contract/events.d.ts +74 -0
- package/dist/contract/events.d.ts.map +1 -0
- package/dist/contract/events.js +63 -0
- package/dist/contract/events.js.map +1 -0
- package/dist/contract/index.d.ts +15 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +15 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/contract/models.d.ts +457 -0
- package/dist/contract/models.d.ts.map +1 -0
- package/dist/contract/models.js +381 -0
- package/dist/contract/models.js.map +1 -0
- package/dist/contract/permissions.d.ts +174 -0
- package/dist/contract/permissions.d.ts.map +1 -0
- package/dist/contract/permissions.js +209 -0
- package/dist/contract/permissions.js.map +1 -0
- package/dist/contract/router.d.ts +2720 -0
- package/dist/contract/router.d.ts.map +1 -0
- package/dist/contract/router.js +520 -0
- package/dist/contract/router.js.map +1 -0
- package/dist/contract/settings.d.ts +20 -0
- package/dist/contract/settings.d.ts.map +1 -0
- package/dist/contract/settings.js +34 -0
- package/dist/contract/settings.js.map +1 -0
- package/dist/policy/calendar.d.ts +64 -0
- package/dist/policy/calendar.d.ts.map +1 -0
- package/dist/policy/calendar.js +113 -0
- package/dist/policy/calendar.js.map +1 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +141 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/packs/index.d.ts +50 -0
- package/dist/server/packs/index.d.ts.map +1 -0
- package/dist/server/packs/index.js +121 -0
- package/dist/server/packs/index.js.map +1 -0
- package/dist/server/router.d.ts +3095 -0
- package/dist/server/router.d.ts.map +1 -0
- package/dist/server/router.js +1537 -0
- package/dist/server/router.js.map +1 -0
- package/dist/server/schema.d.ts +2828 -0
- package/dist/server/schema.d.ts.map +1 -0
- package/dist/server/schema.js +313 -0
- package/dist/server/schema.js.map +1 -0
- package/dist/server/services/db.d.ts +22 -0
- package/dist/server/services/db.d.ts.map +1 -0
- package/dist/server/services/db.js +23 -0
- package/dist/server/services/db.js.map +1 -0
- package/dist/server/services/people.d.ts +110 -0
- package/dist/server/services/people.d.ts.map +1 -0
- package/dist/server/services/people.js +182 -0
- package/dist/server/services/people.js.map +1 -0
- package/dist/server/services/resolve.d.ts +66 -0
- package/dist/server/services/resolve.d.ts.map +1 -0
- package/dist/server/services/resolve.js +145 -0
- package/dist/server/services/resolve.js.map +1 -0
- package/migrations/0000_init.sql +223 -0
- package/migrations/0001_rls.sql +141 -0
- package/migrations/meta/0000_snapshot.json +1715 -0
- package/migrations/meta/_journal.json +20 -0
- package/package.json +59 -0
- package/src/client/index.ts +62 -0
- package/src/contract/capabilities.ts +117 -0
- package/src/contract/events.ts +84 -0
- package/src/contract/index.ts +14 -0
- package/src/contract/models.ts +437 -0
- package/src/contract/permissions.ts +217 -0
- package/src/contract/router.ts +611 -0
- package/src/contract/settings.ts +35 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
-- Row-level security, plus the constraints that carry this module's real invariants.
|
|
2
|
+
--
|
|
3
|
+
-- RLS is the last line, not the first: the API checks membership and permission before anything
|
|
4
|
+
-- reaches here. It exists for the query that skips them — a job, a report, a mistake — and for
|
|
5
|
+
-- anyone who reaches the database another way. A tenant table without a policy is simply readable.
|
|
6
|
+
--
|
|
7
|
+
-- Superusers bypass RLS, so a database owned by one will pass a test that proves nothing. Run the
|
|
8
|
+
-- application as a plain role.
|
|
9
|
+
|
|
10
|
+
alter table "mod_hr"."legal_entities" enable row level security;--> statement-breakpoint
|
|
11
|
+
alter table "mod_hr"."legal_entities" force row level security;--> statement-breakpoint
|
|
12
|
+
create policy "legal_entities_ws_isolation" on "mod_hr"."legal_entities"
|
|
13
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
14
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
15
|
+
|
|
16
|
+
alter table "mod_hr"."offices" enable row level security;--> statement-breakpoint
|
|
17
|
+
alter table "mod_hr"."offices" force row level security;--> statement-breakpoint
|
|
18
|
+
create policy "offices_ws_isolation" on "mod_hr"."offices"
|
|
19
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
20
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
21
|
+
|
|
22
|
+
alter table "mod_hr"."cost_centers" enable row level security;--> statement-breakpoint
|
|
23
|
+
alter table "mod_hr"."cost_centers" force row level security;--> statement-breakpoint
|
|
24
|
+
create policy "cost_centers_ws_isolation" on "mod_hr"."cost_centers"
|
|
25
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
26
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
27
|
+
|
|
28
|
+
alter table "mod_hr"."org_units" enable row level security;--> statement-breakpoint
|
|
29
|
+
alter table "mod_hr"."org_units" force row level security;--> statement-breakpoint
|
|
30
|
+
create policy "org_units_ws_isolation" on "mod_hr"."org_units"
|
|
31
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
32
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
33
|
+
|
|
34
|
+
alter table "mod_hr"."positions" enable row level security;--> statement-breakpoint
|
|
35
|
+
alter table "mod_hr"."positions" force row level security;--> statement-breakpoint
|
|
36
|
+
create policy "positions_ws_isolation" on "mod_hr"."positions"
|
|
37
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
38
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
39
|
+
|
|
40
|
+
alter table "mod_hr"."people" enable row level security;--> statement-breakpoint
|
|
41
|
+
alter table "mod_hr"."people" force row level security;--> statement-breakpoint
|
|
42
|
+
create policy "people_ws_isolation" on "mod_hr"."people"
|
|
43
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
44
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
45
|
+
|
|
46
|
+
alter table "mod_hr"."people_sensitive" enable row level security;--> statement-breakpoint
|
|
47
|
+
alter table "mod_hr"."people_sensitive" force row level security;--> statement-breakpoint
|
|
48
|
+
create policy "people_sensitive_ws_isolation" on "mod_hr"."people_sensitive"
|
|
49
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
50
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
51
|
+
|
|
52
|
+
alter table "mod_hr"."employments" enable row level security;--> statement-breakpoint
|
|
53
|
+
alter table "mod_hr"."employments" force row level security;--> statement-breakpoint
|
|
54
|
+
create policy "employments_ws_isolation" on "mod_hr"."employments"
|
|
55
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
56
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
57
|
+
|
|
58
|
+
alter table "mod_hr"."office_assignments" enable row level security;--> statement-breakpoint
|
|
59
|
+
alter table "mod_hr"."office_assignments" force row level security;--> statement-breakpoint
|
|
60
|
+
create policy "office_assignments_ws_isolation" on "mod_hr"."office_assignments"
|
|
61
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
62
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
63
|
+
|
|
64
|
+
alter table "mod_hr"."person_history" enable row level security;--> statement-breakpoint
|
|
65
|
+
alter table "mod_hr"."person_history" force row level security;--> statement-breakpoint
|
|
66
|
+
create policy "person_history_ws_isolation" on "mod_hr"."person_history"
|
|
67
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
68
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
69
|
+
|
|
70
|
+
alter table "mod_hr"."person_documents" enable row level security;--> statement-breakpoint
|
|
71
|
+
alter table "mod_hr"."person_documents" force row level security;--> statement-breakpoint
|
|
72
|
+
create policy "person_documents_ws_isolation" on "mod_hr"."person_documents"
|
|
73
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
74
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
75
|
+
|
|
76
|
+
alter table "mod_hr"."custom_field_defs" enable row level security;--> statement-breakpoint
|
|
77
|
+
alter table "mod_hr"."custom_field_defs" force row level security;--> statement-breakpoint
|
|
78
|
+
create policy "custom_field_defs_ws_isolation" on "mod_hr"."custom_field_defs"
|
|
79
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
80
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
81
|
+
|
|
82
|
+
alter table "mod_hr"."calendars" enable row level security;--> statement-breakpoint
|
|
83
|
+
alter table "mod_hr"."calendars" force row level security;--> statement-breakpoint
|
|
84
|
+
create policy "calendars_ws_isolation" on "mod_hr"."calendars"
|
|
85
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
86
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
87
|
+
|
|
88
|
+
alter table "mod_hr"."calendar_days" enable row level security;--> statement-breakpoint
|
|
89
|
+
alter table "mod_hr"."calendar_days" force row level security;--> statement-breakpoint
|
|
90
|
+
create policy "calendar_days_ws_isolation" on "mod_hr"."calendar_days"
|
|
91
|
+
using (workspace_id::text = current_setting('app.workspace_id', true))
|
|
92
|
+
with check (workspace_id::text = current_setting('app.workspace_id', true));--> statement-breakpoint
|
|
93
|
+
|
|
94
|
+
-- ---------------------------------------------------------------------------------------------
|
|
95
|
+
-- The invariants, in the database rather than in application code.
|
|
96
|
+
--
|
|
97
|
+
-- Every one of these is something two concurrent requests could otherwise both "win". Enforcing
|
|
98
|
+
-- them here means the loser gets a constraint violation instead of the system holding two
|
|
99
|
+
-- contradictory answers to a question an auditor will eventually ask.
|
|
100
|
+
|
|
101
|
+
create extension if not exists btree_gist;--> statement-breakpoint
|
|
102
|
+
|
|
103
|
+
-- One workspace, one default office. It is where a person with no assignment lands and where the
|
|
104
|
+
-- resolution ladder bottoms out, so two of them would make "which calendar applies" ambiguous.
|
|
105
|
+
create unique index "hr_offices_one_default_per_ws"
|
|
106
|
+
on "mod_hr"."offices" (workspace_id)
|
|
107
|
+
where is_default;--> statement-breakpoint
|
|
108
|
+
|
|
109
|
+
-- No two employment rows for one person may overlap. Without this, a backdated correction racing a
|
|
110
|
+
-- forward-dated change leaves two rows in force on the same day, and "what was her FTE in March"
|
|
111
|
+
-- has two answers.
|
|
112
|
+
alter table "mod_hr"."employments"
|
|
113
|
+
add constraint "hr_employments_no_overlap"
|
|
114
|
+
exclude using gist (
|
|
115
|
+
person_id with =,
|
|
116
|
+
daterange(effective_from, effective_to, '[]') with &&
|
|
117
|
+
);--> statement-breakpoint
|
|
118
|
+
|
|
119
|
+
-- Nor may one person hold the same office twice over an overlapping period.
|
|
120
|
+
alter table "mod_hr"."office_assignments"
|
|
121
|
+
add constraint "hr_office_assignments_no_duplicate"
|
|
122
|
+
exclude using gist (
|
|
123
|
+
person_id with =,
|
|
124
|
+
office_id with =,
|
|
125
|
+
daterange(effective_from, effective_to, '[]') with &&
|
|
126
|
+
);--> statement-breakpoint
|
|
127
|
+
|
|
128
|
+
-- And exactly one of a person's concurrent assignments may be primary. Only the primary office
|
|
129
|
+
-- decides holidays, timezone and policy; two would mean two answers, which is the one thing the
|
|
130
|
+
-- multi-office model must never allow.
|
|
131
|
+
alter table "mod_hr"."office_assignments"
|
|
132
|
+
add constraint "hr_office_assignments_one_primary"
|
|
133
|
+
exclude using gist (
|
|
134
|
+
person_id with =,
|
|
135
|
+
daterange(effective_from, effective_to, '[]') with &&
|
|
136
|
+
) where (is_primary);--> statement-breakpoint
|
|
137
|
+
|
|
138
|
+
-- An org unit's ltree path is unique within a workspace: two departments at the same path would
|
|
139
|
+
-- make a subtree query return one of them arbitrarily.
|
|
140
|
+
create unique index "hr_org_units_ws_path_uq" on "mod_hr"."org_units" (workspace_id, path);--> statement-breakpoint
|
|
141
|
+
create index "hr_org_units_path_gist" on "mod_hr"."org_units" using gist (path);
|