@company-semantics/contracts 24.0.0 → 26.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 +1 -1
- package/src/api/generated-spec-hash.ts +2 -2
- package/src/api/generated.ts +125 -0
- package/src/email/registry.ts +18 -0
- package/src/email/types.ts +35 -1
- package/src/generated/openapi-routes.ts +2 -0
- package/src/identity/README.md +8 -0
- package/src/identity/index.ts +8 -0
- package/src/identity/people-org-chart.ts +97 -0
- package/src/index.ts +10 -0
- package/src/org/README.md +2 -0
- package/src/org/company-md.ts +52 -0
- package/src/org/index.ts +2 -0
- package/src/permissions/access-request.ts +67 -0
- package/src/permissions/index.ts +1 -0
package/package.json
CHANGED
|
@@ -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 = '62fe60545526' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = '62fe605455264b2246bb353c63b3e8905e7e2e22504f193dc15cce1edd34e68f' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -2144,6 +2144,40 @@ export interface paths {
|
|
|
2144
2144
|
patch?: never;
|
|
2145
2145
|
trace?: never;
|
|
2146
2146
|
};
|
|
2147
|
+
"/api/org-units/{unitId}/open-roles/{roleId}/unit": {
|
|
2148
|
+
parameters: {
|
|
2149
|
+
query?: never;
|
|
2150
|
+
header?: never;
|
|
2151
|
+
path?: never;
|
|
2152
|
+
cookie?: never;
|
|
2153
|
+
};
|
|
2154
|
+
get?: never;
|
|
2155
|
+
/** Move an open role to a different unit (set the seat's unit) */
|
|
2156
|
+
put: operations["setOrgUnitOpenRoleUnit"];
|
|
2157
|
+
post?: never;
|
|
2158
|
+
delete?: never;
|
|
2159
|
+
options?: never;
|
|
2160
|
+
head?: never;
|
|
2161
|
+
patch?: never;
|
|
2162
|
+
trace?: never;
|
|
2163
|
+
};
|
|
2164
|
+
"/api/org-units/{unitId}/open-roles/{roleId}/title": {
|
|
2165
|
+
parameters: {
|
|
2166
|
+
query?: never;
|
|
2167
|
+
header?: never;
|
|
2168
|
+
path?: never;
|
|
2169
|
+
cookie?: never;
|
|
2170
|
+
};
|
|
2171
|
+
get?: never;
|
|
2172
|
+
/** Set an open role's seat title */
|
|
2173
|
+
put: operations["setOrgUnitOpenRoleTitle"];
|
|
2174
|
+
post?: never;
|
|
2175
|
+
delete?: never;
|
|
2176
|
+
options?: never;
|
|
2177
|
+
head?: never;
|
|
2178
|
+
patch?: never;
|
|
2179
|
+
trace?: never;
|
|
2180
|
+
};
|
|
2147
2181
|
"/api/users/org-chart": {
|
|
2148
2182
|
parameters: {
|
|
2149
2183
|
query?: never;
|
|
@@ -4877,6 +4911,38 @@ export interface components {
|
|
|
4877
4911
|
};
|
|
4878
4912
|
};
|
|
4879
4913
|
PeopleOrgChartResponse: {
|
|
4914
|
+
seats: {
|
|
4915
|
+
/** Format: uuid */
|
|
4916
|
+
id: string;
|
|
4917
|
+
/** Format: uuid */
|
|
4918
|
+
unitId: string;
|
|
4919
|
+
title: string | null;
|
|
4920
|
+
/** @enum {string} */
|
|
4921
|
+
status: "planned" | "open" | "filled" | "closed";
|
|
4922
|
+
hiring: boolean;
|
|
4923
|
+
occupants: {
|
|
4924
|
+
/** Format: uuid */
|
|
4925
|
+
userId: string;
|
|
4926
|
+
fullName: string;
|
|
4927
|
+
avatarUrl: string | null;
|
|
4928
|
+
primaryUnitId: string | null;
|
|
4929
|
+
ownedUnits: {
|
|
4930
|
+
/** Format: uuid */
|
|
4931
|
+
id: string;
|
|
4932
|
+
name: string;
|
|
4933
|
+
/** @enum {string} */
|
|
4934
|
+
mutability: "derived" | "user_managed";
|
|
4935
|
+
}[];
|
|
4936
|
+
}[];
|
|
4937
|
+
}[];
|
|
4938
|
+
seatEdges: {
|
|
4939
|
+
/** Format: uuid */
|
|
4940
|
+
reportPositionId: string;
|
|
4941
|
+
/** Format: uuid */
|
|
4942
|
+
managerPositionId: string;
|
|
4943
|
+
/** @enum {string} */
|
|
4944
|
+
relationshipType: "solid" | "dotted";
|
|
4945
|
+
}[];
|
|
4880
4946
|
nodes: {
|
|
4881
4947
|
/** Format: uuid */
|
|
4882
4948
|
id: string;
|
|
@@ -9109,6 +9175,65 @@ export interface operations {
|
|
|
9109
9175
|
};
|
|
9110
9176
|
};
|
|
9111
9177
|
};
|
|
9178
|
+
setOrgUnitOpenRoleUnit: {
|
|
9179
|
+
parameters: {
|
|
9180
|
+
query?: never;
|
|
9181
|
+
header?: never;
|
|
9182
|
+
path: {
|
|
9183
|
+
unitId: string;
|
|
9184
|
+
roleId: string;
|
|
9185
|
+
};
|
|
9186
|
+
cookie?: never;
|
|
9187
|
+
};
|
|
9188
|
+
requestBody: {
|
|
9189
|
+
content: {
|
|
9190
|
+
"application/json": {
|
|
9191
|
+
/** Format: uuid */
|
|
9192
|
+
unitId: string;
|
|
9193
|
+
};
|
|
9194
|
+
};
|
|
9195
|
+
};
|
|
9196
|
+
responses: {
|
|
9197
|
+
/** @description Open role moved to the destination unit */
|
|
9198
|
+
200: {
|
|
9199
|
+
headers: {
|
|
9200
|
+
[name: string]: unknown;
|
|
9201
|
+
};
|
|
9202
|
+
content: {
|
|
9203
|
+
"application/json": components["schemas"]["OpenRoleResponse"];
|
|
9204
|
+
};
|
|
9205
|
+
};
|
|
9206
|
+
};
|
|
9207
|
+
};
|
|
9208
|
+
setOrgUnitOpenRoleTitle: {
|
|
9209
|
+
parameters: {
|
|
9210
|
+
query?: never;
|
|
9211
|
+
header?: never;
|
|
9212
|
+
path: {
|
|
9213
|
+
unitId: string;
|
|
9214
|
+
roleId: string;
|
|
9215
|
+
};
|
|
9216
|
+
cookie?: never;
|
|
9217
|
+
};
|
|
9218
|
+
requestBody: {
|
|
9219
|
+
content: {
|
|
9220
|
+
"application/json": {
|
|
9221
|
+
title: string | null;
|
|
9222
|
+
};
|
|
9223
|
+
};
|
|
9224
|
+
};
|
|
9225
|
+
responses: {
|
|
9226
|
+
/** @description Open role with updated title */
|
|
9227
|
+
200: {
|
|
9228
|
+
headers: {
|
|
9229
|
+
[name: string]: unknown;
|
|
9230
|
+
};
|
|
9231
|
+
content: {
|
|
9232
|
+
"application/json": components["schemas"]["OpenRoleResponse"];
|
|
9233
|
+
};
|
|
9234
|
+
};
|
|
9235
|
+
};
|
|
9236
|
+
};
|
|
9112
9237
|
getPeopleOrgChart: {
|
|
9113
9238
|
parameters: {
|
|
9114
9239
|
query?: never;
|
package/src/email/registry.ts
CHANGED
|
@@ -112,6 +112,24 @@ export const EMAIL_KINDS = {
|
|
|
112
112
|
plainTextRequired: true,
|
|
113
113
|
htmlSupported: true,
|
|
114
114
|
},
|
|
115
|
+
"companyMd.access_requested": {
|
|
116
|
+
kind: "companyMd.access_requested",
|
|
117
|
+
subject: "Someone requested access to a document",
|
|
118
|
+
plainTextRequired: true,
|
|
119
|
+
htmlSupported: true,
|
|
120
|
+
},
|
|
121
|
+
"companyMd.access_request_approved": {
|
|
122
|
+
kind: "companyMd.access_request_approved",
|
|
123
|
+
subject: "Your access request was approved",
|
|
124
|
+
plainTextRequired: true,
|
|
125
|
+
htmlSupported: true,
|
|
126
|
+
},
|
|
127
|
+
"companyMd.access_request_denied": {
|
|
128
|
+
kind: "companyMd.access_request_denied",
|
|
129
|
+
subject: "Your access request was reviewed",
|
|
130
|
+
plainTextRequired: true,
|
|
131
|
+
htmlSupported: true,
|
|
132
|
+
},
|
|
115
133
|
} as const satisfies Record<EmailKind, EmailKindDefinition>;
|
|
116
134
|
|
|
117
135
|
// =============================================================================
|
package/src/email/types.ts
CHANGED
|
@@ -32,7 +32,10 @@ export type EmailKind =
|
|
|
32
32
|
| "org.ownership_transfer_completed"
|
|
33
33
|
| "security.alert" // future
|
|
34
34
|
| "chat.shared"
|
|
35
|
-
| "share.granted"
|
|
35
|
+
| "share.granted"
|
|
36
|
+
| "companyMd.access_requested"
|
|
37
|
+
| "companyMd.access_request_approved"
|
|
38
|
+
| "companyMd.access_request_denied";
|
|
36
39
|
|
|
37
40
|
// =============================================================================
|
|
38
41
|
// Email Payloads
|
|
@@ -128,6 +131,37 @@ export interface EmailPayloads {
|
|
|
128
131
|
/** Optional message from the granter, included in the email only (not persisted) */
|
|
129
132
|
message?: string;
|
|
130
133
|
};
|
|
134
|
+
/** Sent to the doc owner(s) when an actor requests access (ADR-BE-338). */
|
|
135
|
+
"companyMd.access_requested": {
|
|
136
|
+
/** Display name of the requester */
|
|
137
|
+
requesterName: string;
|
|
138
|
+
/** Title of the company.md node access is requested for */
|
|
139
|
+
docTitle: string;
|
|
140
|
+
/** Optional message from the requester (email only) */
|
|
141
|
+
message?: string;
|
|
142
|
+
/** Deep-link that opens the doc's ShareDialog scrolled to the pending request */
|
|
143
|
+
reviewUrl: string;
|
|
144
|
+
};
|
|
145
|
+
/** Sent to the requester when an owner approves (ADR-BE-338). */
|
|
146
|
+
"companyMd.access_request_approved": {
|
|
147
|
+
/** Display name of the owner who approved */
|
|
148
|
+
approverName: string;
|
|
149
|
+
/** Title of the company.md node */
|
|
150
|
+
docTitle: string;
|
|
151
|
+
/** Access level granted */
|
|
152
|
+
accessLevel: "editor" | "commenter" | "viewer";
|
|
153
|
+
/** Full URL to view the node */
|
|
154
|
+
docUrl: string;
|
|
155
|
+
};
|
|
156
|
+
/** Sent to the requester when an owner denies (ADR-BE-338). */
|
|
157
|
+
"companyMd.access_request_denied": {
|
|
158
|
+
/** Display name of the owner who denied */
|
|
159
|
+
approverName: string;
|
|
160
|
+
/** Title of the company.md node */
|
|
161
|
+
docTitle: string;
|
|
162
|
+
/** Optional reason from the owner (email only) */
|
|
163
|
+
reason?: string;
|
|
164
|
+
};
|
|
131
165
|
}
|
|
132
166
|
|
|
133
167
|
// =============================================================================
|
|
@@ -22,6 +22,7 @@ export const openApiRoutes = {
|
|
|
22
22
|
'/api/chats/{id}/messages/{messageId}': ['DELETE'],
|
|
23
23
|
'/api/chats/{id}/pin': ['DELETE', 'POST'],
|
|
24
24
|
'/api/company-md/context-bank': ['POST'],
|
|
25
|
+
'/api/company-md/context-bank/search': ['GET'],
|
|
25
26
|
'/api/company-md/docs/{id}': ['GET'],
|
|
26
27
|
'/api/company-md/docs/{id}/content': ['PUT'],
|
|
27
28
|
'/api/company-md/docs/{id}/context-bank': ['GET'],
|
|
@@ -54,6 +55,7 @@ export const openApiRoutes = {
|
|
|
54
55
|
'/api/executions/{executionId}/timeline': ['GET'],
|
|
55
56
|
'/api/executions/{executionId}/undo': ['POST'],
|
|
56
57
|
'/api/factory/floor': ['GET'],
|
|
58
|
+
'/api/factory/kpis': ['GET'],
|
|
57
59
|
'/api/factory/snapshot': ['GET'],
|
|
58
60
|
'/api/ingestion/operations/{id}': ['GET'],
|
|
59
61
|
'/api/internal-admin/impersonate/end': ['POST'],
|
package/src/identity/README.md
CHANGED
|
@@ -61,6 +61,14 @@ TypeScript types and functions for user identity and display name resolution.
|
|
|
61
61
|
- `PeopleOrgChartOwnedUnitSchema`
|
|
62
62
|
- `PeopleOrgChartResponse` _(type)_
|
|
63
63
|
- `PeopleOrgChartResponseSchema`
|
|
64
|
+
- `PeopleOrgChartSeat` _(type)_
|
|
65
|
+
- `PeopleOrgChartSeatEdge` _(type)_
|
|
66
|
+
- `PeopleOrgChartSeatEdgeSchema`
|
|
67
|
+
- `PeopleOrgChartSeatOccupant` _(type)_
|
|
68
|
+
- `PeopleOrgChartSeatOccupantSchema`
|
|
69
|
+
- `PeopleOrgChartSeatSchema`
|
|
70
|
+
- `PeopleOrgChartSeatStatus` _(type)_
|
|
71
|
+
- `PeopleOrgChartSeatStatusSchema`
|
|
64
72
|
- `Person` _(type)_
|
|
65
73
|
- `PersonSchema`
|
|
66
74
|
- `ProfileResponse` _(type)_
|
package/src/identity/index.ts
CHANGED
|
@@ -69,6 +69,10 @@ export {
|
|
|
69
69
|
PeopleOrgChartOwnedUnitSchema,
|
|
70
70
|
PeopleOrgChartEdgeSchema,
|
|
71
71
|
PeopleOrgChartOpenRoleSchema,
|
|
72
|
+
PeopleOrgChartSeatStatusSchema,
|
|
73
|
+
PeopleOrgChartSeatOccupantSchema,
|
|
74
|
+
PeopleOrgChartSeatSchema,
|
|
75
|
+
PeopleOrgChartSeatEdgeSchema,
|
|
72
76
|
PeopleOrgChartResponseSchema,
|
|
73
77
|
} from "./people-org-chart";
|
|
74
78
|
export type {
|
|
@@ -78,6 +82,10 @@ export type {
|
|
|
78
82
|
PeopleOrgChartOwnedUnit,
|
|
79
83
|
PeopleOrgChartEdge,
|
|
80
84
|
PeopleOrgChartOpenRole,
|
|
85
|
+
PeopleOrgChartSeatStatus,
|
|
86
|
+
PeopleOrgChartSeatOccupant,
|
|
87
|
+
PeopleOrgChartSeat,
|
|
88
|
+
PeopleOrgChartSeatEdge,
|
|
81
89
|
PeopleOrgChartResponse,
|
|
82
90
|
} from "./people-org-chart";
|
|
83
91
|
|
|
@@ -113,6 +113,93 @@ export type PeopleOrgChartOpenRole = z.infer<
|
|
|
113
113
|
typeof PeopleOrgChartOpenRoleSchema
|
|
114
114
|
>;
|
|
115
115
|
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// Seat — the position-centric unification (ADR-CONT-093)
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
//
|
|
120
|
+
// A `PeopleOrgChartSeat` is the unified chart actor: a `positions` row carrying
|
|
121
|
+
// its SEAT-SCOPED attributes (unit placement, title, seat-existence status,
|
|
122
|
+
// hiring/staffing sub-state) plus an `occupants[]` array of PERSON-SCOPED
|
|
123
|
+
// attributes for whoever currently holds it. The split is structural, not
|
|
124
|
+
// member-vs-open-role: a VACANT seat (`occupants: []`) is the old "open role";
|
|
125
|
+
// an OCCUPIED seat (`occupants.length >= 1`) is the old "member" (N occupants
|
|
126
|
+
// for a co-occupied seat — forward-compatible; live data is 0/1). Reporting is
|
|
127
|
+
// expressed seat→seat in `seatEdges[]`, NOT on the seat, so the edge list stays
|
|
128
|
+
// the single source of truth for placement (ADR-CTRL-159). `OrgChartActorRef`
|
|
129
|
+
// is retained write-only (set-manager request/response) and is removed from
|
|
130
|
+
// this read model.
|
|
131
|
+
//
|
|
132
|
+
// This pair (`seats[]` + `seatEdges[]`) is ADDITIVE alongside the legacy
|
|
133
|
+
// `nodes`/`edges`/`openRoles` during the transition; the projector dual-emits
|
|
134
|
+
// both from one position pass. A later breaking minor removes the legacy half.
|
|
135
|
+
|
|
136
|
+
export const PeopleOrgChartSeatStatusSchema = z.enum([
|
|
137
|
+
"planned",
|
|
138
|
+
"open",
|
|
139
|
+
"filled",
|
|
140
|
+
"closed",
|
|
141
|
+
]);
|
|
142
|
+
export type PeopleOrgChartSeatStatus = z.infer<
|
|
143
|
+
typeof PeopleOrgChartSeatStatusSchema
|
|
144
|
+
>;
|
|
145
|
+
|
|
146
|
+
// Person-scoped attributes of a seat's holder — keyed by `userId`, they travel
|
|
147
|
+
// with the person across seats (ADR-BE-329: a vacant seat grants none of these
|
|
148
|
+
// by construction). Mirrors the legacy `PeopleOrgChartNode` person fields.
|
|
149
|
+
export const PeopleOrgChartSeatOccupantSchema = z.object({
|
|
150
|
+
userId: z.string().uuid(),
|
|
151
|
+
fullName: z.string(),
|
|
152
|
+
avatarUrl: z.string().nullable(),
|
|
153
|
+
// Stable HOME unit (home_assignments), not the seat unit — mirrors the legacy
|
|
154
|
+
// node's `primaryUnitId`. Null ⇒ no home assignment.
|
|
155
|
+
primaryUnitId: z.string().uuid().nullable(),
|
|
156
|
+
// Units this occupant is a local structural owner of (ADR-BE-168). Empty ⇒
|
|
157
|
+
// not a unit owner. Same shape + semantics as the legacy node's `ownedUnits`.
|
|
158
|
+
ownedUnits: z.array(PeopleOrgChartOwnedUnitSchema),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
export type PeopleOrgChartSeatOccupant = z.infer<
|
|
162
|
+
typeof PeopleOrgChartSeatOccupantSchema
|
|
163
|
+
>;
|
|
164
|
+
|
|
165
|
+
export const PeopleOrgChartSeatSchema = z.object({
|
|
166
|
+
// positionId — the seat identity (stable across occupancy changes).
|
|
167
|
+
id: z.string().uuid(),
|
|
168
|
+
// positions.unit_id — the seat's placement column. The chart columns a seat by
|
|
169
|
+
// this unit regardless of occupancy.
|
|
170
|
+
unitId: z.string().uuid(),
|
|
171
|
+
// positions.title — '' is mapped to null to preserve the legacy nullable wire
|
|
172
|
+
// shape (ADR-BE-312). Seat-scoped, NOT the occupant's member-display jobTitle.
|
|
173
|
+
title: z.string().nullable(),
|
|
174
|
+
// Seat-existence lifecycle (ADR-CTRL-182).
|
|
175
|
+
status: PeopleOrgChartSeatStatusSchema,
|
|
176
|
+
// Staffing sub-state: `position_fulfillment.status != 'inactive'` (ADR-BE-312).
|
|
177
|
+
// Orthogonal to `status` — "are we trying to staff this seat?". An absent
|
|
178
|
+
// fulfillment row ⇒ false.
|
|
179
|
+
hiring: z.boolean(),
|
|
180
|
+
// The seat's current holders. [] ⇒ vacant (the old "open role"); >= 1 ⇒
|
|
181
|
+
// occupied (the old "member"). Only account-linked, active/interim occupants
|
|
182
|
+
// appear, mirroring the legacy node-keying.
|
|
183
|
+
occupants: z.array(PeopleOrgChartSeatOccupantSchema),
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
export type PeopleOrgChartSeat = z.infer<typeof PeopleOrgChartSeatSchema>;
|
|
187
|
+
|
|
188
|
+
// A seat→seat reporting edge — one row per `position_reporting` row (NOT a
|
|
189
|
+
// member cross-product). Endpoints are positionIds; resolve each to its seat in
|
|
190
|
+
// `seats[]`. Mirrors the legacy person-keyed `PeopleOrgChartEdge`, but keyed by
|
|
191
|
+
// the stable seat identity so a vacant seat's edge is expressible without an
|
|
192
|
+
// `OrgChartActorRef`.
|
|
193
|
+
export const PeopleOrgChartSeatEdgeSchema = z.object({
|
|
194
|
+
reportPositionId: z.string().uuid(),
|
|
195
|
+
managerPositionId: z.string().uuid(),
|
|
196
|
+
relationshipType: ReportingRelationshipTypeSchema,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
export type PeopleOrgChartSeatEdge = z.infer<
|
|
200
|
+
typeof PeopleOrgChartSeatEdgeSchema
|
|
201
|
+
>;
|
|
202
|
+
|
|
116
203
|
// ---------------------------------------------------------------------------
|
|
117
204
|
// GET /api/users/org-chart
|
|
118
205
|
// ---------------------------------------------------------------------------
|
|
@@ -123,6 +210,16 @@ export type PeopleOrgChartOpenRole = z.infer<
|
|
|
123
210
|
// the render-time reporting heuristic.
|
|
124
211
|
|
|
125
212
|
export const PeopleOrgChartResponseSchema = z.object({
|
|
213
|
+
// Position-centric unified view (ADR-CONT-093). `seats[]` carries every chart
|
|
214
|
+
// actor (occupied or vacant) and `seatEdges[]` the seat→seat reporting graph.
|
|
215
|
+
// ADDITIVE alongside the legacy fields below during the transition; a later
|
|
216
|
+
// breaking minor removes the legacy half.
|
|
217
|
+
seats: z.array(PeopleOrgChartSeatSchema),
|
|
218
|
+
seatEdges: z.array(PeopleOrgChartSeatEdgeSchema),
|
|
219
|
+
// Legacy, transitional (ADR-CONT-093 supersedes). Derived from the same
|
|
220
|
+
// position pass as `seats`/`seatEdges`; consumers should migrate to the seat
|
|
221
|
+
// model. `nodes` = occupied actors, `openRoles` = vacant 'open' actors,
|
|
222
|
+
// `edges` = the same reporting graph keyed by person/open-role actor refs.
|
|
126
223
|
nodes: z.array(PeopleOrgChartNodeSchema),
|
|
127
224
|
edges: z.array(PeopleOrgChartEdgeSchema),
|
|
128
225
|
openRoles: z.array(PeopleOrgChartOpenRoleSchema),
|
package/src/index.ts
CHANGED
|
@@ -180,6 +180,10 @@ export {
|
|
|
180
180
|
PeopleOrgChartOwnedUnitSchema,
|
|
181
181
|
PeopleOrgChartEdgeSchema,
|
|
182
182
|
PeopleOrgChartOpenRoleSchema,
|
|
183
|
+
PeopleOrgChartSeatStatusSchema,
|
|
184
|
+
PeopleOrgChartSeatOccupantSchema,
|
|
185
|
+
PeopleOrgChartSeatSchema,
|
|
186
|
+
PeopleOrgChartSeatEdgeSchema,
|
|
183
187
|
PeopleOrgChartResponseSchema,
|
|
184
188
|
} from "./identity/index";
|
|
185
189
|
export type {
|
|
@@ -189,6 +193,10 @@ export type {
|
|
|
189
193
|
PeopleOrgChartOwnedUnit,
|
|
190
194
|
PeopleOrgChartEdge,
|
|
191
195
|
PeopleOrgChartOpenRole,
|
|
196
|
+
PeopleOrgChartSeatStatus,
|
|
197
|
+
PeopleOrgChartSeatOccupant,
|
|
198
|
+
PeopleOrgChartSeat,
|
|
199
|
+
PeopleOrgChartSeatEdge,
|
|
192
200
|
PeopleOrgChartResponse,
|
|
193
201
|
} from "./identity/index";
|
|
194
202
|
|
|
@@ -340,6 +348,8 @@ export type {
|
|
|
340
348
|
TransferMemberEligibility,
|
|
341
349
|
// Company.md domain types (PRD-00173)
|
|
342
350
|
CompanyMdVisibility,
|
|
351
|
+
CompanyMdDiscoverabilityPolicy,
|
|
352
|
+
CompanyMdClassification,
|
|
343
353
|
CompanyMdDocLevel,
|
|
344
354
|
CompanyMdDocKind,
|
|
345
355
|
CompanyMdNodeType,
|
package/src/org/README.md
CHANGED
|
@@ -57,8 +57,10 @@ Shared type vocabulary for organization ownership, type classification, and tran
|
|
|
57
57
|
- `ChangeMemberRoleRequest` _(type)_ — Request payload for changing a member's role.
|
|
58
58
|
- `ChangeMemberRoleResponse` _(type)_
|
|
59
59
|
- `ChangeMemberRoleResponseSchema`
|
|
60
|
+
- `CompanyMdClassification` _(type)_ — Information classification for a Company.md node — what the document is, for governance, NOT permissions.
|
|
60
61
|
- `CompanyMdContextBankItem` _(type)_ — A context bank item — a company.md doc associated with one or more parent nodes.
|
|
61
62
|
- `CompanyMdDependency` _(type)_
|
|
63
|
+
- `CompanyMdDiscoverabilityPolicy` _(type)_ — Discoverability policy for a Company.md node — who knows it exists, orthogonal to who may read it (authority…
|
|
62
64
|
- `CompanyMdDoc` _(type)_
|
|
63
65
|
- `CompanyMdDocCollaborators` _(type)_
|
|
64
66
|
- `CompanyMdDocCore` _(type)_
|
package/src/org/company-md.ts
CHANGED
|
@@ -23,6 +23,32 @@
|
|
|
23
23
|
*/
|
|
24
24
|
export type CompanyMdVisibility = "private" | "unit" | "org";
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Discoverability policy for a Company.md node — *who knows it exists*, orthogonal
|
|
28
|
+
* to who may read it (authority resolution). See ADR-CTRL-194 / ADR-BE-338.
|
|
29
|
+
*
|
|
30
|
+
* - `org`: every org member knows the node exists; a non-reader sees the locked
|
|
31
|
+
* meta-stub (title + owner byline) and may request access.
|
|
32
|
+
* - `owners`: only readers know it exists; a non-reader gets a no-leak 404.
|
|
33
|
+
*
|
|
34
|
+
* A *policy*, not a boolean — intentionally extensible (`unit | partners |
|
|
35
|
+
* customers`). It also governs retrieval (search, semantic search, suggested
|
|
36
|
+
* context, citation, agent browsing).
|
|
37
|
+
*/
|
|
38
|
+
export type CompanyMdDiscoverabilityPolicy = "org" | "owners";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Information classification for a Company.md node — *what the document is*, for
|
|
42
|
+
* governance, NOT permissions (ADR-CTRL-194 / ADR-BE-338). Later drives export
|
|
43
|
+
* watermarking, share-approval gates, retrieval rules, and audit verbosity
|
|
44
|
+
* without changing who can read. Named now; enforcement behaviors deferred.
|
|
45
|
+
*/
|
|
46
|
+
export type CompanyMdClassification =
|
|
47
|
+
| "public"
|
|
48
|
+
| "internal"
|
|
49
|
+
| "confidential"
|
|
50
|
+
| "highly_confidential";
|
|
51
|
+
|
|
26
52
|
/**
|
|
27
53
|
* @deprecated Since 1.12.0. `CompanyMdDocLevel` is superseded by `CompanyMdDocKind` + `depth`.
|
|
28
54
|
*
|
|
@@ -107,6 +133,17 @@ export interface CompanyMdNodeIdentity {
|
|
|
107
133
|
readonly depth: 1 | 2 | 3 | 4 | 5 | null;
|
|
108
134
|
readonly parentId: string | null;
|
|
109
135
|
readonly visibility: CompanyMdVisibility;
|
|
136
|
+
/**
|
|
137
|
+
* Who knows this node exists (orthogonal to who may read it). Governs the
|
|
138
|
+
* non-reader branch: `org` → locked meta-stub + request-access; `owners` →
|
|
139
|
+
* no-leak 404. See ADR-CTRL-194 / ADR-BE-338.
|
|
140
|
+
*/
|
|
141
|
+
readonly discoverabilityPolicy: CompanyMdDiscoverabilityPolicy;
|
|
142
|
+
/**
|
|
143
|
+
* Governance classification of the node (not a permission). Drives future
|
|
144
|
+
* governance behaviors (watermarking, share-approval, retrieval, audit).
|
|
145
|
+
*/
|
|
146
|
+
readonly classification: CompanyMdClassification;
|
|
110
147
|
/** Owning org_unit. Null for root docs or when the owning unit has been archived. */
|
|
111
148
|
readonly owningUnitId: string | null;
|
|
112
149
|
}
|
|
@@ -132,6 +169,21 @@ export interface CompanyMdDocCore extends CompanyMdNodeIdentity {
|
|
|
132
169
|
* its body (ADR-BE-245). Omitted/`false` on the normal full-content path.
|
|
133
170
|
*/
|
|
134
171
|
readonly contentRedacted?: boolean;
|
|
172
|
+
/**
|
|
173
|
+
* Read-state of this node for the requesting actor (ADR-CTRL-194 / ADR-BE-338):
|
|
174
|
+
* - `full`: actor may read; `content` is the real body.
|
|
175
|
+
* - `redacted_admin`: meta-tier admin meta-view (ADR-BE-245).
|
|
176
|
+
* - `locked_requestable`: non-reader of an `org`-discoverable node — body is the
|
|
177
|
+
* redacted stub and the actor may request access.
|
|
178
|
+
* Omitted on legacy paths that only set `contentRedacted`.
|
|
179
|
+
*/
|
|
180
|
+
readonly accessState?: "full" | "redacted_admin" | "locked_requestable";
|
|
181
|
+
/**
|
|
182
|
+
* Whether the requesting actor may request access to this node. A *separate*
|
|
183
|
+
* resolver, intentionally NOT equal to `discoverabilityPolicy` (a direct-link
|
|
184
|
+
* recipient to an `owners` node may still be allowed to request).
|
|
185
|
+
*/
|
|
186
|
+
readonly canRequestAccess?: boolean;
|
|
135
187
|
}
|
|
136
188
|
|
|
137
189
|
export interface CompanyMdDocCollaborators {
|
package/src/org/index.ts
CHANGED
|
@@ -163,6 +163,8 @@ export { orderTreeNodes } from "./tree-ordering";
|
|
|
163
163
|
// Company.md domain types (PRD-00173)
|
|
164
164
|
export type {
|
|
165
165
|
CompanyMdVisibility,
|
|
166
|
+
CompanyMdDiscoverabilityPolicy,
|
|
167
|
+
CompanyMdClassification,
|
|
166
168
|
CompanyMdDocLevel,
|
|
167
169
|
CompanyMdDocKind,
|
|
168
170
|
CompanyMdNodeType,
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Company.md Access-Request DTOs (ADR-CONTRACTS-071 / ADR-BE-338)
|
|
3
|
+
*
|
|
4
|
+
* The request-access workflow: a non-reader of an `org`-discoverable node asks
|
|
5
|
+
* the owner(s) for access; the first owner to act resolves the request, minting a
|
|
6
|
+
* normal grant. These are the shared request/response shapes.
|
|
7
|
+
*
|
|
8
|
+
* Zod-canonical: schema is the source of truth, the type is inferred.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { GrantableAccessLevelSchema } from "./share-api";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Lifecycle status of an access request. A single pending request exists per
|
|
15
|
+
* (node, actor); the first owner to act transitions it terminally.
|
|
16
|
+
*/
|
|
17
|
+
export const ACCESS_REQUEST_STATUSES = [
|
|
18
|
+
"pending",
|
|
19
|
+
"approved",
|
|
20
|
+
"denied",
|
|
21
|
+
"withdrawn",
|
|
22
|
+
"expired",
|
|
23
|
+
] as const;
|
|
24
|
+
export const AccessRequestStatusSchema = z.enum(ACCESS_REQUEST_STATUSES);
|
|
25
|
+
export type AccessRequestStatus = z.infer<typeof AccessRequestStatusSchema>;
|
|
26
|
+
|
|
27
|
+
/** POST body to create an access request. */
|
|
28
|
+
export const AccessRequestCreateSchema = z.object({
|
|
29
|
+
/** Optional context the requester sends to the owner(s). */
|
|
30
|
+
message: z.string().max(2000).optional(),
|
|
31
|
+
});
|
|
32
|
+
export type AccessRequestCreate = z.infer<typeof AccessRequestCreateSchema>;
|
|
33
|
+
|
|
34
|
+
/** A single actor that requested access (actor-generic; today a user). */
|
|
35
|
+
export const AccessRequestActorSchema = z.object({
|
|
36
|
+
id: z.string(),
|
|
37
|
+
name: z.string(),
|
|
38
|
+
});
|
|
39
|
+
export type AccessRequestActor = z.infer<typeof AccessRequestActorSchema>;
|
|
40
|
+
|
|
41
|
+
/** Full access-request record returned to owners (and the requester). */
|
|
42
|
+
export const AccessRequestSchema = z.object({
|
|
43
|
+
id: z.string(),
|
|
44
|
+
requestor: AccessRequestActorSchema,
|
|
45
|
+
docId: z.string(),
|
|
46
|
+
status: AccessRequestStatusSchema,
|
|
47
|
+
message: z.string().nullable(),
|
|
48
|
+
createdAt: z.string(),
|
|
49
|
+
resolvedAt: z.string().nullable(),
|
|
50
|
+
});
|
|
51
|
+
export type AccessRequest = z.infer<typeof AccessRequestSchema>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* POST body to approve a request. The owner chooses the granted level (default
|
|
55
|
+
* `viewer` is applied server-side if the field is omitted by older clients).
|
|
56
|
+
*/
|
|
57
|
+
export const ApproveAccessRequestSchema = z.object({
|
|
58
|
+
accessLevel: GrantableAccessLevelSchema,
|
|
59
|
+
});
|
|
60
|
+
export type ApproveAccessRequest = z.infer<typeof ApproveAccessRequestSchema>;
|
|
61
|
+
|
|
62
|
+
/** POST body to deny a request. */
|
|
63
|
+
export const DenyAccessRequestSchema = z.object({
|
|
64
|
+
/** Optional reason, surfaced to the requester (email only). */
|
|
65
|
+
reason: z.string().max(2000).optional(),
|
|
66
|
+
});
|
|
67
|
+
export type DenyAccessRequest = z.infer<typeof DenyAccessRequestSchema>;
|