@company-semantics/contracts 13.20.0 → 15.0.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/package.json +2 -2
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +49 -87
- package/src/email/types.ts +1 -1
- package/src/generated/openapi-routes.ts +1 -1
- package/src/identity/index.ts +0 -4
- package/src/identity/people-org-chart.ts +11 -26
- package/src/index.ts +0 -4
- package/src/org/__tests__/org-units.test.ts +1 -4
- package/src/org/schemas.ts +4 -10
- package/src/permissions/orgchart-roles.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@company-semantics/contracts",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "15.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"zod": "^4.4.3"
|
|
120
120
|
},
|
|
121
121
|
"devDependencies": {
|
|
122
|
-
"@types/node": "^
|
|
122
|
+
"@types/node": "^22.10.0",
|
|
123
123
|
"husky": "^9.1.7",
|
|
124
124
|
"lint-staged": "^17.0.7",
|
|
125
125
|
"markdownlint-cli2": "^0.22.1",
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit. Run pnpm generate:spec-hash to regenerate.
|
|
2
|
-
export const SPEC_HASH = '
|
|
3
|
-
export const SPEC_HASH_FULL = '
|
|
2
|
+
export const SPEC_HASH = '16c3b86cc35a' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = '16c3b86cc35a3f329766b702414438de4950430991a603372f1335206c96b600' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -1972,24 +1972,6 @@ export interface paths {
|
|
|
1972
1972
|
patch?: never;
|
|
1973
1973
|
trace?: never;
|
|
1974
1974
|
};
|
|
1975
|
-
"/api/org-units/{unitId}/head": {
|
|
1976
|
-
parameters: {
|
|
1977
|
-
query?: never;
|
|
1978
|
-
header?: never;
|
|
1979
|
-
path?: never;
|
|
1980
|
-
cookie?: never;
|
|
1981
|
-
};
|
|
1982
|
-
get?: never;
|
|
1983
|
-
/** Pin an explicit head (anchor person) for an org unit */
|
|
1984
|
-
put: operations["setOrgUnitHead"];
|
|
1985
|
-
post?: never;
|
|
1986
|
-
/** Revert an org unit head to the system-inferred default */
|
|
1987
|
-
delete: operations["revertOrgUnitHead"];
|
|
1988
|
-
options?: never;
|
|
1989
|
-
head?: never;
|
|
1990
|
-
patch?: never;
|
|
1991
|
-
trace?: never;
|
|
1992
|
-
};
|
|
1993
1975
|
"/api/org-units/{unitId}/my-authority": {
|
|
1994
1976
|
parameters: {
|
|
1995
1977
|
query?: never;
|
|
@@ -2111,6 +2093,23 @@ export interface paths {
|
|
|
2111
2093
|
patch?: never;
|
|
2112
2094
|
trace?: never;
|
|
2113
2095
|
};
|
|
2096
|
+
"/api/org-units/{unitId}/open-roles/{roleId}/reports-to": {
|
|
2097
|
+
parameters: {
|
|
2098
|
+
query?: never;
|
|
2099
|
+
header?: never;
|
|
2100
|
+
path?: never;
|
|
2101
|
+
cookie?: never;
|
|
2102
|
+
};
|
|
2103
|
+
get?: never;
|
|
2104
|
+
/** Set or clear an open role's own reporting edge */
|
|
2105
|
+
put: operations["setOrgUnitOpenRoleReportsTo"];
|
|
2106
|
+
post?: never;
|
|
2107
|
+
delete?: never;
|
|
2108
|
+
options?: never;
|
|
2109
|
+
head?: never;
|
|
2110
|
+
patch?: never;
|
|
2111
|
+
trace?: never;
|
|
2112
|
+
};
|
|
2114
2113
|
"/api/users/org-chart": {
|
|
2115
2114
|
parameters: {
|
|
2116
2115
|
query?: never;
|
|
@@ -4322,8 +4321,6 @@ export interface components {
|
|
|
4322
4321
|
count: number;
|
|
4323
4322
|
userIds: string[];
|
|
4324
4323
|
} | null;
|
|
4325
|
-
headUserId: string | null;
|
|
4326
|
-
headOrigin: ("user" | "inferred") | null;
|
|
4327
4324
|
}[];
|
|
4328
4325
|
};
|
|
4329
4326
|
OrgUnitDescendantsResponse: {
|
|
@@ -4472,8 +4469,6 @@ export interface components {
|
|
|
4472
4469
|
count: number;
|
|
4473
4470
|
userIds: string[];
|
|
4474
4471
|
} | null;
|
|
4475
|
-
headUserId: string | null;
|
|
4476
|
-
headOrigin: ("user" | "inferred") | null;
|
|
4477
4472
|
}[];
|
|
4478
4473
|
levelConfig: {
|
|
4479
4474
|
/** Format: uuid */
|
|
@@ -4618,12 +4613,6 @@ export interface components {
|
|
|
4618
4613
|
revokedAt: string | null;
|
|
4619
4614
|
reason: string | null;
|
|
4620
4615
|
};
|
|
4621
|
-
UnitHeadResponse: {
|
|
4622
|
-
/** Format: uuid */
|
|
4623
|
-
unitId: string;
|
|
4624
|
-
headUserId: string | null;
|
|
4625
|
-
origin: ("user" | "inferred") | null;
|
|
4626
|
-
};
|
|
4627
4616
|
OrgUnitMyAuthorityResponse: {
|
|
4628
4617
|
/** Format: uuid */
|
|
4629
4618
|
unitId: string;
|
|
@@ -4693,6 +4682,7 @@ export interface components {
|
|
|
4693
4682
|
/** @enum {string} */
|
|
4694
4683
|
status: "open" | "hiring" | "filled" | "closed";
|
|
4695
4684
|
filledByUserId: string | null;
|
|
4685
|
+
reportsToUserId: string | null;
|
|
4696
4686
|
createdAt: string;
|
|
4697
4687
|
updatedAt: string;
|
|
4698
4688
|
}[];
|
|
@@ -4710,6 +4700,7 @@ export interface components {
|
|
|
4710
4700
|
/** @enum {string} */
|
|
4711
4701
|
status: "open" | "hiring" | "filled" | "closed";
|
|
4712
4702
|
filledByUserId: string | null;
|
|
4703
|
+
reportsToUserId: string | null;
|
|
4713
4704
|
createdAt: string;
|
|
4714
4705
|
updatedAt: string;
|
|
4715
4706
|
};
|
|
@@ -4737,14 +4728,7 @@ export interface components {
|
|
|
4737
4728
|
/** Format: uuid */
|
|
4738
4729
|
unitId: string;
|
|
4739
4730
|
title: string | null;
|
|
4740
|
-
|
|
4741
|
-
unitHeads: {
|
|
4742
|
-
/** Format: uuid */
|
|
4743
|
-
unitId: string;
|
|
4744
|
-
/** Format: uuid */
|
|
4745
|
-
headUserId: string;
|
|
4746
|
-
/** @enum {string} */
|
|
4747
|
-
origin: "user" | "inferred";
|
|
4731
|
+
reportsToUserId: string | null;
|
|
4748
4732
|
}[];
|
|
4749
4733
|
};
|
|
4750
4734
|
/** @description Polling snapshot of a generic ingestion operation. */
|
|
@@ -8497,57 +8481,6 @@ export interface operations {
|
|
|
8497
8481
|
};
|
|
8498
8482
|
};
|
|
8499
8483
|
};
|
|
8500
|
-
setOrgUnitHead: {
|
|
8501
|
-
parameters: {
|
|
8502
|
-
query?: never;
|
|
8503
|
-
header?: never;
|
|
8504
|
-
path: {
|
|
8505
|
-
unitId: string;
|
|
8506
|
-
};
|
|
8507
|
-
cookie?: never;
|
|
8508
|
-
};
|
|
8509
|
-
requestBody: {
|
|
8510
|
-
content: {
|
|
8511
|
-
"application/json": {
|
|
8512
|
-
/** Format: uuid */
|
|
8513
|
-
userId: string;
|
|
8514
|
-
};
|
|
8515
|
-
};
|
|
8516
|
-
};
|
|
8517
|
-
responses: {
|
|
8518
|
-
/** @description The pinned unit head */
|
|
8519
|
-
200: {
|
|
8520
|
-
headers: {
|
|
8521
|
-
[name: string]: unknown;
|
|
8522
|
-
};
|
|
8523
|
-
content: {
|
|
8524
|
-
"application/json": components["schemas"]["UnitHeadResponse"];
|
|
8525
|
-
};
|
|
8526
|
-
};
|
|
8527
|
-
};
|
|
8528
|
-
};
|
|
8529
|
-
revertOrgUnitHead: {
|
|
8530
|
-
parameters: {
|
|
8531
|
-
query?: never;
|
|
8532
|
-
header?: never;
|
|
8533
|
-
path: {
|
|
8534
|
-
unitId: string;
|
|
8535
|
-
};
|
|
8536
|
-
cookie?: never;
|
|
8537
|
-
};
|
|
8538
|
-
requestBody?: never;
|
|
8539
|
-
responses: {
|
|
8540
|
-
/** @description The re-inferred unit head (or null when none resolves) */
|
|
8541
|
-
200: {
|
|
8542
|
-
headers: {
|
|
8543
|
-
[name: string]: unknown;
|
|
8544
|
-
};
|
|
8545
|
-
content: {
|
|
8546
|
-
"application/json": components["schemas"]["UnitHeadResponse"];
|
|
8547
|
-
};
|
|
8548
|
-
};
|
|
8549
|
-
};
|
|
8550
|
-
};
|
|
8551
8484
|
getMyOrgUnitAuthority: {
|
|
8552
8485
|
parameters: {
|
|
8553
8486
|
query?: never;
|
|
@@ -8794,6 +8727,35 @@ export interface operations {
|
|
|
8794
8727
|
};
|
|
8795
8728
|
};
|
|
8796
8729
|
};
|
|
8730
|
+
setOrgUnitOpenRoleReportsTo: {
|
|
8731
|
+
parameters: {
|
|
8732
|
+
query?: never;
|
|
8733
|
+
header?: never;
|
|
8734
|
+
path: {
|
|
8735
|
+
unitId: string;
|
|
8736
|
+
roleId: string;
|
|
8737
|
+
};
|
|
8738
|
+
cookie?: never;
|
|
8739
|
+
};
|
|
8740
|
+
requestBody: {
|
|
8741
|
+
content: {
|
|
8742
|
+
"application/json": {
|
|
8743
|
+
userId: string | null;
|
|
8744
|
+
};
|
|
8745
|
+
};
|
|
8746
|
+
};
|
|
8747
|
+
responses: {
|
|
8748
|
+
/** @description Open role with updated reporting edge */
|
|
8749
|
+
200: {
|
|
8750
|
+
headers: {
|
|
8751
|
+
[name: string]: unknown;
|
|
8752
|
+
};
|
|
8753
|
+
content: {
|
|
8754
|
+
"application/json": components["schemas"]["OpenRoleResponse"];
|
|
8755
|
+
};
|
|
8756
|
+
};
|
|
8757
|
+
};
|
|
8758
|
+
};
|
|
8797
8759
|
getPeopleOrgChart: {
|
|
8798
8760
|
parameters: {
|
|
8799
8761
|
query?: never;
|
package/src/email/types.ts
CHANGED
|
@@ -70,7 +70,7 @@ export interface EmailPayloads {
|
|
|
70
70
|
/** Name of the org unit / team the access applies to */
|
|
71
71
|
unitName: string;
|
|
72
72
|
/** Human-readable role label the recipient was given */
|
|
73
|
-
roleLabel: "
|
|
73
|
+
roleLabel: "Unit owner" | "Delegate";
|
|
74
74
|
/** Full URL to view the org unit in the app */
|
|
75
75
|
ctaUrl: string;
|
|
76
76
|
/** Optional message from the granter, shown in the email and recorded with the grant */
|
|
@@ -82,7 +82,6 @@ export const openApiRoutes = {
|
|
|
82
82
|
'/api/org-units/{unitId}/delegations': ['POST'],
|
|
83
83
|
'/api/org-units/{unitId}/delegations/{id}': ['DELETE', 'PATCH'],
|
|
84
84
|
'/api/org-units/{unitId}/descendants': ['GET'],
|
|
85
|
-
'/api/org-units/{unitId}/head': ['DELETE', 'PUT'],
|
|
86
85
|
'/api/org-units/{unitId}/memberships': ['GET', 'POST'],
|
|
87
86
|
'/api/org-units/{unitId}/memberships/{userId}': ['DELETE'],
|
|
88
87
|
'/api/org-units/{unitId}/memberships/{userId}/role': ['PUT'],
|
|
@@ -90,6 +89,7 @@ export const openApiRoutes = {
|
|
|
90
89
|
'/api/org-units/{unitId}/open-roles': ['GET', 'POST'],
|
|
91
90
|
'/api/org-units/{unitId}/open-roles/{roleId}': ['PATCH'],
|
|
92
91
|
'/api/org-units/{unitId}/open-roles/{roleId}/fill': ['POST'],
|
|
92
|
+
'/api/org-units/{unitId}/open-roles/{roleId}/reports-to': ['PUT'],
|
|
93
93
|
'/api/org-units/{unitId}/owners': ['GET'],
|
|
94
94
|
'/api/org-units/{unitId}/permissions': ['GET'],
|
|
95
95
|
'/api/org-units/{unitId}/relationships': ['GET', 'POST'],
|
package/src/identity/index.ts
CHANGED
|
@@ -67,8 +67,6 @@ export {
|
|
|
67
67
|
PeopleOrgChartNodeSchema,
|
|
68
68
|
PeopleOrgChartEdgeSchema,
|
|
69
69
|
PeopleOrgChartOpenRoleSchema,
|
|
70
|
-
UnitHeadOriginSchema,
|
|
71
|
-
PeopleOrgChartUnitHeadSchema,
|
|
72
70
|
PeopleOrgChartResponseSchema,
|
|
73
71
|
} from "./people-org-chart";
|
|
74
72
|
export type {
|
|
@@ -76,7 +74,5 @@ export type {
|
|
|
76
74
|
PeopleOrgChartNode,
|
|
77
75
|
PeopleOrgChartEdge,
|
|
78
76
|
PeopleOrgChartOpenRole,
|
|
79
|
-
UnitHeadOrigin,
|
|
80
|
-
PeopleOrgChartUnitHead,
|
|
81
77
|
PeopleOrgChartResponse,
|
|
82
78
|
} from "./people-org-chart";
|
|
@@ -52,52 +52,37 @@ export type PeopleOrgChartEdge = z.infer<typeof PeopleOrgChartEdgeSchema>;
|
|
|
52
52
|
// Open role — a persisted placeholder seat rendered as a dashed "Open role"
|
|
53
53
|
// card in its unit's sibling column. Only active roles (open + hiring) are
|
|
54
54
|
// included; filled/closed roles never appear here. `unitId` seats the card in
|
|
55
|
-
// the right column
|
|
56
|
-
//
|
|
55
|
+
// the right column. `reportsToUserId` is the open role's OWN reporting edge
|
|
56
|
+
// (ADR-BE-291): it defaults to the role's creator and is editable/clearable, so
|
|
57
|
+
// a person-less seat is placed by reporting like everyone else (the chart owns
|
|
58
|
+
// placement, ADR-CTRL-159). Null → the role hangs in its unit's projection-only
|
|
59
|
+
// Unassigned bucket. This replaces the retired unit-head anchor (ADR-BE-284).
|
|
57
60
|
// ---------------------------------------------------------------------------
|
|
58
61
|
|
|
59
62
|
export const PeopleOrgChartOpenRoleSchema = z.object({
|
|
60
63
|
id: z.string().uuid(),
|
|
61
64
|
unitId: z.string().uuid(),
|
|
62
65
|
title: z.string().nullable(),
|
|
66
|
+
reportsToUserId: z.string().uuid().nullable(),
|
|
63
67
|
});
|
|
64
68
|
|
|
65
69
|
export type PeopleOrgChartOpenRole = z.infer<
|
|
66
70
|
typeof PeopleOrgChartOpenRoleSchema
|
|
67
71
|
>;
|
|
68
72
|
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
// Unit head — the person a unit (and its person-less children: empty-unit
|
|
71
|
-
// placeholders, pending-invite ghosts, open-role seats) anchors under in the
|
|
72
|
-
// people chart. A presentation/anchor "tether" (ADR-BE-284), NOT authority.
|
|
73
|
-
// `origin` distinguishes an explicit user choice from a system-inferred default
|
|
74
|
-
// so the UI can render "Pinned" vs "Auto" and offer revert-to-auto. The client
|
|
75
|
-
// prefers the head of a unit's PARENT when anchoring its person-less children,
|
|
76
|
-
// falling back to the render-time heuristic only when no head row exists.
|
|
77
|
-
// ---------------------------------------------------------------------------
|
|
78
|
-
|
|
79
|
-
export const UnitHeadOriginSchema = z.enum(["user", "inferred"]);
|
|
80
|
-
export type UnitHeadOrigin = z.infer<typeof UnitHeadOriginSchema>;
|
|
81
|
-
|
|
82
|
-
export const PeopleOrgChartUnitHeadSchema = z.object({
|
|
83
|
-
unitId: z.string().uuid(),
|
|
84
|
-
headUserId: z.string().uuid(),
|
|
85
|
-
origin: UnitHeadOriginSchema,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
export type PeopleOrgChartUnitHead = z.infer<
|
|
89
|
-
typeof PeopleOrgChartUnitHeadSchema
|
|
90
|
-
>;
|
|
91
|
-
|
|
92
73
|
// ---------------------------------------------------------------------------
|
|
93
74
|
// GET /api/users/org-chart
|
|
94
75
|
// ---------------------------------------------------------------------------
|
|
76
|
+
//
|
|
77
|
+
// Person-less cards (empty-unit placeholders, ghosts, open roles) no longer
|
|
78
|
+
// anchor under a stored unit-head "tether" (ADR-BE-284, retired by ADR-BE-292).
|
|
79
|
+
// Open roles carry their own `reportsToUserId` edge; placeholders fall back to
|
|
80
|
+
// the render-time reporting heuristic.
|
|
95
81
|
|
|
96
82
|
export const PeopleOrgChartResponseSchema = z.object({
|
|
97
83
|
nodes: z.array(PeopleOrgChartNodeSchema),
|
|
98
84
|
edges: z.array(PeopleOrgChartEdgeSchema),
|
|
99
85
|
openRoles: z.array(PeopleOrgChartOpenRoleSchema),
|
|
100
|
-
unitHeads: z.array(PeopleOrgChartUnitHeadSchema),
|
|
101
86
|
});
|
|
102
87
|
|
|
103
88
|
export type PeopleOrgChartResponse = z.infer<
|
package/src/index.ts
CHANGED
|
@@ -173,8 +173,6 @@ export {
|
|
|
173
173
|
PeopleOrgChartNodeSchema,
|
|
174
174
|
PeopleOrgChartEdgeSchema,
|
|
175
175
|
PeopleOrgChartOpenRoleSchema,
|
|
176
|
-
UnitHeadOriginSchema,
|
|
177
|
-
PeopleOrgChartUnitHeadSchema,
|
|
178
176
|
PeopleOrgChartResponseSchema,
|
|
179
177
|
} from "./identity/index";
|
|
180
178
|
export type {
|
|
@@ -182,8 +180,6 @@ export type {
|
|
|
182
180
|
PeopleOrgChartNode,
|
|
183
181
|
PeopleOrgChartEdge,
|
|
184
182
|
PeopleOrgChartOpenRole,
|
|
185
|
-
UnitHeadOrigin,
|
|
186
|
-
PeopleOrgChartUnitHead,
|
|
187
183
|
PeopleOrgChartResponse,
|
|
188
184
|
} from "./identity/index";
|
|
189
185
|
|
|
@@ -98,8 +98,6 @@ describe("OrgUnitTreeNodeSchema", () => {
|
|
|
98
98
|
memberCount: 5,
|
|
99
99
|
openRoleCount: 1,
|
|
100
100
|
missingAtNextLevel: null,
|
|
101
|
-
headUserId: null,
|
|
102
|
-
headOrigin: null,
|
|
103
101
|
};
|
|
104
102
|
expect(() => OrgUnitTreeNodeSchema.parse(base)).not.toThrow();
|
|
105
103
|
expect(() => OrgUnitTreeNodeSchema.parse({ ...base, depth: 0 })).toThrow();
|
|
@@ -114,8 +112,6 @@ describe("OrgUnitTreeNodeSchema", () => {
|
|
|
114
112
|
memberCount: 5,
|
|
115
113
|
openRoleCount: 0,
|
|
116
114
|
missingAtNextLevel: null,
|
|
117
|
-
headUserId: null,
|
|
118
|
-
headOrigin: null,
|
|
119
115
|
};
|
|
120
116
|
expect(() => OrgUnitTreeNodeSchema.parse(base)).not.toThrow();
|
|
121
117
|
expect(() =>
|
|
@@ -133,6 +129,7 @@ describe("OpenRoleSchema", () => {
|
|
|
133
129
|
targetStartDate: "2026-09-01",
|
|
134
130
|
status: "open",
|
|
135
131
|
filledByUserId: null,
|
|
132
|
+
reportsToUserId: null,
|
|
136
133
|
createdAt: "2026-04-17T00:00:00Z",
|
|
137
134
|
updatedAt: "2026-04-17T00:00:00Z",
|
|
138
135
|
...overrides,
|
package/src/org/schemas.ts
CHANGED
|
@@ -949,16 +949,6 @@ export const OrgUnitTreeNodeSchema = OrgUnitSchema.extend({
|
|
|
949
949
|
*/
|
|
950
950
|
openRoleCount: z.number().int().min(0),
|
|
951
951
|
missingAtNextLevel: MissingAtNextLevelSchema.nullable(),
|
|
952
|
-
/**
|
|
953
|
-
* The unit head (ADR-BE-284): the person this unit (and its person-less
|
|
954
|
-
* children) anchors under in the people chart — a presentation "tether", NOT
|
|
955
|
-
* authority. `headUserId` is null when no head is resolved (e.g. an empty
|
|
956
|
-
* unit with no members). `headOrigin` is `'user'` for an explicit choice,
|
|
957
|
-
* `'inferred'` for a system default (so the management UI can show Pinned vs
|
|
958
|
-
* Auto and offer revert-to-auto), or null when there is no head.
|
|
959
|
-
*/
|
|
960
|
-
headUserId: z.string().uuid().nullable(),
|
|
961
|
-
headOrigin: z.enum(["user", "inferred"]).nullable(),
|
|
962
952
|
});
|
|
963
953
|
|
|
964
954
|
export const OrgUnitMembershipSchema = z.object({
|
|
@@ -989,6 +979,10 @@ export const OpenRoleSchema = z.object({
|
|
|
989
979
|
targetStartDate: z.string().nullable(),
|
|
990
980
|
status: OpenRoleStatusSchema,
|
|
991
981
|
filledByUserId: z.string().uuid().nullable(),
|
|
982
|
+
// The open role's own reporting edge (ADR-BE-291): defaults to its creator,
|
|
983
|
+
// editable/clearable. Drives chart placement now that the unit-head anchor is
|
|
984
|
+
// retired (ADR-BE-292). Null → unmanaged (Unassigned bucket).
|
|
985
|
+
reportsToUserId: z.string().uuid().nullable(),
|
|
992
986
|
createdAt: z.string(),
|
|
993
987
|
updatedAt: z.string(),
|
|
994
988
|
});
|