@company-semantics/contracts 0.95.0 → 0.97.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "0.95.0",
3
+ "version": "0.97.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
package/src/index.ts CHANGED
@@ -250,6 +250,23 @@ export type {
250
250
  GoalDependency,
251
251
  GoalTreeNode,
252
252
  GoalDoc,
253
+ // Team types (PRD-00306)
254
+ TeamMembershipRole,
255
+ TeamSyncMode,
256
+ Team,
257
+ TeamMember,
258
+ TeamDetail,
259
+ // Sharing and ACL types (PRD-00306)
260
+ AccessLevel,
261
+ SharePolicy,
262
+ AclEntry,
263
+ AccessSource,
264
+ AccessReason,
265
+ EffectiveAccess,
266
+ EvaluationStep,
267
+ AccessExplanation,
268
+ ShareState,
269
+ PermissionAuditEntry,
253
270
  } from './org/index'
254
271
 
255
272
  export { ROLE_DISPLAY_MAP, VIEW_SCOPE_MAP, getViewScope, TRANSFER_RESPONSIBILITIES, IDENTITY_TRUST_LEVEL_LABELS } from './org/index'
@@ -6,12 +6,14 @@ describe('VIEW_SCOPE_MAP golden snapshot', () => {
6
6
  expect(VIEW_SCOPE_MAP).toStrictEqual({
7
7
  workspace: 'org.view_workspace',
8
8
  timeline: 'org.view_timeline',
9
- activity: 'org.view_activity',
9
+ teamwork: 'org.view_teamwork',
10
10
  goals: 'org.view_goals',
11
+ teams: 'org.view_teams',
11
12
  'internal-admin': 'internal.view_admin',
12
13
  chat: null,
13
14
  settings: null,
14
15
  chats: null,
16
+ 'my-work': null,
15
17
  upgrade: null,
16
18
  })
17
19
  })
@@ -21,7 +23,7 @@ describe('getViewScope', () => {
21
23
  it('returns the required scope for protected views', () => {
22
24
  expect(getViewScope('workspace')).toBe('org.view_workspace')
23
25
  expect(getViewScope('timeline')).toBe('org.view_timeline')
24
- expect(getViewScope('activity')).toBe('org.view_activity')
26
+ expect(getViewScope('teamwork')).toBe('org.view_teamwork')
25
27
  expect(getViewScope('goals')).toBe('org.view_goals')
26
28
  expect(getViewScope('internal-admin')).toBe('internal.view_admin')
27
29
  })
package/src/org/goals.ts CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  export type GoalVisibility = 'public' | 'private';
10
10
 
11
- export type GoalDocLevel = 'root' | 'department';
11
+ export type GoalDocLevel = 'root' | 'department' | 'team';
12
12
 
13
13
  export interface GoalSource {
14
14
  readonly label: string;
@@ -30,6 +30,8 @@ export interface GoalTreeNode {
30
30
  readonly visibility: GoalVisibility;
31
31
  readonly canEdit: boolean;
32
32
  readonly memberCount: number;
33
+ /** Owning team. Null for root docs or when the owning team has been deleted. */
34
+ readonly owningTeam: { readonly id: string; readonly name: string } | null;
33
35
  }
34
36
 
35
37
  export interface GoalDocCore {
@@ -41,6 +43,8 @@ export interface GoalDocCore {
41
43
  readonly content: string;
42
44
  readonly visibility: GoalVisibility;
43
45
  readonly parentId: string | null;
46
+ /** Owning team. Null for root docs or when the owning team has been deleted. */
47
+ readonly owningTeam: { readonly id: string; readonly name: string } | null;
44
48
  }
45
49
 
46
50
  export interface GoalDocCollaborators {
package/src/org/index.ts CHANGED
@@ -92,3 +92,26 @@ export type {
92
92
  GoalDocRelations,
93
93
  GoalDoc,
94
94
  } from './goals';
95
+
96
+ // Team types (PRD-00306)
97
+ export type {
98
+ TeamMembershipRole,
99
+ TeamSyncMode,
100
+ Team,
101
+ TeamMember,
102
+ TeamDetail,
103
+ } from './teams';
104
+
105
+ // Sharing and ACL types (PRD-00306)
106
+ export type {
107
+ AccessLevel,
108
+ SharePolicy,
109
+ AclEntry,
110
+ AccessSource,
111
+ AccessReason,
112
+ EffectiveAccess,
113
+ EvaluationStep,
114
+ AccessExplanation,
115
+ ShareState,
116
+ PermissionAuditEntry,
117
+ } from './sharing';
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Document access level.
3
+ * Privilege order: editor > commenter > viewer.
4
+ */
5
+ export type AccessLevel = 'viewer' | 'commenter' | 'editor';
6
+
7
+ /**
8
+ * Document sharing policy.
9
+ * - restricted: Only explicit ACL + owning team + org admins
10
+ * - org_read: All org members can view
11
+ * - org_comment: All org members can comment
12
+ * - org_edit: All org members can edit (does NOT imply canShare)
13
+ */
14
+ export type SharePolicy = 'restricted' | 'org_read' | 'org_comment' | 'org_edit';
15
+
16
+ export interface AclEntry {
17
+ readonly principalType: 'user' | 'team';
18
+ readonly principalId: string;
19
+ readonly principalName: string;
20
+ readonly accessLevel: AccessLevel;
21
+ readonly grantedBy: { readonly id: string; readonly name: string } | null;
22
+ readonly grantedAt: string;
23
+ }
24
+
25
+ /**
26
+ * Source of an access grant.
27
+ * Used in EffectiveAccess.reasons and EvaluationStep.source.
28
+ */
29
+ export type AccessSource = 'org_rbac' | 'sharing_policy' | 'team_baseline' | 'acl_grant' | 'doc_ownership';
30
+
31
+ export interface AccessReason {
32
+ readonly source: AccessSource;
33
+ readonly detail: string;
34
+ }
35
+
36
+ /**
37
+ * Effective access for a user on a document.
38
+ *
39
+ * INVARIANTS:
40
+ * - canShare is granted ONLY by: doc ownership, team ownership of owning team,
41
+ * or org-level org.manage_goals / org.manage_teams.
42
+ * - canShare is NEVER granted by ACL entries or sharing policy.
43
+ * - org_edit via sharing policy does NOT imply canShare.
44
+ * - Team membership grants baseline access ONLY to resources owned by that team.
45
+ */
46
+ export interface EffectiveAccess {
47
+ readonly level: 'none' | AccessLevel;
48
+ readonly reasons: ReadonlyArray<AccessReason>;
49
+ readonly canShare: boolean;
50
+ }
51
+
52
+ /**
53
+ * Single step in the access evaluation trace.
54
+ * Enables full traceability for debugging, audit UI, and compliance.
55
+ */
56
+ export interface EvaluationStep {
57
+ readonly source: AccessSource;
58
+ readonly checked: boolean;
59
+ readonly granted: AccessLevel | null;
60
+ readonly detail: string;
61
+ }
62
+
63
+ /**
64
+ * Full access explanation with evaluation trace.
65
+ * Returned by GoalsAccessEvaluator.explain().
66
+ */
67
+ export interface AccessExplanation extends EffectiveAccess {
68
+ readonly evaluationTrace: ReadonlyArray<EvaluationStep>;
69
+ }
70
+
71
+ /**
72
+ * Complete sharing state for a document.
73
+ * Returned by GET /api/goals/docs/:slug/sharing.
74
+ */
75
+ export interface ShareState {
76
+ readonly sharingPolicy: SharePolicy;
77
+ readonly acl: ReadonlyArray<AclEntry>;
78
+ readonly effectiveAccess: EffectiveAccess;
79
+ }
80
+
81
+ /**
82
+ * Single entry in the permission change audit log.
83
+ * Used by audit views to display a history of permission changes.
84
+ */
85
+ export interface PermissionAuditEntry {
86
+ readonly action: 'granted' | 'revoked' | 'updated';
87
+ readonly resourceType: 'goals_doc' | 'team';
88
+ readonly resourceId: string;
89
+ readonly resourceName: string;
90
+ readonly principalType: 'user' | 'team';
91
+ readonly principalId: string;
92
+ readonly principalName: string;
93
+ readonly detail: string;
94
+ readonly actorId: string;
95
+ readonly actorName: string;
96
+ readonly timestamp: string;
97
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Team membership role.
3
+ * Privilege order: owner > manager > member.
4
+ * Effective role = max(role by privilege) across all active rows for a (team_id, user_id) pair.
5
+ * Rows with status != 'active' are ignored.
6
+ */
7
+ export type TeamMembershipRole = 'member' | 'manager' | 'owner';
8
+
9
+ /**
10
+ * Team membership sync mode.
11
+ * - manual_only: All in-app membership mutations allowed
12
+ * - synced_readonly: Rejects all in-app membership changes (external source is authority)
13
+ * - synced_with_overrides: Allows manual additions; sync-sourced rows are read-only
14
+ */
15
+ export type TeamSyncMode = 'manual_only' | 'synced_readonly' | 'synced_with_overrides';
16
+
17
+ /**
18
+ * Team read model for list views.
19
+ */
20
+ export interface Team {
21
+ readonly id: string;
22
+ readonly name: string;
23
+ readonly slug: string;
24
+ readonly description: string | null;
25
+ readonly memberCount: number;
26
+ }
27
+
28
+ /**
29
+ * Team member within a team detail view.
30
+ */
31
+ export interface TeamMember {
32
+ readonly userId: string;
33
+ readonly name: string;
34
+ readonly email: string;
35
+ readonly role: TeamMembershipRole;
36
+ readonly joinedAt: string;
37
+ }
38
+
39
+ /**
40
+ * Full team detail view including members.
41
+ * Returned by GET /api/teams/:teamId.
42
+ */
43
+ export interface TeamDetail extends Team {
44
+ readonly members: ReadonlyArray<TeamMember>;
45
+ readonly syncMode: TeamSyncMode;
46
+ }
@@ -19,13 +19,15 @@ export const VIEW_SCOPE_MAP = {
19
19
  // Protected views (require specific scope)
20
20
  workspace: 'org.view_workspace',
21
21
  timeline: 'org.view_timeline',
22
- activity: 'org.view_activity',
22
+ teamwork: 'org.view_teamwork',
23
23
  goals: 'org.view_goals',
24
+ teams: 'org.view_teams',
24
25
  'internal-admin': 'internal.view_admin',
25
26
  // Public views (require only authentication)
26
27
  chat: null,
27
28
  settings: null,
28
29
  chats: null,
30
+ 'my-work': null,
29
31
  upgrade: null,
30
32
  } as const;
31
33