@company-semantics/contracts 2.8.0 → 2.10.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 +359 -0
- package/src/index.ts +5 -0
- package/src/permissions/access-levels.ts +40 -0
- package/src/permissions/access-source.ts +28 -0
- package/src/permissions/index.ts +9 -0
- package/src/permissions/orgchart-roles.ts +24 -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 = 'b33671a6612a' as const;
|
|
3
|
+
export const SPEC_HASH_FULL = 'b33671a6612a405a566dcdcc0f0bd2fc4017f84c43a46177e4db59fcb9f21709' as const;
|
package/src/api/generated.ts
CHANGED
|
@@ -2313,6 +2313,91 @@ export interface paths {
|
|
|
2313
2313
|
patch?: never;
|
|
2314
2314
|
trace?: never;
|
|
2315
2315
|
};
|
|
2316
|
+
"/api/me/meetings/recordings/{id}/export": {
|
|
2317
|
+
parameters: {
|
|
2318
|
+
query?: never;
|
|
2319
|
+
header?: never;
|
|
2320
|
+
path?: never;
|
|
2321
|
+
cookie?: never;
|
|
2322
|
+
};
|
|
2323
|
+
get?: never;
|
|
2324
|
+
put?: never;
|
|
2325
|
+
/** Export a transcript as markdown/JSON (sync) or PDF (async job) */
|
|
2326
|
+
post: operations["exportMeetingRecording"];
|
|
2327
|
+
delete?: never;
|
|
2328
|
+
options?: never;
|
|
2329
|
+
head?: never;
|
|
2330
|
+
patch?: never;
|
|
2331
|
+
trace?: never;
|
|
2332
|
+
};
|
|
2333
|
+
"/api/me/meetings/recordings/{id}/export/{jobId}": {
|
|
2334
|
+
parameters: {
|
|
2335
|
+
query?: never;
|
|
2336
|
+
header?: never;
|
|
2337
|
+
path?: never;
|
|
2338
|
+
cookie?: never;
|
|
2339
|
+
};
|
|
2340
|
+
/** Download a rendered PDF export, or poll its job status */
|
|
2341
|
+
get: operations["downloadMeetingRecordingExport"];
|
|
2342
|
+
put?: never;
|
|
2343
|
+
post?: never;
|
|
2344
|
+
delete?: never;
|
|
2345
|
+
options?: never;
|
|
2346
|
+
head?: never;
|
|
2347
|
+
patch?: never;
|
|
2348
|
+
trace?: never;
|
|
2349
|
+
};
|
|
2350
|
+
"/api/me/meetings/recordings/{id}": {
|
|
2351
|
+
parameters: {
|
|
2352
|
+
query?: never;
|
|
2353
|
+
header?: never;
|
|
2354
|
+
path?: never;
|
|
2355
|
+
cookie?: never;
|
|
2356
|
+
};
|
|
2357
|
+
get?: never;
|
|
2358
|
+
put?: never;
|
|
2359
|
+
post?: never;
|
|
2360
|
+
/** Soft-delete a recording (30-day hard-delete grace; idempotent) */
|
|
2361
|
+
delete: operations["softDeleteMeetingRecording"];
|
|
2362
|
+
options?: never;
|
|
2363
|
+
head?: never;
|
|
2364
|
+
patch?: never;
|
|
2365
|
+
trace?: never;
|
|
2366
|
+
};
|
|
2367
|
+
"/api/me/meetings/recordings/{id}/restore": {
|
|
2368
|
+
parameters: {
|
|
2369
|
+
query?: never;
|
|
2370
|
+
header?: never;
|
|
2371
|
+
path?: never;
|
|
2372
|
+
cookie?: never;
|
|
2373
|
+
};
|
|
2374
|
+
get?: never;
|
|
2375
|
+
put?: never;
|
|
2376
|
+
/** Restore a soft-deleted recording within its 30-day window */
|
|
2377
|
+
post: operations["restoreMeetingRecording"];
|
|
2378
|
+
delete?: never;
|
|
2379
|
+
options?: never;
|
|
2380
|
+
head?: never;
|
|
2381
|
+
patch?: never;
|
|
2382
|
+
trace?: never;
|
|
2383
|
+
};
|
|
2384
|
+
"/api/me/meetings/recordings/{id}/visibility": {
|
|
2385
|
+
parameters: {
|
|
2386
|
+
query?: never;
|
|
2387
|
+
header?: never;
|
|
2388
|
+
path?: never;
|
|
2389
|
+
cookie?: never;
|
|
2390
|
+
};
|
|
2391
|
+
get?: never;
|
|
2392
|
+
put?: never;
|
|
2393
|
+
/** Change recording visibility (post-finalize only) */
|
|
2394
|
+
post: operations["changeMeetingRecordingVisibility"];
|
|
2395
|
+
delete?: never;
|
|
2396
|
+
options?: never;
|
|
2397
|
+
head?: never;
|
|
2398
|
+
patch?: never;
|
|
2399
|
+
trace?: never;
|
|
2400
|
+
};
|
|
2316
2401
|
"/api/internal-admin/impersonate/start": {
|
|
2317
2402
|
parameters: {
|
|
2318
2403
|
query?: never;
|
|
@@ -4068,6 +4153,112 @@ export interface components {
|
|
|
4068
4153
|
checksum: string;
|
|
4069
4154
|
cancelled?: boolean;
|
|
4070
4155
|
};
|
|
4156
|
+
/** @description Synchronous markdown/JSON content, or a queued PDF job id. */
|
|
4157
|
+
ExportMeetingRecordingResponse: {
|
|
4158
|
+
/** @constant */
|
|
4159
|
+
format: "markdown";
|
|
4160
|
+
content: string;
|
|
4161
|
+
} | {
|
|
4162
|
+
/** @constant */
|
|
4163
|
+
format: "json";
|
|
4164
|
+
/** @description Finalized read projection for a recording (excludes drafts). */
|
|
4165
|
+
metadata: {
|
|
4166
|
+
/** @description ULID; unified trace key for the recording (INV-MTG-7). */
|
|
4167
|
+
recordingId: string;
|
|
4168
|
+
/** Format: uuid */
|
|
4169
|
+
ownerUserId: string;
|
|
4170
|
+
/** Format: uuid */
|
|
4171
|
+
orgId: string;
|
|
4172
|
+
title: string | null;
|
|
4173
|
+
/**
|
|
4174
|
+
* @description Auto-detected meeting app that owns the system audio stream.
|
|
4175
|
+
* @enum {string}
|
|
4176
|
+
*/
|
|
4177
|
+
detectedApp: "zoom" | "teams" | "meet-browser" | "slack-huddle" | "manual";
|
|
4178
|
+
/**
|
|
4179
|
+
* @description Visibility band for the finalized meeting projection. Default `meeting_only`.
|
|
4180
|
+
* @enum {string}
|
|
4181
|
+
*/
|
|
4182
|
+
visibility: "meeting_only" | "shared" | "org" | "finalized_private";
|
|
4183
|
+
/**
|
|
4184
|
+
* @description Coarse lifecycle state for a recording entity.
|
|
4185
|
+
* @enum {string}
|
|
4186
|
+
*/
|
|
4187
|
+
status: "draft" | "recording" | "processing" | "finalized" | "failed" | "partial-transcript-network" | "cancelled";
|
|
4188
|
+
/**
|
|
4189
|
+
* @description Capture-runtime quality signal. `degraded` triggers a UI hint.
|
|
4190
|
+
* @enum {string}
|
|
4191
|
+
*/
|
|
4192
|
+
quality: "clean" | "degraded";
|
|
4193
|
+
/** Format: date-time */
|
|
4194
|
+
startedAt: string;
|
|
4195
|
+
endedAt: string | null;
|
|
4196
|
+
durationMs: number;
|
|
4197
|
+
participantUserIds: string[];
|
|
4198
|
+
transcriptAvailable: boolean;
|
|
4199
|
+
};
|
|
4200
|
+
segments: {
|
|
4201
|
+
startMs: number;
|
|
4202
|
+
endMs: number;
|
|
4203
|
+
/** @enum {string} */
|
|
4204
|
+
source: "mic" | "remote" | "unknown";
|
|
4205
|
+
speakerLabel: string | null;
|
|
4206
|
+
text: string;
|
|
4207
|
+
confidence: number | null;
|
|
4208
|
+
}[];
|
|
4209
|
+
} | {
|
|
4210
|
+
/** @constant */
|
|
4211
|
+
format: "pdf";
|
|
4212
|
+
/** Format: uuid */
|
|
4213
|
+
jobId: string;
|
|
4214
|
+
/** @constant */
|
|
4215
|
+
status: "queued";
|
|
4216
|
+
};
|
|
4217
|
+
/** @description Export a recording transcript as markdown, JSON, or PDF. */
|
|
4218
|
+
ExportMeetingRecordingRequest: {
|
|
4219
|
+
/** @enum {string} */
|
|
4220
|
+
format: "markdown" | "json" | "pdf";
|
|
4221
|
+
};
|
|
4222
|
+
/** @description PDF export job not yet ready (pending) or failed. */
|
|
4223
|
+
MeetingRecordingExportJobStatus: {
|
|
4224
|
+
/** Format: uuid */
|
|
4225
|
+
jobId: string;
|
|
4226
|
+
/** @enum {string} */
|
|
4227
|
+
status: "pending" | "failed";
|
|
4228
|
+
};
|
|
4229
|
+
/** @description Recording soft-deleted; hard-delete scheduled 30 days out. */
|
|
4230
|
+
SoftDeleteMeetingRecordingResponse: {
|
|
4231
|
+
/** @description ULID; unified trace key for the recording (INV-MTG-7). */
|
|
4232
|
+
recordingId: string;
|
|
4233
|
+
/** @constant */
|
|
4234
|
+
deleted: true;
|
|
4235
|
+
hardDeleteScheduledAt: string | null;
|
|
4236
|
+
};
|
|
4237
|
+
/** @description Restore a soft-deleted recording within its grace window. */
|
|
4238
|
+
RestoreMeetingRecordingResponse: {
|
|
4239
|
+
/** @description ULID; unified trace key for the recording (INV-MTG-7). */
|
|
4240
|
+
recordingId: string;
|
|
4241
|
+
restored: boolean;
|
|
4242
|
+
status: string;
|
|
4243
|
+
};
|
|
4244
|
+
/** @description Result of a visibility change. */
|
|
4245
|
+
ChangeMeetingRecordingVisibilityResponse: {
|
|
4246
|
+
/** @description ULID; unified trace key for the recording (INV-MTG-7). */
|
|
4247
|
+
recordingId: string;
|
|
4248
|
+
/**
|
|
4249
|
+
* @description Visibility band for the finalized meeting projection. Default `meeting_only`.
|
|
4250
|
+
* @enum {string}
|
|
4251
|
+
*/
|
|
4252
|
+
visibility: "meeting_only" | "shared" | "org" | "finalized_private";
|
|
4253
|
+
};
|
|
4254
|
+
/** @description Change a recording visibility (post-finalize only). */
|
|
4255
|
+
ChangeMeetingRecordingVisibilityRequest: {
|
|
4256
|
+
/**
|
|
4257
|
+
* @description Visibility band for the finalized meeting projection. Default `meeting_only`.
|
|
4258
|
+
* @enum {string}
|
|
4259
|
+
*/
|
|
4260
|
+
visibility: "meeting_only" | "shared" | "org" | "finalized_private";
|
|
4261
|
+
};
|
|
4071
4262
|
ImpersonationSessionResponse: {
|
|
4072
4263
|
session: {
|
|
4073
4264
|
impersonationSessionId: string;
|
|
@@ -7783,6 +7974,174 @@ export interface operations {
|
|
|
7783
7974
|
};
|
|
7784
7975
|
};
|
|
7785
7976
|
};
|
|
7977
|
+
exportMeetingRecording: {
|
|
7978
|
+
parameters: {
|
|
7979
|
+
query?: never;
|
|
7980
|
+
header?: never;
|
|
7981
|
+
path: {
|
|
7982
|
+
id: string;
|
|
7983
|
+
};
|
|
7984
|
+
cookie?: never;
|
|
7985
|
+
};
|
|
7986
|
+
requestBody: {
|
|
7987
|
+
content: {
|
|
7988
|
+
"application/json": components["schemas"]["ExportMeetingRecordingRequest"];
|
|
7989
|
+
};
|
|
7990
|
+
};
|
|
7991
|
+
responses: {
|
|
7992
|
+
/** @description Markdown/JSON content inline, or a queued PDF job id */
|
|
7993
|
+
200: {
|
|
7994
|
+
headers: {
|
|
7995
|
+
[name: string]: unknown;
|
|
7996
|
+
};
|
|
7997
|
+
content: {
|
|
7998
|
+
"application/json": components["schemas"]["ExportMeetingRecordingResponse"];
|
|
7999
|
+
};
|
|
8000
|
+
};
|
|
8001
|
+
/** @description Recording not found or not owned by this user */
|
|
8002
|
+
404: {
|
|
8003
|
+
headers: {
|
|
8004
|
+
[name: string]: unknown;
|
|
8005
|
+
};
|
|
8006
|
+
content?: never;
|
|
8007
|
+
};
|
|
8008
|
+
};
|
|
8009
|
+
};
|
|
8010
|
+
downloadMeetingRecordingExport: {
|
|
8011
|
+
parameters: {
|
|
8012
|
+
query?: never;
|
|
8013
|
+
header?: never;
|
|
8014
|
+
path: {
|
|
8015
|
+
id: string;
|
|
8016
|
+
jobId: string;
|
|
8017
|
+
};
|
|
8018
|
+
cookie?: never;
|
|
8019
|
+
};
|
|
8020
|
+
requestBody?: never;
|
|
8021
|
+
responses: {
|
|
8022
|
+
/** @description The rendered PDF */
|
|
8023
|
+
200: {
|
|
8024
|
+
headers: {
|
|
8025
|
+
[name: string]: unknown;
|
|
8026
|
+
};
|
|
8027
|
+
content?: never;
|
|
8028
|
+
};
|
|
8029
|
+
/** @description PDF not yet ready (pending) or failed */
|
|
8030
|
+
202: {
|
|
8031
|
+
headers: {
|
|
8032
|
+
[name: string]: unknown;
|
|
8033
|
+
};
|
|
8034
|
+
content: {
|
|
8035
|
+
"application/json": components["schemas"]["MeetingRecordingExportJobStatus"];
|
|
8036
|
+
};
|
|
8037
|
+
};
|
|
8038
|
+
/** @description Recording or export job not found / not owned by this user */
|
|
8039
|
+
404: {
|
|
8040
|
+
headers: {
|
|
8041
|
+
[name: string]: unknown;
|
|
8042
|
+
};
|
|
8043
|
+
content?: never;
|
|
8044
|
+
};
|
|
8045
|
+
};
|
|
8046
|
+
};
|
|
8047
|
+
softDeleteMeetingRecording: {
|
|
8048
|
+
parameters: {
|
|
8049
|
+
query?: never;
|
|
8050
|
+
header?: never;
|
|
8051
|
+
path: {
|
|
8052
|
+
id: string;
|
|
8053
|
+
};
|
|
8054
|
+
cookie?: never;
|
|
8055
|
+
};
|
|
8056
|
+
requestBody?: never;
|
|
8057
|
+
responses: {
|
|
8058
|
+
/** @description Recording soft-deleted */
|
|
8059
|
+
200: {
|
|
8060
|
+
headers: {
|
|
8061
|
+
[name: string]: unknown;
|
|
8062
|
+
};
|
|
8063
|
+
content: {
|
|
8064
|
+
"application/json": components["schemas"]["SoftDeleteMeetingRecordingResponse"];
|
|
8065
|
+
};
|
|
8066
|
+
};
|
|
8067
|
+
/** @description Recording not found or not owned by this user */
|
|
8068
|
+
404: {
|
|
8069
|
+
headers: {
|
|
8070
|
+
[name: string]: unknown;
|
|
8071
|
+
};
|
|
8072
|
+
content?: never;
|
|
8073
|
+
};
|
|
8074
|
+
};
|
|
8075
|
+
};
|
|
8076
|
+
restoreMeetingRecording: {
|
|
8077
|
+
parameters: {
|
|
8078
|
+
query?: never;
|
|
8079
|
+
header?: never;
|
|
8080
|
+
path: {
|
|
8081
|
+
id: string;
|
|
8082
|
+
};
|
|
8083
|
+
cookie?: never;
|
|
8084
|
+
};
|
|
8085
|
+
requestBody?: never;
|
|
8086
|
+
responses: {
|
|
8087
|
+
/** @description Recording restored (or a no-op outside the window) */
|
|
8088
|
+
200: {
|
|
8089
|
+
headers: {
|
|
8090
|
+
[name: string]: unknown;
|
|
8091
|
+
};
|
|
8092
|
+
content: {
|
|
8093
|
+
"application/json": components["schemas"]["RestoreMeetingRecordingResponse"];
|
|
8094
|
+
};
|
|
8095
|
+
};
|
|
8096
|
+
/** @description Recording not found or not owned by this user */
|
|
8097
|
+
404: {
|
|
8098
|
+
headers: {
|
|
8099
|
+
[name: string]: unknown;
|
|
8100
|
+
};
|
|
8101
|
+
content?: never;
|
|
8102
|
+
};
|
|
8103
|
+
};
|
|
8104
|
+
};
|
|
8105
|
+
changeMeetingRecordingVisibility: {
|
|
8106
|
+
parameters: {
|
|
8107
|
+
query?: never;
|
|
8108
|
+
header?: never;
|
|
8109
|
+
path: {
|
|
8110
|
+
id: string;
|
|
8111
|
+
};
|
|
8112
|
+
cookie?: never;
|
|
8113
|
+
};
|
|
8114
|
+
requestBody: {
|
|
8115
|
+
content: {
|
|
8116
|
+
"application/json": components["schemas"]["ChangeMeetingRecordingVisibilityRequest"];
|
|
8117
|
+
};
|
|
8118
|
+
};
|
|
8119
|
+
responses: {
|
|
8120
|
+
/** @description Visibility changed */
|
|
8121
|
+
200: {
|
|
8122
|
+
headers: {
|
|
8123
|
+
[name: string]: unknown;
|
|
8124
|
+
};
|
|
8125
|
+
content: {
|
|
8126
|
+
"application/json": components["schemas"]["ChangeMeetingRecordingVisibilityResponse"];
|
|
8127
|
+
};
|
|
8128
|
+
};
|
|
8129
|
+
/** @description Recording not found or not owned by this user */
|
|
8130
|
+
404: {
|
|
8131
|
+
headers: {
|
|
8132
|
+
[name: string]: unknown;
|
|
8133
|
+
};
|
|
8134
|
+
content?: never;
|
|
8135
|
+
};
|
|
8136
|
+
/** @description Cannot change visibility while recording (pre-finalize) */
|
|
8137
|
+
409: {
|
|
8138
|
+
headers: {
|
|
8139
|
+
[name: string]: unknown;
|
|
8140
|
+
};
|
|
8141
|
+
content?: never;
|
|
8142
|
+
};
|
|
8143
|
+
};
|
|
8144
|
+
};
|
|
7786
8145
|
startImpersonation: {
|
|
7787
8146
|
parameters: {
|
|
7788
8147
|
query?: never;
|
package/src/index.ts
CHANGED
|
@@ -747,3 +747,8 @@ export type {
|
|
|
747
747
|
// Meeting recorder vocabulary (PRD-00651)
|
|
748
748
|
// @see ./meetings/schemas.ts for invariants
|
|
749
749
|
export * from './meetings'
|
|
750
|
+
|
|
751
|
+
// Permission model vocabulary (PRD-00669 AUTH-001)
|
|
752
|
+
// AccessLevel / OrgChartRole / AccessSource — see ADR-CTRL-084..088.
|
|
753
|
+
// No consumers in this PRD; cutover starts in AUTH-002 (PRD-00670).
|
|
754
|
+
export * from './permissions'
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission Access Levels
|
|
3
|
+
*
|
|
4
|
+
* Canonical four-level access vocabulary for object permissions across
|
|
5
|
+
* Company Semantics, modeled on the Google-Docs four-level scheme.
|
|
6
|
+
*
|
|
7
|
+
* Authority: ADR-CTRL-085 (Rights Table). See ADR-CTRL-084 for how these
|
|
8
|
+
* levels are materialized into `effective_acl_grants`, and ADR-CTRL-086 for
|
|
9
|
+
* the aggregation rule (most-permissive across sources).
|
|
10
|
+
*
|
|
11
|
+
* The commenter level is currently a stub — see ADR-CTRL-087.
|
|
12
|
+
*/
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
|
|
15
|
+
export const ACCESS_LEVELS = ['owner', 'editor', 'commenter', 'viewer'] as const;
|
|
16
|
+
export type AccessLevel = (typeof ACCESS_LEVELS)[number];
|
|
17
|
+
|
|
18
|
+
export const AccessLevelSchema = z.enum(ACCESS_LEVELS);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Ordered weakest → strongest. Index = ranking.
|
|
22
|
+
* Used by `highestGrant()` in AUTH-006 (PRD-00674) to aggregate across sources.
|
|
23
|
+
*/
|
|
24
|
+
export const ACCESS_LEVEL_ORDER: Record<AccessLevel, number> = {
|
|
25
|
+
viewer: 0,
|
|
26
|
+
commenter: 1,
|
|
27
|
+
editor: 2,
|
|
28
|
+
owner: 3,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns true when `actual` is at least as strong as `required`.
|
|
33
|
+
* Examples:
|
|
34
|
+
* isAtLeast('editor', 'viewer') === true
|
|
35
|
+
* isAtLeast('viewer', 'editor') === false
|
|
36
|
+
* isAtLeast('owner', 'owner') === true
|
|
37
|
+
*/
|
|
38
|
+
export function isAtLeast(actual: AccessLevel, required: AccessLevel): boolean {
|
|
39
|
+
return ACCESS_LEVEL_ORDER[actual] >= ACCESS_LEVEL_ORDER[required];
|
|
40
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access Source
|
|
3
|
+
*
|
|
4
|
+
* Provenance tag on rows in `effective_acl_grants`. Each row is materialized
|
|
5
|
+
* from exactly one input source; multiple rows for the same
|
|
6
|
+
* (entity, principal) pair are allowed, one per source.
|
|
7
|
+
*
|
|
8
|
+
* Authority: ADR-CTRL-084 (Permission Resolution Architecture).
|
|
9
|
+
*
|
|
10
|
+
* Sources:
|
|
11
|
+
* - `explicit` — direct `acl_grants` row
|
|
12
|
+
* - `ownership` — entity.owner_user_id column projection
|
|
13
|
+
* - `visibility` — entity.visibility tier compiled to viewer rows
|
|
14
|
+
* - `inheritance` — org-chart-membership-based unit walk
|
|
15
|
+
* - `migration` — one-shot backfill from legacy systems (AUTH-004)
|
|
16
|
+
*/
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
|
|
19
|
+
export const ACCESS_SOURCES = [
|
|
20
|
+
'explicit',
|
|
21
|
+
'ownership',
|
|
22
|
+
'visibility',
|
|
23
|
+
'inheritance',
|
|
24
|
+
'migration',
|
|
25
|
+
] as const;
|
|
26
|
+
export type AccessSource = (typeof ACCESS_SOURCES)[number];
|
|
27
|
+
|
|
28
|
+
export const AccessSourceSchema = z.enum(ACCESS_SOURCES);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permissions Vocabulary Barrel
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the three canonical enums introduced in AUTH-001 (PRD-00669).
|
|
5
|
+
* Import from '@company-semantics/contracts' (root).
|
|
6
|
+
*/
|
|
7
|
+
export * from './access-levels';
|
|
8
|
+
export * from './orgchart-roles';
|
|
9
|
+
export * from './access-source';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Org-Chart Roles
|
|
3
|
+
*
|
|
4
|
+
* Canonical four-role vocabulary for subtree-CRUD authority on org_units.
|
|
5
|
+
*
|
|
6
|
+
* Authority: ADR-CTRL-088 (Org-Chart Roles).
|
|
7
|
+
*
|
|
8
|
+
* These roles govern only member CRUD on a unit and its ltree descendants.
|
|
9
|
+
* They never grant object access — object access flows through ownership +
|
|
10
|
+
* ACL + visibility + inheritance per ADR-CTRL-084.
|
|
11
|
+
*
|
|
12
|
+
* Consumers: AUTH-006 policy registry (PRD-00674),
|
|
13
|
+
* AUTH-009 org-chart member CRUD UI (PRD-00677),
|
|
14
|
+
* AUTH-011C strict-guard flip (PRD-00681).
|
|
15
|
+
*
|
|
16
|
+
* The legacy `WorkspaceRole` and `OrgUnitMembershipRole` enums coexist with
|
|
17
|
+
* this enum until AUTH-011C deletes them.
|
|
18
|
+
*/
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
|
|
21
|
+
export const ORG_CHART_ROLES = ['ceo', 'leader', 'delegate', 'admin'] as const;
|
|
22
|
+
export type OrgChartRole = (typeof ORG_CHART_ROLES)[number];
|
|
23
|
+
|
|
24
|
+
export const OrgChartRoleSchema = z.enum(ORG_CHART_ROLES);
|