@trycompai/db 2.0.0 → 2.0.2

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.
Files changed (268) hide show
  1. package/dist/client.d.ts +2 -2
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +24 -3
  4. package/dist/schema.prisma +921 -546
  5. package/dist/scripts/backfill-framework-versions.d.ts +6 -0
  6. package/dist/scripts/backfill-framework-versions.d.ts.map +1 -0
  7. package/dist/scripts/backfill-framework-versions.js +142 -0
  8. package/package.json +5 -3
  9. package/dist/client.ts +0 -7
  10. package/dist/generated/prisma/client.d.ts +0 -427
  11. package/dist/generated/prisma/client.d.ts.map +0 -1
  12. package/dist/generated/prisma/client.js +0 -73
  13. package/dist/generated/prisma/commonInputTypes.d.ts +0 -2082
  14. package/dist/generated/prisma/commonInputTypes.d.ts.map +0 -1
  15. package/dist/generated/prisma/commonInputTypes.js +0 -11
  16. package/dist/generated/prisma/enums.d.ts +0 -367
  17. package/dist/generated/prisma/enums.d.ts.map +0 -1
  18. package/dist/generated/prisma/enums.js +0 -329
  19. package/dist/generated/prisma/internal/class.d.ts +0 -1000
  20. package/dist/generated/prisma/internal/class.d.ts.map +0 -1
  21. package/dist/generated/prisma/internal/class.js +0 -87
  22. package/dist/generated/prisma/internal/prismaNamespace.d.ts +0 -8063
  23. package/dist/generated/prisma/internal/prismaNamespace.d.ts.map +0 -1
  24. package/dist/generated/prisma/internal/prismaNamespace.js +0 -1256
  25. package/dist/generated/prisma/models/Account.d.ts +0 -1456
  26. package/dist/generated/prisma/models/Account.d.ts.map +0 -1
  27. package/dist/generated/prisma/models/Account.js +0 -2
  28. package/dist/generated/prisma/models/ApiKey.d.ts +0 -1387
  29. package/dist/generated/prisma/models/ApiKey.d.ts.map +0 -1
  30. package/dist/generated/prisma/models/ApiKey.js +0 -2
  31. package/dist/generated/prisma/models/Attachment.d.ts +0 -1520
  32. package/dist/generated/prisma/models/Attachment.d.ts.map +0 -1
  33. package/dist/generated/prisma/models/Attachment.js +0 -2
  34. package/dist/generated/prisma/models/AuditLog.d.ts +0 -1590
  35. package/dist/generated/prisma/models/AuditLog.d.ts.map +0 -1
  36. package/dist/generated/prisma/models/AuditLog.js +0 -2
  37. package/dist/generated/prisma/models/BrowserAutomation.d.ts +0 -1507
  38. package/dist/generated/prisma/models/BrowserAutomation.d.ts.map +0 -1
  39. package/dist/generated/prisma/models/BrowserAutomation.js +0 -2
  40. package/dist/generated/prisma/models/BrowserAutomationRun.d.ts +0 -1455
  41. package/dist/generated/prisma/models/BrowserAutomationRun.d.ts.map +0 -1
  42. package/dist/generated/prisma/models/BrowserAutomationRun.js +0 -2
  43. package/dist/generated/prisma/models/BrowserbaseContext.d.ts +0 -1139
  44. package/dist/generated/prisma/models/BrowserbaseContext.d.ts.map +0 -1
  45. package/dist/generated/prisma/models/BrowserbaseContext.js +0 -2
  46. package/dist/generated/prisma/models/Comment.d.ts +0 -1502
  47. package/dist/generated/prisma/models/Comment.d.ts.map +0 -1
  48. package/dist/generated/prisma/models/Comment.js +0 -2
  49. package/dist/generated/prisma/models/Context.d.ts +0 -1254
  50. package/dist/generated/prisma/models/Context.d.ts.map +0 -1
  51. package/dist/generated/prisma/models/Context.js +0 -2
  52. package/dist/generated/prisma/models/Control.d.ts +0 -1965
  53. package/dist/generated/prisma/models/Control.d.ts.map +0 -1
  54. package/dist/generated/prisma/models/Control.js +0 -2
  55. package/dist/generated/prisma/models/ControlDocumentType.d.ts +0 -1115
  56. package/dist/generated/prisma/models/ControlDocumentType.d.ts.map +0 -1
  57. package/dist/generated/prisma/models/ControlDocumentType.js +0 -2
  58. package/dist/generated/prisma/models/Device.d.ts +0 -1858
  59. package/dist/generated/prisma/models/Device.d.ts.map +0 -1
  60. package/dist/generated/prisma/models/Device.js +0 -2
  61. package/dist/generated/prisma/models/DynamicCheck.d.ts +0 -1517
  62. package/dist/generated/prisma/models/DynamicCheck.d.ts.map +0 -1
  63. package/dist/generated/prisma/models/DynamicCheck.js +0 -2
  64. package/dist/generated/prisma/models/DynamicIntegration.d.ts +0 -1528
  65. package/dist/generated/prisma/models/DynamicIntegration.d.ts.map +0 -1
  66. package/dist/generated/prisma/models/DynamicIntegration.js +0 -2
  67. package/dist/generated/prisma/models/EmployeeTrainingVideoCompletion.d.ts +0 -1146
  68. package/dist/generated/prisma/models/EmployeeTrainingVideoCompletion.d.ts.map +0 -1
  69. package/dist/generated/prisma/models/EmployeeTrainingVideoCompletion.js +0 -2
  70. package/dist/generated/prisma/models/EvidenceAutomation.d.ts +0 -1533
  71. package/dist/generated/prisma/models/EvidenceAutomation.d.ts.map +0 -1
  72. package/dist/generated/prisma/models/EvidenceAutomation.js +0 -2
  73. package/dist/generated/prisma/models/EvidenceAutomationRun.d.ts +0 -1833
  74. package/dist/generated/prisma/models/EvidenceAutomationRun.d.ts.map +0 -1
  75. package/dist/generated/prisma/models/EvidenceAutomationRun.js +0 -2
  76. package/dist/generated/prisma/models/EvidenceAutomationVersion.d.ts +0 -1331
  77. package/dist/generated/prisma/models/EvidenceAutomationVersion.d.ts.map +0 -1
  78. package/dist/generated/prisma/models/EvidenceAutomationVersion.js +0 -2
  79. package/dist/generated/prisma/models/EvidenceSubmission.d.ts +0 -1905
  80. package/dist/generated/prisma/models/EvidenceSubmission.d.ts.map +0 -1
  81. package/dist/generated/prisma/models/EvidenceSubmission.js +0 -2
  82. package/dist/generated/prisma/models/Finding.d.ts +0 -2386
  83. package/dist/generated/prisma/models/Finding.d.ts.map +0 -1
  84. package/dist/generated/prisma/models/Finding.js +0 -2
  85. package/dist/generated/prisma/models/FindingTemplate.d.ts +0 -1264
  86. package/dist/generated/prisma/models/FindingTemplate.d.ts.map +0 -1
  87. package/dist/generated/prisma/models/FindingTemplate.js +0 -2
  88. package/dist/generated/prisma/models/FleetPolicyResult.d.ts +0 -1484
  89. package/dist/generated/prisma/models/FleetPolicyResult.d.ts.map +0 -1
  90. package/dist/generated/prisma/models/FleetPolicyResult.js +0 -2
  91. package/dist/generated/prisma/models/FrameworkEditorControlTemplate.d.ts +0 -1669
  92. package/dist/generated/prisma/models/FrameworkEditorControlTemplate.d.ts.map +0 -1
  93. package/dist/generated/prisma/models/FrameworkEditorControlTemplate.js +0 -2
  94. package/dist/generated/prisma/models/FrameworkEditorFramework.d.ts +0 -1581
  95. package/dist/generated/prisma/models/FrameworkEditorFramework.d.ts.map +0 -1
  96. package/dist/generated/prisma/models/FrameworkEditorFramework.js +0 -2
  97. package/dist/generated/prisma/models/FrameworkEditorPolicyTemplate.d.ts +0 -1428
  98. package/dist/generated/prisma/models/FrameworkEditorPolicyTemplate.d.ts.map +0 -1
  99. package/dist/generated/prisma/models/FrameworkEditorPolicyTemplate.js +0 -2
  100. package/dist/generated/prisma/models/FrameworkEditorRequirement.d.ts +0 -1525
  101. package/dist/generated/prisma/models/FrameworkEditorRequirement.d.ts.map +0 -1
  102. package/dist/generated/prisma/models/FrameworkEditorRequirement.js +0 -2
  103. package/dist/generated/prisma/models/FrameworkEditorTaskTemplate.d.ts +0 -1434
  104. package/dist/generated/prisma/models/FrameworkEditorTaskTemplate.d.ts.map +0 -1
  105. package/dist/generated/prisma/models/FrameworkEditorTaskTemplate.js +0 -2
  106. package/dist/generated/prisma/models/FrameworkEditorVideo.d.ts +0 -1054
  107. package/dist/generated/prisma/models/FrameworkEditorVideo.d.ts.map +0 -1
  108. package/dist/generated/prisma/models/FrameworkEditorVideo.js +0 -2
  109. package/dist/generated/prisma/models/FrameworkInstance.d.ts +0 -1321
  110. package/dist/generated/prisma/models/FrameworkInstance.d.ts.map +0 -1
  111. package/dist/generated/prisma/models/FrameworkInstance.js +0 -2
  112. package/dist/generated/prisma/models/GlobalVendors.d.ts +0 -1358
  113. package/dist/generated/prisma/models/GlobalVendors.d.ts.map +0 -1
  114. package/dist/generated/prisma/models/GlobalVendors.js +0 -2
  115. package/dist/generated/prisma/models/Integration.d.ts +0 -1363
  116. package/dist/generated/prisma/models/Integration.d.ts.map +0 -1
  117. package/dist/generated/prisma/models/Integration.js +0 -2
  118. package/dist/generated/prisma/models/IntegrationCheckResult.d.ts +0 -1408
  119. package/dist/generated/prisma/models/IntegrationCheckResult.d.ts.map +0 -1
  120. package/dist/generated/prisma/models/IntegrationCheckResult.js +0 -2
  121. package/dist/generated/prisma/models/IntegrationCheckRun.d.ts +0 -1958
  122. package/dist/generated/prisma/models/IntegrationCheckRun.d.ts.map +0 -1
  123. package/dist/generated/prisma/models/IntegrationCheckRun.js +0 -2
  124. package/dist/generated/prisma/models/IntegrationConnection.d.ts +0 -2472
  125. package/dist/generated/prisma/models/IntegrationConnection.d.ts.map +0 -1
  126. package/dist/generated/prisma/models/IntegrationConnection.js +0 -2
  127. package/dist/generated/prisma/models/IntegrationCredentialVersion.d.ts +0 -1298
  128. package/dist/generated/prisma/models/IntegrationCredentialVersion.d.ts.map +0 -1
  129. package/dist/generated/prisma/models/IntegrationCredentialVersion.js +0 -2
  130. package/dist/generated/prisma/models/IntegrationOAuthApp.d.ts +0 -1362
  131. package/dist/generated/prisma/models/IntegrationOAuthApp.d.ts.map +0 -1
  132. package/dist/generated/prisma/models/IntegrationOAuthApp.js +0 -2
  133. package/dist/generated/prisma/models/IntegrationOAuthState.d.ts +0 -1131
  134. package/dist/generated/prisma/models/IntegrationOAuthState.d.ts.map +0 -1
  135. package/dist/generated/prisma/models/IntegrationOAuthState.js +0 -2
  136. package/dist/generated/prisma/models/IntegrationPlatformCredential.d.ts +0 -1237
  137. package/dist/generated/prisma/models/IntegrationPlatformCredential.d.ts.map +0 -1
  138. package/dist/generated/prisma/models/IntegrationPlatformCredential.js +0 -2
  139. package/dist/generated/prisma/models/IntegrationPlatformFinding.d.ts +0 -1652
  140. package/dist/generated/prisma/models/IntegrationPlatformFinding.d.ts.map +0 -1
  141. package/dist/generated/prisma/models/IntegrationPlatformFinding.js +0 -2
  142. package/dist/generated/prisma/models/IntegrationProvider.d.ts +0 -1300
  143. package/dist/generated/prisma/models/IntegrationProvider.d.ts.map +0 -1
  144. package/dist/generated/prisma/models/IntegrationProvider.js +0 -2
  145. package/dist/generated/prisma/models/IntegrationResult.d.ts +0 -1539
  146. package/dist/generated/prisma/models/IntegrationResult.d.ts.map +0 -1
  147. package/dist/generated/prisma/models/IntegrationResult.js +0 -2
  148. package/dist/generated/prisma/models/IntegrationRun.d.ts +0 -1596
  149. package/dist/generated/prisma/models/IntegrationRun.d.ts.map +0 -1
  150. package/dist/generated/prisma/models/IntegrationRun.js +0 -2
  151. package/dist/generated/prisma/models/IntegrationSyncLog.d.ts +0 -1716
  152. package/dist/generated/prisma/models/IntegrationSyncLog.d.ts.map +0 -1
  153. package/dist/generated/prisma/models/IntegrationSyncLog.js +0 -2
  154. package/dist/generated/prisma/models/Invitation.d.ts +0 -1404
  155. package/dist/generated/prisma/models/Invitation.d.ts.map +0 -1
  156. package/dist/generated/prisma/models/Invitation.js +0 -2
  157. package/dist/generated/prisma/models/Jwks.d.ts +0 -998
  158. package/dist/generated/prisma/models/Jwks.d.ts.map +0 -1
  159. package/dist/generated/prisma/models/Jwks.js +0 -2
  160. package/dist/generated/prisma/models/KnowledgeBaseDocument.d.ts +0 -1463
  161. package/dist/generated/prisma/models/KnowledgeBaseDocument.d.ts.map +0 -1
  162. package/dist/generated/prisma/models/KnowledgeBaseDocument.js +0 -2
  163. package/dist/generated/prisma/models/Member.d.ts +0 -5530
  164. package/dist/generated/prisma/models/Member.d.ts.map +0 -1
  165. package/dist/generated/prisma/models/Member.js +0 -2
  166. package/dist/generated/prisma/models/Onboarding.d.ts +0 -1376
  167. package/dist/generated/prisma/models/Onboarding.d.ts.map +0 -1
  168. package/dist/generated/prisma/models/Onboarding.js +0 -2
  169. package/dist/generated/prisma/models/Organization.d.ts +0 -14367
  170. package/dist/generated/prisma/models/Organization.d.ts.map +0 -1
  171. package/dist/generated/prisma/models/Organization.js +0 -2
  172. package/dist/generated/prisma/models/OrganizationBilling.d.ts +0 -1222
  173. package/dist/generated/prisma/models/OrganizationBilling.d.ts.map +0 -1
  174. package/dist/generated/prisma/models/OrganizationBilling.js +0 -2
  175. package/dist/generated/prisma/models/OrganizationChart.d.ts +0 -1248
  176. package/dist/generated/prisma/models/OrganizationChart.d.ts.map +0 -1
  177. package/dist/generated/prisma/models/OrganizationChart.js +0 -2
  178. package/dist/generated/prisma/models/OrganizationRole.d.ts +0 -1251
  179. package/dist/generated/prisma/models/OrganizationRole.d.ts.map +0 -1
  180. package/dist/generated/prisma/models/OrganizationRole.js +0 -2
  181. package/dist/generated/prisma/models/PentestSubscription.d.ts +0 -1497
  182. package/dist/generated/prisma/models/PentestSubscription.d.ts.map +0 -1
  183. package/dist/generated/prisma/models/PentestSubscription.js +0 -2
  184. package/dist/generated/prisma/models/Policy.d.ts +0 -3356
  185. package/dist/generated/prisma/models/Policy.d.ts.map +0 -1
  186. package/dist/generated/prisma/models/Policy.js +0 -2
  187. package/dist/generated/prisma/models/PolicyVersion.d.ts +0 -1619
  188. package/dist/generated/prisma/models/PolicyVersion.d.ts.map +0 -1
  189. package/dist/generated/prisma/models/PolicyVersion.js +0 -2
  190. package/dist/generated/prisma/models/Questionnaire.d.ts +0 -1808
  191. package/dist/generated/prisma/models/Questionnaire.d.ts.map +0 -1
  192. package/dist/generated/prisma/models/Questionnaire.js +0 -2
  193. package/dist/generated/prisma/models/QuestionnaireQuestionAnswer.d.ts +0 -1422
  194. package/dist/generated/prisma/models/QuestionnaireQuestionAnswer.d.ts.map +0 -1
  195. package/dist/generated/prisma/models/QuestionnaireQuestionAnswer.js +0 -2
  196. package/dist/generated/prisma/models/RequirementMap.d.ts +0 -1345
  197. package/dist/generated/prisma/models/RequirementMap.d.ts.map +0 -1
  198. package/dist/generated/prisma/models/RequirementMap.js +0 -2
  199. package/dist/generated/prisma/models/Risk.d.ts +0 -1975
  200. package/dist/generated/prisma/models/Risk.d.ts.map +0 -1
  201. package/dist/generated/prisma/models/Risk.js +0 -2
  202. package/dist/generated/prisma/models/RoleNotificationSetting.d.ts +0 -1391
  203. package/dist/generated/prisma/models/RoleNotificationSetting.d.ts.map +0 -1
  204. package/dist/generated/prisma/models/RoleNotificationSetting.js +0 -2
  205. package/dist/generated/prisma/models/SOAAnswer.d.ts +0 -1498
  206. package/dist/generated/prisma/models/SOAAnswer.d.ts.map +0 -1
  207. package/dist/generated/prisma/models/SOAAnswer.js +0 -2
  208. package/dist/generated/prisma/models/SOADocument.d.ts +0 -2272
  209. package/dist/generated/prisma/models/SOADocument.d.ts.map +0 -1
  210. package/dist/generated/prisma/models/SOADocument.js +0 -2
  211. package/dist/generated/prisma/models/SOAFrameworkConfiguration.d.ts +0 -1445
  212. package/dist/generated/prisma/models/SOAFrameworkConfiguration.d.ts.map +0 -1
  213. package/dist/generated/prisma/models/SOAFrameworkConfiguration.js +0 -2
  214. package/dist/generated/prisma/models/Secret.d.ts +0 -1321
  215. package/dist/generated/prisma/models/Secret.d.ts.map +0 -1
  216. package/dist/generated/prisma/models/Secret.js +0 -2
  217. package/dist/generated/prisma/models/SecurityPenetrationTestRun.d.ts +0 -1176
  218. package/dist/generated/prisma/models/SecurityPenetrationTestRun.d.ts.map +0 -1
  219. package/dist/generated/prisma/models/SecurityPenetrationTestRun.js +0 -2
  220. package/dist/generated/prisma/models/SecurityQuestionnaireManualAnswer.d.ts +0 -1510
  221. package/dist/generated/prisma/models/SecurityQuestionnaireManualAnswer.d.ts.map +0 -1
  222. package/dist/generated/prisma/models/SecurityQuestionnaireManualAnswer.js +0 -2
  223. package/dist/generated/prisma/models/Session.d.ts +0 -1351
  224. package/dist/generated/prisma/models/Session.d.ts.map +0 -1
  225. package/dist/generated/prisma/models/Session.js +0 -2
  226. package/dist/generated/prisma/models/Task.d.ts +0 -3980
  227. package/dist/generated/prisma/models/Task.d.ts.map +0 -1
  228. package/dist/generated/prisma/models/Task.js +0 -2
  229. package/dist/generated/prisma/models/TaskItem.d.ts +0 -1961
  230. package/dist/generated/prisma/models/TaskItem.d.ts.map +0 -1
  231. package/dist/generated/prisma/models/TaskItem.js +0 -2
  232. package/dist/generated/prisma/models/Trust.d.ts +0 -2242
  233. package/dist/generated/prisma/models/Trust.d.ts.map +0 -1
  234. package/dist/generated/prisma/models/Trust.js +0 -2
  235. package/dist/generated/prisma/models/TrustAccessGrant.d.ts +0 -1888
  236. package/dist/generated/prisma/models/TrustAccessGrant.d.ts.map +0 -1
  237. package/dist/generated/prisma/models/TrustAccessGrant.js +0 -2
  238. package/dist/generated/prisma/models/TrustAccessRequest.d.ts +0 -2103
  239. package/dist/generated/prisma/models/TrustAccessRequest.d.ts.map +0 -1
  240. package/dist/generated/prisma/models/TrustAccessRequest.js +0 -2
  241. package/dist/generated/prisma/models/TrustCustomLink.d.ts +0 -1354
  242. package/dist/generated/prisma/models/TrustCustomLink.d.ts.map +0 -1
  243. package/dist/generated/prisma/models/TrustCustomLink.js +0 -2
  244. package/dist/generated/prisma/models/TrustDocument.d.ts +0 -1281
  245. package/dist/generated/prisma/models/TrustDocument.d.ts.map +0 -1
  246. package/dist/generated/prisma/models/TrustDocument.js +0 -2
  247. package/dist/generated/prisma/models/TrustNDAAgreement.d.ts +0 -1877
  248. package/dist/generated/prisma/models/TrustNDAAgreement.d.ts.map +0 -1
  249. package/dist/generated/prisma/models/TrustNDAAgreement.js +0 -2
  250. package/dist/generated/prisma/models/TrustResource.d.ts +0 -1328
  251. package/dist/generated/prisma/models/TrustResource.d.ts.map +0 -1
  252. package/dist/generated/prisma/models/TrustResource.js +0 -2
  253. package/dist/generated/prisma/models/User.d.ts +0 -3070
  254. package/dist/generated/prisma/models/User.d.ts.map +0 -1
  255. package/dist/generated/prisma/models/User.js +0 -2
  256. package/dist/generated/prisma/models/Vendor.d.ts +0 -2307
  257. package/dist/generated/prisma/models/Vendor.d.ts.map +0 -1
  258. package/dist/generated/prisma/models/Vendor.js +0 -2
  259. package/dist/generated/prisma/models/VendorContact.d.ts +0 -1246
  260. package/dist/generated/prisma/models/VendorContact.d.ts.map +0 -1
  261. package/dist/generated/prisma/models/VendorContact.js +0 -2
  262. package/dist/generated/prisma/models/Verification.d.ts +0 -1026
  263. package/dist/generated/prisma/models/Verification.d.ts.map +0 -1
  264. package/dist/generated/prisma/models/Verification.js +0 -2
  265. package/dist/generated/prisma/models.d.ts +0 -82
  266. package/dist/generated/prisma/models.d.ts.map +0 -1
  267. package/dist/generated/prisma/models.js +0 -2
  268. package/dist/index.ts +0 -1
@@ -9,7 +9,6 @@ datasource db {
9
9
  extensions = [pgcrypto]
10
10
  }
11
11
 
12
-
13
12
  // ===== attachments.prisma =====
14
13
  model Attachment {
15
14
  id String @id @default(dbgenerated("generate_prefixed_cuid('att'::text)"))
@@ -49,7 +48,6 @@ enum AttachmentType {
49
48
  other
50
49
  }
51
50
 
52
-
53
51
  // ===== auth.prisma =====
54
52
  model User {
55
53
  id String @id @default(dbgenerated("generate_prefixed_cuid('usr'::text)"))
@@ -68,16 +66,20 @@ model User {
68
66
  banExpires DateTime?
69
67
  isPlatformAdmin Boolean @default(false)
70
68
 
71
- accounts Account[]
72
- auditLog AuditLog[]
73
- integrationResults IntegrationResult[]
74
- invitations Invitation[]
75
- members Member[]
76
- sessions Session[]
77
- fleetPolicyResults FleetPolicyResult[]
78
- evidenceSubmissions EvidenceSubmission[] @relation("EvidenceSubmitter")
79
- evidenceReviews EvidenceSubmission[] @relation("EvidenceReviewer")
80
- adminFindings Finding[] @relation("AdminFindingCreator")
69
+ accounts Account[]
70
+ auditLog AuditLog[]
71
+ integrationResults IntegrationResult[]
72
+ invitations Invitation[]
73
+ members Member[]
74
+ sessions Session[]
75
+ fleetPolicyResults FleetPolicyResult[]
76
+ evidenceSubmissions EvidenceSubmission[] @relation("EvidenceSubmitter")
77
+ evidenceReviews EvidenceSubmission[] @relation("EvidenceReviewer")
78
+ adminFindings Finding[] @relation("AdminFindingCreator")
79
+ timelinePhaseCompletions TimelinePhase[]
80
+ lockedTimelineInstances TimelineInstance[] @relation("TimelineInstanceLockedBy")
81
+ unlockedTimelineInstances TimelineInstance[] @relation("TimelineInstanceUnlockedBy")
82
+ publishedFrameworkVersions FrameworkVersion[] @relation("FrameworkVersionPublisher")
81
83
 
82
84
  @@unique([email])
83
85
  }
@@ -105,9 +107,15 @@ model Session {
105
107
  userId String
106
108
  activeOrganizationId String?
107
109
  impersonatedBy String?
108
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
110
+
111
+ deviceAgent Boolean @default(false)
112
+ deviceAgentFor Device[] @relation("DeviceAgentSession")
113
+
114
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
109
115
 
110
116
  @@unique([token])
117
+ @@index([userId])
118
+ @@index([deviceAgent])
111
119
  }
112
120
 
113
121
  model Account {
@@ -166,24 +174,26 @@ model Member {
166
174
  employeeTrainingVideoCompletion EmployeeTrainingVideoCompletion[]
167
175
  fleetDmLabelId Int?
168
176
 
169
- assignedPolicies Policy[] @relation("PolicyAssignee") // Policies where this member is an assignee
170
- approvedPolicies Policy[] @relation("PolicyApprover") // Policies where this member is an approver
171
- approvedSOADocuments SOADocument[] @relation("SOADocumentApprover") // SOA documents where this member is an approver
172
- risks Risk[]
173
- tasks Task[]
174
- vendors Vendor[]
175
- comments Comment[]
176
- auditLogs AuditLog[]
177
- reviewedAccessRequests TrustAccessRequest[] @relation("TrustAccessRequestReviewer")
178
- issuedGrants TrustAccessGrant[] @relation("IssuedGrants")
179
- revokedGrants TrustAccessGrant[] @relation("RevokedGrants")
180
- createdTaskItems TaskItem[] @relation("TaskItemCreator")
181
- updatedTaskItems TaskItem[] @relation("TaskItemUpdater")
182
- assignedTaskItems TaskItem[] @relation("TaskItemAssignee")
183
- createdFindings Finding[] @relation("FindingCreatedBy")
184
- publishedPolicyVersions PolicyVersion[] @relation("PolicyVersionPublisher")
185
- approvedTasks Task[] @relation("TaskApprover")
186
- devices Device[]
177
+ assignedPolicies Policy[] @relation("PolicyAssignee") // Policies where this member is an assignee
178
+ approvedPolicies Policy[] @relation("PolicyApprover") // Policies where this member is an approver
179
+ approvedSOADocuments SOADocument[] @relation("SOADocumentApprover") // SOA documents where this member is an approver
180
+ risks Risk[]
181
+ tasks Task[]
182
+ vendors Vendor[]
183
+ comments Comment[]
184
+ auditLogs AuditLog[]
185
+ reviewedAccessRequests TrustAccessRequest[] @relation("TrustAccessRequestReviewer")
186
+ issuedGrants TrustAccessGrant[] @relation("IssuedGrants")
187
+ revokedGrants TrustAccessGrant[] @relation("RevokedGrants")
188
+ createdTaskItems TaskItem[] @relation("TaskItemCreator")
189
+ updatedTaskItems TaskItem[] @relation("TaskItemUpdater")
190
+ assignedTaskItems TaskItem[] @relation("TaskItemAssignee")
191
+ createdFindings Finding[] @relation("FindingCreatedBy")
192
+ subjectFindings Finding[] @relation("FindingSubject")
193
+ publishedPolicyVersions PolicyVersion[] @relation("PolicyVersionPublisher")
194
+ performedFrameworkSyncOperations FrameworkSyncOperation[] @relation("FrameworkSyncOperationPerformer")
195
+ approvedTasks Task[] @relation("TaskApprover")
196
+ devices Device[]
187
197
  }
188
198
 
189
199
  model Invitation {
@@ -232,7 +242,6 @@ enum PolicyStatus {
232
242
  needs_review
233
243
  }
234
244
 
235
-
236
245
  // ===== automation-run.prisma =====
237
246
  model EvidenceAutomationRun {
238
247
  id String @id @default(dbgenerated("generate_prefixed_cuid('ear'::text)"))
@@ -290,7 +299,6 @@ enum EvidenceAutomationEvaluationStatus {
290
299
  fail
291
300
  }
292
301
 
293
-
294
302
  // ===== automation-version.prisma =====
295
303
  model EvidenceAutomationVersion {
296
304
  id String @id @default(dbgenerated("generate_prefixed_cuid('eav'::text)"))
@@ -312,14 +320,15 @@ model EvidenceAutomationVersion {
312
320
  @@index([createdAt])
313
321
  }
314
322
 
315
-
316
323
  // ===== automation.prisma =====
317
324
  model EvidenceAutomation {
318
- id String @id @default(dbgenerated("generate_prefixed_cuid('aut'::text)"))
319
- name String
320
- description String?
321
- createdAt DateTime @default(now())
322
- isEnabled Boolean @default(false)
325
+ id String @id @default(dbgenerated("generate_prefixed_cuid('aut'::text)"))
326
+ name String
327
+ description String?
328
+ createdAt DateTime @default(now())
329
+ isEnabled Boolean @default(false)
330
+ scheduleFrequency TaskFrequency @default(daily)
331
+ lastRunAt DateTime?
323
332
 
324
333
  chatHistory String?
325
334
  evaluationCriteria String?
@@ -334,106 +343,108 @@ model EvidenceAutomation {
334
343
  @@index([taskId])
335
344
  }
336
345
 
337
-
338
346
  // ===== browserbase-context.prisma =====
339
347
  /// Stores Browserbase context IDs for browser-based automation
340
348
  /// One context per organization - shared like a normal browser
341
349
  model BrowserbaseContext {
342
- id String @id @default(dbgenerated("generate_prefixed_cuid('bbc'::text)"))
350
+ id String @id @default(dbgenerated("generate_prefixed_cuid('bbc'::text)"))
343
351
 
344
- /// Organization that owns this browser context
345
- organizationId String @unique
346
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
352
+ /// Organization that owns this browser context
353
+ organizationId String @unique
354
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
347
355
 
348
- /// Browserbase context ID from their API
349
- contextId String
356
+ /// Browserbase context ID from their API
357
+ contextId String
350
358
 
351
- createdAt DateTime @default(now())
352
- updatedAt DateTime @updatedAt
359
+ createdAt DateTime @default(now())
360
+ updatedAt DateTime @updatedAt
353
361
 
354
- @@index([organizationId])
362
+ @@index([organizationId])
355
363
  }
356
364
 
357
365
  /// Browser automation configuration linked to a task
358
366
  model BrowserAutomation {
359
- id String @id @default(dbgenerated("generate_prefixed_cuid('bau'::text)"))
360
- name String
361
- description String?
367
+ id String @id @default(dbgenerated("generate_prefixed_cuid('bau'::text)"))
368
+ name String
369
+ description String?
362
370
 
363
- /// Task this automation belongs to
364
- taskId String
365
- task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
371
+ /// Task this automation belongs to
372
+ taskId String
373
+ task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
366
374
 
367
- /// Starting URL for the automation
368
- targetUrl String
375
+ /// Starting URL for the automation
376
+ targetUrl String
369
377
 
370
- /// Natural language instruction for the AI agent
371
- instruction String
378
+ /// Natural language instruction for the AI agent
379
+ instruction String
372
380
 
373
- /// Whether automation is enabled for scheduled runs
374
- isEnabled Boolean @default(false)
381
+ /// Optional natural-language criteria used to evaluate whether the
382
+ /// automation's outcome satisfies the auditor's requirement.
383
+ /// When null, runs don't produce a pass/fail verdict — only a screenshot.
384
+ evaluationCriteria String?
375
385
 
376
- /// Cron expression for scheduled runs (null = manual only)
377
- schedule String?
386
+ /// Whether automation is enabled for scheduled runs
387
+ isEnabled Boolean @default(false)
388
+ scheduleFrequency TaskFrequency @default(daily)
389
+ lastRunAt DateTime?
378
390
 
379
- createdAt DateTime @default(now())
380
- updatedAt DateTime @updatedAt
391
+ createdAt DateTime @default(now())
392
+ updatedAt DateTime @updatedAt
381
393
 
382
- runs BrowserAutomationRun[]
394
+ runs BrowserAutomationRun[]
383
395
 
384
- @@index([taskId])
396
+ @@index([taskId])
385
397
  }
386
398
 
387
399
  /// Records of browser automation executions
388
400
  model BrowserAutomationRun {
389
- id String @id @default(dbgenerated("generate_prefixed_cuid('bar'::text)"))
401
+ id String @id @default(dbgenerated("generate_prefixed_cuid('bar'::text)"))
390
402
 
391
- /// Parent automation
392
- automationId String
393
- automation BrowserAutomation @relation(fields: [automationId], references: [id], onDelete: Cascade)
403
+ /// Parent automation
404
+ automationId String
405
+ automation BrowserAutomation @relation(fields: [automationId], references: [id], onDelete: Cascade)
394
406
 
395
- /// Execution status
396
- status BrowserAutomationRunStatus @default(pending)
407
+ /// Execution status
408
+ status BrowserAutomationRunStatus @default(pending)
397
409
 
398
- /// Timestamps
399
- startedAt DateTime?
400
- completedAt DateTime?
410
+ /// Timestamps
411
+ startedAt DateTime?
412
+ completedAt DateTime?
401
413
 
402
- /// Duration in milliseconds
403
- durationMs Int?
414
+ /// Duration in milliseconds
415
+ durationMs Int?
404
416
 
405
- /// Screenshot URL in S3 (if successful)
406
- screenshotUrl String?
417
+ /// Screenshot URL in S3 (if successful)
418
+ screenshotUrl String?
407
419
 
408
- /// Evaluation result - whether the automation fulfilled the task requirements
409
- evaluationStatus BrowserAutomationEvaluationStatus?
420
+ /// Evaluation result - whether the automation fulfilled the task requirements
421
+ evaluationStatus BrowserAutomationEvaluationStatus?
410
422
 
411
- /// AI explanation of why it passed or failed
412
- evaluationReason String?
423
+ /// AI explanation of why it passed or failed
424
+ evaluationReason String?
413
425
 
414
- /// Error message (if failed)
415
- error String?
426
+ /// Error message (if failed)
427
+ error String?
416
428
 
417
- createdAt DateTime @default(now())
429
+ createdAt DateTime @default(now())
418
430
 
419
- @@index([automationId])
420
- @@index([status])
421
- @@index([createdAt])
431
+ @@index([automationId])
432
+ @@index([status])
433
+ @@index([createdAt])
422
434
  }
423
435
 
424
436
  enum BrowserAutomationEvaluationStatus {
425
- pass
426
- fail
437
+ pass
438
+ fail
427
439
  }
428
440
 
429
441
  enum BrowserAutomationRunStatus {
430
- pending
431
- running
432
- completed
433
- failed
442
+ pending
443
+ running
444
+ completed
445
+ failed
434
446
  }
435
447
 
436
-
437
448
  // ===== comment.prisma =====
438
449
  model Comment {
439
450
  id String @id @default(dbgenerated("generate_prefixed_cuid('cmt'::text)"))
@@ -463,7 +474,6 @@ enum CommentEntityType {
463
474
  policy
464
475
  }
465
476
 
466
-
467
477
  // ===== context.prisma =====
468
478
  model Context {
469
479
  id String @id @default(dbgenerated("generate_prefixed_cuid('ctx'::text)"))
@@ -484,7 +494,6 @@ model Context {
484
494
  @@index([tags])
485
495
  }
486
496
 
487
-
488
497
  // ===== control-document-type.prisma =====
489
498
  model ControlDocumentType {
490
499
  id String @id @default(dbgenerated("generate_prefixed_cuid('cdt'::text)"))
@@ -496,7 +505,6 @@ model ControlDocumentType {
496
505
  @@index([controlId])
497
506
  }
498
507
 
499
-
500
508
  // ===== control.prisma =====
501
509
  model Control {
502
510
  // Metadata
@@ -508,19 +516,67 @@ model Control {
508
516
  lastReviewDate DateTime?
509
517
  nextReviewDate DateTime?
510
518
 
519
+ // Sync-driven archive (set by FrameworkSyncOperation when the control
520
+ // template is removed from the framework's latest version and no other
521
+ // framework instance in the org still references it). Distinct from user
522
+ // archive (no user archive exists on Control today).
523
+ archivedAt DateTime?
524
+
511
525
  // Relationships
512
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
513
- organizationId String
514
- requirementsMapped RequirementMap[]
515
- tasks Task[]
516
- policies Policy[]
517
- controlTemplateId String?
518
- controlTemplate FrameworkEditorControlTemplate? @relation(fields: [controlTemplateId], references: [id])
526
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
527
+ organizationId String
528
+ requirementsMapped RequirementMap[]
529
+ tasks Task[]
530
+ policies Policy[]
531
+ controlTemplateId String?
532
+ controlTemplate FrameworkEditorControlTemplate? @relation(fields: [controlTemplateId], references: [id])
519
533
  controlDocumentTypes ControlDocumentType[]
520
534
 
521
535
  @@index([organizationId])
536
+ @@index([organizationId, archivedAt])
522
537
  }
523
538
 
539
+ // ===== custom-framework.prisma =====
540
+ model CustomFramework {
541
+ id String @id @default(dbgenerated("generate_prefixed_cuid('cfrm'::text)"))
542
+ name String
543
+ description String
544
+ version String @default("1.0.0")
545
+
546
+ organizationId String
547
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
548
+
549
+ requirements CustomRequirement[]
550
+ instances FrameworkInstance[]
551
+
552
+ createdAt DateTime @default(now())
553
+ updatedAt DateTime @default(now()) @updatedAt
554
+
555
+ @@unique([id, organizationId])
556
+ @@index([organizationId])
557
+ }
558
+
559
+ model CustomRequirement {
560
+ id String @id @default(dbgenerated("generate_prefixed_cuid('creq'::text)"))
561
+ name String
562
+ description String
563
+ identifier String
564
+
565
+ organizationId String
566
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
567
+ customFrameworkId String
568
+ // Composite FK onto (id, organizationId) so tenant consistency with the
569
+ // referenced CustomFramework is enforced at the DB level.
570
+ customFramework CustomFramework @relation(fields: [customFrameworkId, organizationId], references: [id, organizationId], onDelete: Cascade)
571
+
572
+ requirementMaps RequirementMap[]
573
+
574
+ createdAt DateTime @default(now())
575
+ updatedAt DateTime @default(now()) @updatedAt
576
+
577
+ @@unique([customFrameworkId, identifier])
578
+ @@index([organizationId])
579
+ }
524
580
 
525
581
  // ===== device.prisma =====
526
582
  model Device {
@@ -537,22 +593,28 @@ model Device {
537
593
  organizationId String
538
594
  organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
539
595
 
540
- isCompliant Boolean @default(false)
541
- diskEncryptionEnabled Boolean @default(false)
542
- antivirusEnabled Boolean @default(false)
543
- passwordPolicySet Boolean @default(false)
544
- screenLockEnabled Boolean @default(false)
596
+ agentSessionId String?
597
+ agentSession Session? @relation("DeviceAgentSession", fields: [agentSessionId], references: [id], onDelete: SetNull)
598
+
599
+ isCompliant Boolean @default(false)
600
+ diskEncryptionEnabled Boolean @default(false)
601
+ antivirusEnabled Boolean @default(false)
602
+ passwordPolicySet Boolean @default(false)
603
+ screenLockEnabled Boolean @default(false)
545
604
  checkDetails Json?
546
605
 
547
606
  lastCheckIn DateTime?
548
607
  agentVersion String?
549
- installedAt DateTime @default(now())
550
- updatedAt DateTime @updatedAt
608
+ installedAt DateTime @default(now())
609
+ updatedAt DateTime @updatedAt
610
+
611
+ findings Finding[]
551
612
 
552
613
  @@unique([serialNumber, organizationId])
553
614
  @@index([memberId])
554
615
  @@index([organizationId])
555
616
  @@index([isCompliant])
617
+ @@index([agentSessionId])
556
618
  }
557
619
 
558
620
  enum DevicePlatform {
@@ -561,7 +623,6 @@ enum DevicePlatform {
561
623
  linux
562
624
  }
563
625
 
564
-
565
626
  // ===== dynamic-integration.prisma =====
566
627
  // ===== Dynamic Integration Platform =====
567
628
  // Stores integration manifests and declarative check definitions in the database
@@ -569,93 +630,98 @@ enum DevicePlatform {
569
630
 
570
631
  /// Stores a full integration manifest as JSON — replaces hand-written TypeScript manifests
571
632
  model DynamicIntegration {
572
- id String @id @default(dbgenerated("generate_prefixed_cuid('din'::text)"))
573
- /// Unique slug (e.g., "azure-devops", "office-365")
574
- slug String @unique
575
- /// Display name
576
- name String
577
- /// Short description for catalog
578
- description String
579
- /// Category for grouping
580
- category String
581
- /// Logo URL
582
- logoUrl String
583
- /// URL to documentation
584
- docsUrl String?
633
+ id String @id @default(dbgenerated("generate_prefixed_cuid('din'::text)"))
634
+ /// Unique slug (e.g., "azure-devops", "office-365")
635
+ slug String @unique
636
+ /// Display name
637
+ name String
638
+ /// Short description for catalog
639
+ description String
640
+ /// Category for grouping
641
+ category String
642
+ /// Logo URL
643
+ logoUrl String
644
+ /// URL to documentation
645
+ docsUrl String?
585
646
 
586
- /// API base URL for ctx.fetch
587
- baseUrl String?
588
- /// Default headers (JSON object)
589
- defaultHeaders Json?
647
+ /// API base URL for ctx.fetch
648
+ baseUrl String?
649
+ /// Default headers (JSON object)
650
+ defaultHeaders Json?
590
651
 
591
- /// Auth strategy config (JSON — matches AuthStrategy type: oauth2/api_key/basic/jwt/custom)
592
- authConfig Json
652
+ /// Auth strategy config (JSON — matches AuthStrategy type: oauth2/api_key/basic/jwt/custom)
653
+ authConfig Json
593
654
 
594
- /// Capabilities JSON array (default ["checks"])
595
- capabilities Json @default("[\"checks\"]")
655
+ /// Capabilities JSON array (default ["checks"])
656
+ capabilities Json @default("[\"checks\"]")
596
657
 
597
- /// Whether multiple connections per org are allowed
598
- supportsMultipleConnections Boolean @default(false)
658
+ /// Whether multiple connections per org are allowed
659
+ supportsMultipleConnections Boolean @default(false)
599
660
 
600
- /// Declarative sync definition (JSON — DSL steps that produce employee list)
601
- /// When present and capabilities includes 'sync', enables employee sync
602
- syncDefinition Json?
661
+ /// Declarative sync definition (JSON — DSL steps that produce employee list)
662
+ /// When present and capabilities includes 'sync', enables employee sync
663
+ syncDefinition Json?
603
664
 
604
- /// Whether this dynamic integration is active
605
- isActive Boolean @default(true)
665
+ /// Services metadata (JSON array of { id, name, description, enabledByDefault?, implemented? })
666
+ services Json?
606
667
 
607
- createdAt DateTime @default(now())
608
- updatedAt DateTime @updatedAt
668
+ /// Whether this dynamic integration is active
669
+ isActive Boolean @default(true)
609
670
 
610
- checks DynamicCheck[]
671
+ createdAt DateTime @default(now())
672
+ updatedAt DateTime @updatedAt
673
+
674
+ checks DynamicCheck[]
611
675
 
612
- @@index([slug])
613
- @@index([category])
614
- @@index([isActive])
676
+ @@index([slug])
677
+ @@index([category])
678
+ @@index([isActive])
615
679
  }
616
680
 
617
681
  /// Stores a declarative check definition — DSL JSON replaces hand-written run() functions
618
682
  model DynamicCheck {
619
- id String @id @default(dbgenerated("generate_prefixed_cuid('dck'::text)"))
683
+ id String @id @default(dbgenerated("generate_prefixed_cuid('dck'::text)"))
620
684
 
621
- /// Parent integration
622
- integrationId String
623
- integration DynamicIntegration @relation(fields: [integrationId], references: [id], onDelete: Cascade)
685
+ /// Parent integration
686
+ integrationId String
687
+ integration DynamicIntegration @relation(fields: [integrationId], references: [id], onDelete: Cascade)
624
688
 
625
- /// Unique slug within integration (e.g., "mfa_enabled")
626
- checkSlug String
689
+ /// Unique slug within integration (e.g., "mfa_enabled")
690
+ checkSlug String
627
691
 
628
- /// Human-readable name
629
- name String
630
- /// Description of what this check does
631
- description String
692
+ /// Human-readable name
693
+ name String
694
+ /// Description of what this check does
695
+ description String
632
696
 
633
- /// Task template ID for auto-completion (references TASK_TEMPLATES)
634
- taskMapping String?
697
+ /// Task template ID for auto-completion (references TASK_TEMPLATES)
698
+ taskMapping String?
635
699
 
636
- /// Default severity for findings
637
- defaultSeverity String @default("medium")
700
+ /// Default severity for findings
701
+ defaultSeverity String @default("medium")
638
702
 
639
- /// Declarative DSL definition (JSON the step-by-step instructions)
640
- definition Json
703
+ /// Service ID this check belongs to (groups checks under a service)
704
+ service String?
641
705
 
642
- /// Check-level variables (JSON array of CheckVariable)
643
- variables Json @default("[]")
706
+ /// Declarative DSL definition (JSON the step-by-step instructions)
707
+ definition Json
644
708
 
645
- /// Whether this check is enabled
646
- isEnabled Boolean @default(true)
709
+ /// Check-level variables (JSON array of CheckVariable)
710
+ variables Json @default("[]")
647
711
 
648
- /// Display order
649
- sortOrder Int @default(0)
712
+ /// Whether this check is enabled
713
+ isEnabled Boolean @default(true)
650
714
 
651
- createdAt DateTime @default(now())
652
- updatedAt DateTime @updatedAt
715
+ /// Display order
716
+ sortOrder Int @default(0)
653
717
 
654
- @@unique([integrationId, checkSlug])
655
- @@index([integrationId])
656
- @@index([isEnabled])
657
- }
718
+ createdAt DateTime @default(now())
719
+ updatedAt DateTime @updatedAt
658
720
 
721
+ @@unique([integrationId, checkSlug])
722
+ @@index([integrationId])
723
+ @@index([isEnabled])
724
+ }
659
725
 
660
726
  // ===== evidence-submission.prisma =====
661
727
  model EvidenceSubmission {
@@ -682,7 +748,6 @@ model EvidenceSubmission {
682
748
  @@index([submittedById, status])
683
749
  }
684
750
 
685
-
686
751
  // ===== finding.prisma =====
687
752
  enum FindingType {
688
753
  soc2
@@ -696,6 +761,29 @@ enum FindingStatus {
696
761
  closed
697
762
  }
698
763
 
764
+ enum FindingSeverity {
765
+ low
766
+ medium
767
+ high
768
+ critical
769
+ }
770
+
771
+ enum FindingArea {
772
+ people
773
+ documents
774
+ compliance
775
+ // "General" buckets for cases where an auditor wants to log something like
776
+ // "no risks are tracked" or "the policy for X is missing" without picking a
777
+ // specific Risk/Vendor/Policy row.
778
+ risks
779
+ vendors
780
+ policies
781
+ // Legacy/unclassified bucket for rows backfilled from the old FindingScope
782
+ // enum (see migration 20260419120000). Not surfaced as a primary target
783
+ // option in the Create Finding sheet.
784
+ other
785
+ }
786
+
699
787
  model FindingTemplate {
700
788
  id String @id @default(dbgenerated("generate_prefixed_cuid('fnd_t'::text)"))
701
789
  category String // e.g., "evidence_issue", "further_evidence", "task_specific", "na_incorrect"
@@ -709,37 +797,57 @@ model FindingTemplate {
709
797
  }
710
798
 
711
799
  model Finding {
712
- id String @id @default(dbgenerated("generate_prefixed_cuid('fnd'::text)"))
713
- type FindingType @default(soc2)
714
- status FindingStatus @default(open)
800
+ id String @id @default(dbgenerated("generate_prefixed_cuid('fnd'::text)"))
801
+ type FindingType @default(soc2)
802
+ status FindingStatus @default(open)
803
+ severity FindingSeverity @default(medium)
715
804
  content String // Custom message or copied from template
716
805
  revisionNote String? // Auditor's note when requesting revision
806
+ area FindingArea? // Used when the finding is not tied to a specific item
717
807
 
718
808
  createdAt DateTime @default(now())
719
809
  updatedAt DateTime @updatedAt
720
810
 
721
- // Relationships
811
+ // Target relationships — exactly one target link should be set (task, evidenceSubmission,
812
+ // evidenceFormType, policy, vendor, risk, member, device) OR the `area` field for non-item findings.
722
813
  taskId String?
723
814
  task Task? @relation(fields: [taskId], references: [id], onDelete: Cascade)
724
815
  evidenceSubmissionId String?
725
816
  evidenceSubmission EvidenceSubmission? @relation(fields: [evidenceSubmissionId], references: [id], onDelete: Cascade)
726
817
  evidenceFormType EvidenceFormType?
727
- templateId String?
728
- template FindingTemplate? @relation(fields: [templateId], references: [id])
729
- createdById String?
730
- createdBy Member? @relation("FindingCreatedBy", fields: [createdById], references: [id])
731
- createdByAdminId String?
732
- createdByAdmin User? @relation("AdminFindingCreator", fields: [createdByAdminId], references: [id])
733
- organizationId String
734
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
818
+ policyId String?
819
+ policy Policy? @relation(fields: [policyId], references: [id], onDelete: Cascade)
820
+ vendorId String?
821
+ vendor Vendor? @relation(fields: [vendorId], references: [id], onDelete: Cascade)
822
+ riskId String?
823
+ risk Risk? @relation(fields: [riskId], references: [id], onDelete: Cascade)
824
+ memberId String?
825
+ member Member? @relation("FindingSubject", fields: [memberId], references: [id], onDelete: Cascade)
826
+ deviceId String?
827
+ device Device? @relation(fields: [deviceId], references: [id], onDelete: Cascade)
828
+
829
+ // Metadata
830
+ templateId String?
831
+ template FindingTemplate? @relation(fields: [templateId], references: [id])
832
+ createdById String?
833
+ createdBy Member? @relation("FindingCreatedBy", fields: [createdById], references: [id])
834
+ createdByAdminId String?
835
+ createdByAdmin User? @relation("AdminFindingCreator", fields: [createdByAdminId], references: [id])
836
+ organizationId String
837
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
735
838
 
736
839
  @@index([taskId])
737
840
  @@index([evidenceSubmissionId])
738
841
  @@index([evidenceFormType])
842
+ @@index([policyId])
843
+ @@index([vendorId])
844
+ @@index([riskId])
845
+ @@index([memberId])
846
+ @@index([deviceId])
739
847
  @@index([organizationId, status])
848
+ @@index([organizationId, severity])
740
849
  }
741
850
 
742
-
743
851
  // ===== fleet-policy-result.prisma =====
744
852
  model FleetPolicyResult {
745
853
  id String @id @default(dbgenerated("generate_prefixed_cuid('fpr'::text)"))
@@ -759,7 +867,6 @@ model FleetPolicyResult {
759
867
  @@index([organizationId])
760
868
  }
761
869
 
762
-
763
870
  // ===== framework-editor.prisma =====
764
871
  // --- Data for Framework Editor ---
765
872
  model FrameworkEditorVideo {
@@ -785,6 +892,8 @@ model FrameworkEditorFramework {
785
892
  frameworkInstances FrameworkInstance[]
786
893
  soaConfigurations SOAFrameworkConfiguration[] // Multiple SOA config versions per framework
787
894
  soaDocuments SOADocument[] // SOA documents from organizations
895
+ timelineTemplates TimelineTemplate[]
896
+ versions FrameworkVersion[]
788
897
 
789
898
  // Dates
790
899
  createdAt DateTime @default(now())
@@ -830,8 +939,8 @@ model FrameworkEditorTaskTemplate {
830
939
  id String @id @default(dbgenerated("generate_prefixed_cuid('frk_tt'::text)"))
831
940
  name String
832
941
  description String
833
- frequency Frequency // Using the enum from shared.prisma
834
- department Departments // Using the enum from shared.prisma
942
+ frequency Frequency // Using the enum from shared.prisma
943
+ department Departments // Using the enum from shared.prisma
835
944
  automationStatus TaskAutomationStatus @default(AUTOMATED)
836
945
 
837
946
  controlTemplates FrameworkEditorControlTemplate[]
@@ -862,6 +971,67 @@ model FrameworkEditorControlTemplate {
862
971
  controls Control[]
863
972
  }
864
973
 
974
+ // ===== framework-sync-operation.prisma =====
975
+ enum FrameworkSyncOperationKind {
976
+ SYNC
977
+ ROLLBACK
978
+ }
979
+
980
+ model FrameworkSyncOperation {
981
+ id String @id @default(dbgenerated("generate_prefixed_cuid('fso'::text)"))
982
+ frameworkInstanceId String
983
+ frameworkInstance FrameworkInstance @relation(fields: [frameworkInstanceId], references: [id], onDelete: Cascade)
984
+
985
+ fromVersionId String
986
+ fromVersion FrameworkVersion @relation("FrameworkSyncOperationFromVersion", fields: [fromVersionId], references: [id])
987
+ toVersionId String
988
+ toVersion FrameworkVersion @relation("FrameworkSyncOperationToVersion", fields: [toVersionId], references: [id])
989
+
990
+ kind FrameworkSyncOperationKind
991
+
992
+ performedAt DateTime @default(now())
993
+ performedById String?
994
+ performedBy Member? @relation("FrameworkSyncOperationPerformer", fields: [performedById], references: [id], onDelete: SetNull)
995
+
996
+ // Only set when kind = SYNC
997
+ rollbackExpiresAt DateTime?
998
+
999
+ // Self-reference: when this sync was reversed, points at the rollback op.
1000
+ rolledBackByOperationId String? @unique
1001
+ rolledBackByOperation FrameworkSyncOperation? @relation("FrameworkSyncOperationRollback", fields: [rolledBackByOperationId], references: [id])
1002
+ rolledBackOperation FrameworkSyncOperation? @relation("FrameworkSyncOperationRollback")
1003
+
1004
+ undoPayload Json // structured per undo-payload.types.ts
1005
+ summary Json // counts for audit log / UI
1006
+
1007
+ @@index([frameworkInstanceId, performedAt])
1008
+ @@index([frameworkInstanceId, kind])
1009
+ }
1010
+
1011
+ // ===== framework-version.prisma =====
1012
+ model FrameworkVersion {
1013
+ id String @id @default(dbgenerated("generate_prefixed_cuid('fvr'::text)"))
1014
+ frameworkId String
1015
+ framework FrameworkEditorFramework @relation(fields: [frameworkId], references: [id], onDelete: Cascade)
1016
+
1017
+ version String // semver-ish, e.g., "1.0.0", "2.1.0"
1018
+ publishedAt DateTime @default(now())
1019
+ publishedById String?
1020
+ publishedBy User? @relation("FrameworkVersionPublisher", fields: [publishedById], references: [id], onDelete: SetNull)
1021
+
1022
+ releaseNotes String? // markdown
1023
+
1024
+ // Full snapshot of all templates at publish time (see manifest.types.ts).
1025
+ // Immutable once published.
1026
+ manifest Json
1027
+
1028
+ frameworkInstances FrameworkInstance[] @relation("FrameworkInstanceCurrentVersion")
1029
+ syncOperationsFrom FrameworkSyncOperation[] @relation("FrameworkSyncOperationFromVersion")
1030
+ syncOperationsTo FrameworkSyncOperation[] @relation("FrameworkSyncOperationToVersion")
1031
+
1032
+ @@unique([frameworkId, version])
1033
+ @@index([frameworkId, publishedAt])
1034
+ }
865
1035
 
866
1036
  // ===== framework.prisma =====
867
1037
  model FrameworkInstance {
@@ -869,454 +1039,470 @@ model FrameworkInstance {
869
1039
  id String @id @default(dbgenerated("generate_prefixed_cuid('frm'::text)"))
870
1040
  organizationId String
871
1041
 
872
- frameworkId String
873
- framework FrameworkEditorFramework @relation(fields: [frameworkId], references: [id], onDelete: Cascade)
1042
+ // Exactly one of frameworkId / customFrameworkId is set (enforced by DB CHECK constraint).
1043
+ frameworkId String?
1044
+ framework FrameworkEditorFramework? @relation(fields: [frameworkId], references: [id], onDelete: Cascade)
1045
+
1046
+ customFrameworkId String?
1047
+ // Composite FK onto (id, organizationId) so an FI can only reference a
1048
+ // CustomFramework in its own org. Enforced at the DB level.
1049
+ customFramework CustomFramework? @relation(fields: [customFrameworkId, organizationId], references: [id, organizationId], onDelete: Cascade)
1050
+
1051
+ currentVersionId String?
1052
+ currentVersion FrameworkVersion? @relation("FrameworkInstanceCurrentVersion", fields: [currentVersionId], references: [id], onDelete: Restrict)
874
1053
 
875
1054
  // Relationships
876
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1055
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
877
1056
  requirementsMapped RequirementMap[]
1057
+ timelineInstances TimelineInstance[]
1058
+ syncOperations FrameworkSyncOperation[]
878
1059
 
879
1060
  @@unique([organizationId, frameworkId])
1061
+ @@unique([organizationId, customFrameworkId])
1062
+ @@index([customFrameworkId])
1063
+ @@index([currentVersionId])
880
1064
  }
881
1065
 
882
-
883
1066
  // ===== integration-platform.prisma =====
884
1067
  // ===== Integration Platform =====
885
1068
  // New integration platform models for scalable, config-driven integrations
886
1069
 
887
1070
  /// Stores metadata about available integration providers (synced from code manifests)
888
1071
  model IntegrationProvider {
889
- id String @id @default(dbgenerated("generate_prefixed_cuid('prv'::text)"))
890
- /// Unique slug matching manifest ID (e.g., "github", "slack")
891
- slug String @unique
892
- /// Display name
893
- name String
894
- /// Category for grouping
895
- category String
896
- /// Hash of manifest for detecting changes
897
- manifestHash String?
898
- /// Capabilities JSON array
899
- capabilities Json @default("[]")
900
- /// Whether provider is active
901
- isActive Boolean @default(true)
1072
+ id String @id @default(dbgenerated("generate_prefixed_cuid('prv'::text)"))
1073
+ /// Unique slug matching manifest ID (e.g., "github", "slack")
1074
+ slug String @unique
1075
+ /// Display name
1076
+ name String
1077
+ /// Category for grouping
1078
+ category String
1079
+ /// Hash of manifest for detecting changes
1080
+ manifestHash String?
1081
+ /// Capabilities JSON array
1082
+ capabilities Json @default("[]")
1083
+ /// Whether provider is active
1084
+ isActive Boolean @default(true)
902
1085
 
903
- createdAt DateTime @default(now())
904
- updatedAt DateTime @updatedAt
1086
+ createdAt DateTime @default(now())
1087
+ updatedAt DateTime @updatedAt
905
1088
 
906
- connections IntegrationConnection[]
1089
+ connections IntegrationConnection[]
907
1090
 
908
- @@index([slug])
909
- @@index([category])
1091
+ @@index([slug])
1092
+ @@index([category])
910
1093
  }
911
1094
 
912
1095
  /// Represents an organization's connection to an integration provider
913
1096
  model IntegrationConnection {
914
- id String @id @default(dbgenerated("generate_prefixed_cuid('icn'::text)"))
1097
+ id String @id @default(dbgenerated("generate_prefixed_cuid('icn'::text)"))
915
1098
 
916
- /// Reference to the provider
917
- providerId String
918
- provider IntegrationProvider @relation(fields: [providerId], references: [id], onDelete: Cascade)
1099
+ /// Reference to the provider
1100
+ providerId String
1101
+ provider IntegrationProvider @relation(fields: [providerId], references: [id], onDelete: Cascade)
919
1102
 
920
- /// Organization that owns this connection
921
- organizationId String
922
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1103
+ /// Organization that owns this connection
1104
+ organizationId String
1105
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
923
1106
 
924
- /// Connection status
925
- status IntegrationConnectionStatus @default(pending)
1107
+ /// Connection status
1108
+ status IntegrationConnectionStatus @default(pending)
926
1109
 
927
- /// Auth strategy used (oauth2, api_key, basic, jwt, custom)
928
- authStrategy String
1110
+ /// Auth strategy used (oauth2, api_key, basic, jwt, custom)
1111
+ authStrategy String
929
1112
 
930
- /// Reference to active credential version
931
- activeCredentialVersionId String?
1113
+ /// Reference to active credential version
1114
+ activeCredentialVersionId String?
932
1115
 
933
- /// Last successful sync timestamp
934
- lastSyncAt DateTime?
1116
+ /// Last successful sync timestamp
1117
+ lastSyncAt DateTime?
935
1118
 
936
- /// Next scheduled sync timestamp
937
- nextSyncAt DateTime?
1119
+ /// Next scheduled sync timestamp
1120
+ nextSyncAt DateTime?
938
1121
 
939
- /// Custom sync cadence (cron expression), null = use default
940
- syncCadence String?
1122
+ /// Custom sync cadence (cron expression), null = use default
1123
+ syncCadence String?
941
1124
 
942
- /// Additional metadata (e.g., connected account info)
943
- metadata Json?
1125
+ /// Additional metadata (e.g., connected account info)
1126
+ metadata Json?
944
1127
 
945
- /// User-configured variables for checks (collected after OAuth)
946
- variables Json?
1128
+ /// User-configured variables for checks (collected after OAuth)
1129
+ variables Json?
947
1130
 
948
- /// Error message if status is error
949
- errorMessage String?
1131
+ /// Error message if status is error
1132
+ errorMessage String?
950
1133
 
951
- createdAt DateTime @default(now())
952
- updatedAt DateTime @updatedAt
1134
+ createdAt DateTime @default(now())
1135
+ updatedAt DateTime @updatedAt
953
1136
 
954
- credentialVersions IntegrationCredentialVersion[]
955
- runs IntegrationRun[]
956
- findings IntegrationPlatformFinding[]
957
- checkRuns IntegrationCheckRun[]
958
- syncLogs IntegrationSyncLog[]
1137
+ credentialVersions IntegrationCredentialVersion[]
1138
+ runs IntegrationRun[]
1139
+ findings IntegrationPlatformFinding[]
1140
+ checkRuns IntegrationCheckRun[]
1141
+ syncLogs IntegrationSyncLog[]
1142
+ remediationActions RemediationAction[]
1143
+ remediationBatches RemediationBatch[]
959
1144
 
960
- @@index([organizationId])
961
- @@index([providerId])
962
- @@index([providerId, organizationId])
963
- @@index([status])
1145
+ @@index([organizationId])
1146
+ @@index([providerId])
1147
+ @@index([providerId, organizationId])
1148
+ @@index([status])
964
1149
  }
965
1150
 
966
1151
  enum IntegrationConnectionStatus {
967
- pending // Awaiting credential setup
968
- active // Connected and operational
969
- error // Connection has errors
970
- paused // Manually paused by user
971
- disconnected // User disconnected
1152
+ pending // Awaiting credential setup
1153
+ active // Connected and operational
1154
+ error // Connection has errors
1155
+ paused // Manually paused by user
1156
+ disconnected // User disconnected
972
1157
  }
973
1158
 
974
1159
  /// Stores encrypted credentials with versioning for audit trail
975
1160
  model IntegrationCredentialVersion {
976
- id String @id @default(dbgenerated("generate_prefixed_cuid('icv'::text)"))
1161
+ id String @id @default(dbgenerated("generate_prefixed_cuid('icv'::text)"))
977
1162
 
978
- /// Parent connection
979
- connectionId String
980
- connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1163
+ /// Parent connection
1164
+ connectionId String
1165
+ connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
981
1166
 
982
- /// Encrypted credential payload (JSON with encrypted fields)
983
- encryptedPayload Json
1167
+ /// Encrypted credential payload (JSON with encrypted fields)
1168
+ encryptedPayload Json
984
1169
 
985
- /// Version number (auto-increment per connection)
986
- version Int
1170
+ /// Version number (auto-increment per connection)
1171
+ version Int
987
1172
 
988
- /// Token expiration (for OAuth tokens)
989
- expiresAt DateTime?
1173
+ /// Token expiration (for OAuth tokens)
1174
+ expiresAt DateTime?
990
1175
 
991
- /// When this version was rotated/replaced
992
- rotatedAt DateTime?
1176
+ /// When this version was rotated/replaced
1177
+ rotatedAt DateTime?
993
1178
 
994
- createdAt DateTime @default(now())
1179
+ createdAt DateTime @default(now())
995
1180
 
996
- @@unique([connectionId, version])
997
- @@index([connectionId])
1181
+ @@unique([connectionId, version])
1182
+ @@index([connectionId])
998
1183
  }
999
1184
 
1000
1185
  /// Records each sync/job execution for audit and debugging
1001
1186
  model IntegrationRun {
1002
- id String @id @default(dbgenerated("generate_prefixed_cuid('irn'::text)"))
1187
+ id String @id @default(dbgenerated("generate_prefixed_cuid('irn'::text)"))
1003
1188
 
1004
- /// Parent connection
1005
- connectionId String
1006
- connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1189
+ /// Parent connection
1190
+ connectionId String
1191
+ connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1007
1192
 
1008
- /// Type of job
1009
- jobType IntegrationRunJobType
1193
+ /// Type of job
1194
+ jobType IntegrationRunJobType
1010
1195
 
1011
- /// Execution status
1012
- status IntegrationRunStatus @default(pending)
1196
+ /// Execution status
1197
+ status IntegrationRunStatus @default(pending)
1013
1198
 
1014
- /// Timestamps
1015
- startedAt DateTime?
1016
- completedAt DateTime?
1199
+ /// Timestamps
1200
+ startedAt DateTime?
1201
+ completedAt DateTime?
1017
1202
 
1018
- /// Duration in milliseconds
1019
- durationMs Int?
1203
+ /// Duration in milliseconds
1204
+ durationMs Int?
1020
1205
 
1021
- /// Number of findings from this run
1022
- findingsCount Int @default(0)
1206
+ /// Number of findings from this run
1207
+ findingsCount Int @default(0)
1023
1208
 
1024
- /// Error details if failed
1025
- error Json?
1209
+ /// Error details if failed
1210
+ error Json?
1026
1211
 
1027
- /// Additional metadata (trigger source, cursor, etc.)
1028
- metadata Json?
1212
+ /// Additional metadata (trigger source, cursor, etc.)
1213
+ metadata Json?
1029
1214
 
1030
- createdAt DateTime @default(now())
1215
+ createdAt DateTime @default(now())
1031
1216
 
1032
- findings IntegrationPlatformFinding[]
1217
+ findings IntegrationPlatformFinding[]
1033
1218
 
1034
- @@index([connectionId])
1035
- @@index([status])
1036
- @@index([createdAt])
1219
+ @@index([connectionId])
1220
+ @@index([status])
1221
+ @@index([createdAt])
1037
1222
  }
1038
1223
 
1039
1224
  enum IntegrationRunJobType {
1040
- full_sync
1041
- delta_sync
1042
- webhook
1043
- manual
1044
- test_connection
1225
+ full_sync
1226
+ delta_sync
1227
+ webhook
1228
+ manual
1229
+ test_connection
1045
1230
  }
1046
1231
 
1047
1232
  enum IntegrationRunStatus {
1048
- pending
1049
- running
1050
- success
1051
- failed
1052
- cancelled
1233
+ pending
1234
+ running
1235
+ success
1236
+ failed
1237
+ cancelled
1053
1238
  }
1054
1239
 
1055
1240
  /// Stores findings/results from integration syncs
1056
1241
  model IntegrationPlatformFinding {
1057
- id String @id @default(dbgenerated("generate_prefixed_cuid('ipf'::text)"))
1242
+ id String @id @default(dbgenerated("generate_prefixed_cuid('ipf'::text)"))
1058
1243
 
1059
- /// Parent run (optional - webhooks may not have runs)
1060
- runId String?
1061
- run IntegrationRun? @relation(fields: [runId], references: [id], onDelete: SetNull)
1244
+ /// Parent run (optional - webhooks may not have runs)
1245
+ runId String?
1246
+ run IntegrationRun? @relation(fields: [runId], references: [id], onDelete: SetNull)
1062
1247
 
1063
- /// Parent connection
1064
- connectionId String
1065
- connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1248
+ /// Parent connection
1249
+ connectionId String
1250
+ connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1066
1251
 
1067
- /// Resource classification
1068
- resourceType String
1069
- resourceId String
1252
+ /// Resource classification
1253
+ resourceType String
1254
+ resourceId String
1070
1255
 
1071
- /// Finding details
1072
- title String
1073
- description String?
1256
+ /// Finding details
1257
+ title String
1258
+ description String?
1074
1259
 
1075
- /// Severity level
1076
- severity IntegrationFindingSeverity @default(info)
1260
+ /// Severity level
1261
+ severity IntegrationFindingSeverity @default(info)
1077
1262
 
1078
- /// Finding status
1079
- status IntegrationFindingStatus @default(open)
1263
+ /// Finding status
1264
+ status IntegrationFindingStatus @default(open)
1080
1265
 
1081
- /// Remediation guidance
1082
- remediation String?
1266
+ /// Remediation guidance
1267
+ remediation String?
1083
1268
 
1084
- /// Raw payload from provider
1085
- rawPayload Json?
1269
+ /// Raw payload from provider
1270
+ rawPayload Json?
1086
1271
 
1087
- createdAt DateTime @default(now())
1088
- updatedAt DateTime @updatedAt
1272
+ createdAt DateTime @default(now())
1273
+ updatedAt DateTime @updatedAt
1089
1274
 
1090
- @@index([connectionId])
1091
- @@index([runId])
1092
- @@index([resourceType, resourceId])
1093
- @@index([severity])
1094
- @@index([status])
1275
+ @@index([connectionId])
1276
+ @@index([runId])
1277
+ @@index([resourceType, resourceId])
1278
+ @@index([severity])
1279
+ @@index([status])
1095
1280
  }
1096
1281
 
1097
1282
  enum IntegrationFindingSeverity {
1098
- info
1099
- low
1100
- medium
1101
- high
1102
- critical
1283
+ info
1284
+ low
1285
+ medium
1286
+ high
1287
+ critical
1103
1288
  }
1104
1289
 
1105
1290
  enum IntegrationFindingStatus {
1106
- open
1107
- resolved
1108
- ignored
1291
+ open
1292
+ resolved
1293
+ ignored
1109
1294
  }
1110
1295
 
1111
1296
  /// Stores OAuth state for CSRF protection during OAuth flow
1112
1297
  model IntegrationOAuthState {
1113
- id String @id @default(dbgenerated("generate_prefixed_cuid('ios'::text)"))
1298
+ id String @id @default(dbgenerated("generate_prefixed_cuid('ios'::text)"))
1114
1299
 
1115
- /// Random state parameter
1116
- state String @unique
1300
+ /// Random state parameter
1301
+ state String @unique
1117
1302
 
1118
- /// Provider slug
1119
- providerSlug String
1303
+ /// Provider slug
1304
+ providerSlug String
1120
1305
 
1121
- /// Organization initiating the OAuth
1122
- organizationId String
1306
+ /// Organization initiating the OAuth
1307
+ organizationId String
1123
1308
 
1124
- /// User initiating the OAuth
1125
- userId String
1309
+ /// User initiating the OAuth
1310
+ userId String
1126
1311
 
1127
- /// PKCE code verifier (if using PKCE)
1128
- codeVerifier String?
1312
+ /// PKCE code verifier (if using PKCE)
1313
+ codeVerifier String?
1129
1314
 
1130
- /// Redirect URL after OAuth completes
1131
- redirectUrl String?
1315
+ /// Redirect URL after OAuth completes
1316
+ redirectUrl String?
1132
1317
 
1133
- /// Expiration timestamp
1134
- expiresAt DateTime
1318
+ /// Expiration timestamp
1319
+ expiresAt DateTime
1135
1320
 
1136
- createdAt DateTime @default(now())
1321
+ createdAt DateTime @default(now())
1137
1322
 
1138
- @@index([state])
1139
- @@index([expiresAt])
1323
+ @@index([state])
1324
+ @@index([expiresAt])
1140
1325
  }
1141
1326
 
1142
1327
  /// Stores organization-level OAuth app credentials
1143
1328
  /// Allows orgs (especially self-hosters) to use their own OAuth apps
1144
1329
  model IntegrationOAuthApp {
1145
- id String @id @default(dbgenerated("generate_prefixed_cuid('ioa'::text)"))
1330
+ id String @id @default(dbgenerated("generate_prefixed_cuid('ioa'::text)"))
1146
1331
 
1147
- /// Provider slug (e.g., "github", "slack")
1148
- providerSlug String
1332
+ /// Provider slug (e.g., "github", "slack")
1333
+ providerSlug String
1149
1334
 
1150
- /// Organization that owns this OAuth app config
1151
- organizationId String
1152
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1335
+ /// Organization that owns this OAuth app config
1336
+ organizationId String
1337
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1153
1338
 
1154
- /// Encrypted client ID
1155
- encryptedClientId Json
1339
+ /// Encrypted client ID
1340
+ encryptedClientId Json
1156
1341
 
1157
- /// Encrypted client secret
1158
- encryptedClientSecret Json
1342
+ /// Encrypted client secret
1343
+ encryptedClientSecret Json
1159
1344
 
1160
- /// Optional: custom scopes (overrides manifest defaults)
1161
- customScopes String[]
1345
+ /// Optional: custom scopes (overrides manifest defaults)
1346
+ customScopes String[]
1162
1347
 
1163
- /// Provider-specific settings (e.g., Rippling app name for authorize URL)
1164
- /// Stored as JSON: { "appName": "compai533c" }
1165
- customSettings Json?
1348
+ /// Provider-specific settings (e.g., Rippling app name for authorize URL)
1349
+ /// Stored as JSON: { "appName": "compai533c" }
1350
+ customSettings Json?
1166
1351
 
1167
- /// Whether this config is active
1168
- isActive Boolean @default(true)
1352
+ /// Whether this config is active
1353
+ isActive Boolean @default(true)
1169
1354
 
1170
- createdAt DateTime @default(now())
1171
- updatedAt DateTime @updatedAt
1355
+ createdAt DateTime @default(now())
1356
+ updatedAt DateTime @updatedAt
1172
1357
 
1173
- @@unique([providerSlug, organizationId])
1174
- @@index([organizationId])
1175
- @@index([providerSlug])
1358
+ @@unique([providerSlug, organizationId])
1359
+ @@index([organizationId])
1360
+ @@index([providerSlug])
1176
1361
  }
1177
1362
 
1178
1363
  /// Records check runs linked to tasks for compliance verification
1179
1364
  model IntegrationCheckRun {
1180
- id String @id @default(dbgenerated("generate_prefixed_cuid('icr'::text)"))
1365
+ id String @id @default(dbgenerated("generate_prefixed_cuid('icr'::text)"))
1181
1366
 
1182
- /// Parent connection
1183
- connectionId String
1184
- connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1367
+ /// Parent connection
1368
+ connectionId String
1369
+ connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1185
1370
 
1186
- /// Task being verified (optional - checks can run without a task)
1187
- taskId String?
1188
- task Task? @relation(fields: [taskId], references: [id], onDelete: SetNull)
1371
+ /// Task being verified (optional - checks can run without a task)
1372
+ taskId String?
1373
+ task Task? @relation(fields: [taskId], references: [id], onDelete: SetNull)
1189
1374
 
1190
- /// Check ID from the manifest
1191
- checkId String
1375
+ /// Check ID from the manifest
1376
+ checkId String
1192
1377
 
1193
- /// Check name (denormalized for display)
1194
- checkName String
1378
+ /// Check name (denormalized for display)
1379
+ checkName String
1195
1380
 
1196
- /// Execution status
1197
- status IntegrationRunStatus @default(pending)
1381
+ /// Execution status
1382
+ status IntegrationRunStatus @default(pending)
1198
1383
 
1199
- /// Timestamps
1200
- startedAt DateTime?
1201
- completedAt DateTime?
1384
+ /// Timestamps
1385
+ startedAt DateTime?
1386
+ completedAt DateTime?
1202
1387
 
1203
- /// Duration in milliseconds
1204
- durationMs Int?
1388
+ /// Duration in milliseconds
1389
+ durationMs Int?
1205
1390
 
1206
- /// Summary counts
1207
- totalChecked Int @default(0)
1208
- passedCount Int @default(0)
1209
- failedCount Int @default(0)
1391
+ /// Summary counts
1392
+ totalChecked Int @default(0)
1393
+ passedCount Int @default(0)
1394
+ failedCount Int @default(0)
1210
1395
 
1211
- /// Error message if failed
1212
- errorMessage String?
1396
+ /// Error message if failed
1397
+ errorMessage String?
1213
1398
 
1214
- /// Full execution logs (JSON array)
1215
- logs Json?
1399
+ /// Full execution logs (JSON array)
1400
+ logs Json?
1216
1401
 
1217
- createdAt DateTime @default(now())
1402
+ createdAt DateTime @default(now())
1218
1403
 
1219
- /// Results from this check run
1220
- results IntegrationCheckResult[]
1404
+ /// Results from this check run
1405
+ results IntegrationCheckResult[]
1221
1406
 
1222
- @@index([connectionId])
1223
- @@index([taskId])
1224
- @@index([checkId])
1225
- @@index([status])
1226
- @@index([createdAt])
1407
+ @@index([connectionId])
1408
+ @@index([taskId])
1409
+ @@index([checkId])
1410
+ @@index([status])
1411
+ @@index([createdAt])
1227
1412
  }
1228
1413
 
1229
1414
  /// Stores individual results (pass/fail) from check runs
1230
1415
  model IntegrationCheckResult {
1231
- id String @id @default(dbgenerated("generate_prefixed_cuid('icx'::text)"))
1416
+ id String @id @default(dbgenerated("generate_prefixed_cuid('icx'::text)"))
1417
+
1418
+ /// Parent check run
1419
+ checkRunId String
1420
+ checkRun IntegrationCheckRun @relation(fields: [checkRunId], references: [id], onDelete: Cascade)
1232
1421
 
1233
- /// Parent check run
1234
- checkRunId String
1235
- checkRun IntegrationCheckRun @relation(fields: [checkRunId], references: [id], onDelete: Cascade)
1422
+ /// Whether this result is a pass or fail
1423
+ passed Boolean
1236
1424
 
1237
- /// Whether this result is a pass or fail
1238
- passed Boolean
1425
+ /// Resource classification
1426
+ resourceType String
1427
+ resourceId String
1239
1428
 
1240
- /// Resource classification
1241
- resourceType String
1242
- resourceId String
1429
+ /// Result details
1430
+ title String
1431
+ description String?
1243
1432
 
1244
- /// Result details
1245
- title String
1246
- description String?
1433
+ /// Severity (for failures)
1434
+ severity IntegrationFindingSeverity?
1247
1435
 
1248
- /// Severity (for failures)
1249
- severity IntegrationFindingSeverity?
1436
+ /// Remediation guidance (for failures)
1437
+ remediation String?
1250
1438
 
1251
- /// Remediation guidance (for failures)
1252
- remediation String?
1439
+ /// Evidence/proof (JSON - API response data)
1440
+ evidence Json?
1253
1441
 
1254
- /// Evidence/proof (JSON - API response data)
1255
- evidence Json?
1442
+ /// When this evidence was collected
1443
+ collectedAt DateTime @default(now())
1256
1444
 
1257
- /// When this evidence was collected
1258
- collectedAt DateTime @default(now())
1445
+ remediationActions RemediationAction[]
1259
1446
 
1260
- @@index([checkRunId])
1261
- @@index([passed])
1262
- @@index([resourceType, resourceId])
1447
+ @@index([checkRunId])
1448
+ @@index([passed])
1449
+ @@index([resourceType, resourceId])
1263
1450
  }
1264
1451
 
1265
1452
  /// Stores platform-wide OAuth app credentials
1266
1453
  /// Used by platform operators to provide default OAuth apps for all users
1267
1454
  model IntegrationPlatformCredential {
1268
- id String @id @default(dbgenerated("generate_prefixed_cuid('ipc'::text)"))
1455
+ id String @id @default(dbgenerated("generate_prefixed_cuid('ipc'::text)"))
1269
1456
 
1270
- /// Provider slug (e.g., "github", "slack") - unique per platform
1271
- providerSlug String @unique
1457
+ /// Provider slug (e.g., "github", "slack") - unique per platform
1458
+ providerSlug String @unique
1272
1459
 
1273
- /// Encrypted client ID
1274
- encryptedClientId Json
1460
+ /// Encrypted client ID
1461
+ encryptedClientId Json
1275
1462
 
1276
- /// Encrypted client secret
1277
- encryptedClientSecret Json
1463
+ /// Encrypted client secret
1464
+ encryptedClientSecret Json
1278
1465
 
1279
- /// Masked display hint for client ID (computed at write time)
1280
- clientIdHint String?
1466
+ /// Masked display hint for client ID (computed at write time)
1467
+ clientIdHint String?
1281
1468
 
1282
- /// Masked display hint for client secret (computed at write time)
1283
- clientSecretHint String?
1469
+ /// Masked display hint for client secret (computed at write time)
1470
+ clientSecretHint String?
1284
1471
 
1285
- /// Optional: custom scopes (overrides manifest defaults)
1286
- customScopes String[]
1472
+ /// Optional: custom scopes (overrides manifest defaults)
1473
+ customScopes String[]
1287
1474
 
1288
- /// Provider-specific settings (e.g., Rippling app name for authorize URL)
1289
- /// Stored as JSON: { "appName": "compai533c" }
1290
- customSettings Json?
1475
+ /// Provider-specific settings (e.g., Rippling app name for authorize URL)
1476
+ /// Stored as JSON: { "appName": "compai533c" }
1477
+ customSettings Json?
1291
1478
 
1292
- /// Whether this credential is active
1293
- isActive Boolean @default(true)
1479
+ /// Whether this credential is active
1480
+ isActive Boolean @default(true)
1294
1481
 
1295
- /// Who created this credential
1296
- createdById String?
1482
+ /// Who created this credential
1483
+ createdById String?
1297
1484
 
1298
- /// Who last updated this credential
1299
- updatedById String?
1485
+ /// Who last updated this credential
1486
+ updatedById String?
1300
1487
 
1301
- createdAt DateTime @default(now())
1302
- updatedAt DateTime @updatedAt
1488
+ createdAt DateTime @default(now())
1489
+ updatedAt DateTime @updatedAt
1303
1490
 
1304
- @@index([providerSlug])
1491
+ @@index([providerSlug])
1305
1492
  }
1306
1493
 
1307
-
1308
1494
  // ===== integration-sync-log.prisma =====
1309
1495
  // ===== Integration Sync Log =====
1310
1496
  // Generic audit trail for integration sync operations (employee sync, role discovery, etc.)
1311
1497
 
1312
1498
  model IntegrationSyncLog {
1313
- id String @id @default(dbgenerated("generate_prefixed_cuid('isl'::text)"))
1499
+ id String @id @default(dbgenerated("generate_prefixed_cuid('isl'::text)"))
1314
1500
  connectionId String
1315
- connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1501
+ connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1316
1502
  organizationId String
1317
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1503
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1318
1504
 
1319
- /// Provider slug (e.g., "ramp", "google-workspace", "rippling", "jumpcloud")
1505
+ /// Provider slug (e.g., "google-workspace", "rippling", "jumpcloud")
1320
1506
  provider String
1321
1507
  /// Event type (e.g., "employee_sync", "role_discovery", "role_mapping_save")
1322
1508
  eventType String
@@ -1352,7 +1538,6 @@ enum IntegrationSyncLogStatus {
1352
1538
  failed
1353
1539
  }
1354
1540
 
1355
-
1356
1541
  // ===== integration.prisma =====
1357
1542
  model Integration {
1358
1543
  id String @id @default(dbgenerated("generate_prefixed_cuid('int'::text)"))
@@ -1387,7 +1572,6 @@ model IntegrationResult {
1387
1572
  @@index([integrationId])
1388
1573
  }
1389
1574
 
1390
-
1391
1575
  // ===== knowledge-base-document.prisma =====
1392
1576
  model KnowledgeBaseDocument {
1393
1577
  id String @id @default(dbgenerated("generate_prefixed_cuid('kbd'::text)"))
@@ -1421,13 +1605,12 @@ enum KnowledgeBaseDocumentProcessingStatus {
1421
1605
  failed // Processing failed
1422
1606
  }
1423
1607
 
1424
-
1425
1608
  // ===== notification-policy.prisma =====
1426
1609
  model RoleNotificationSetting {
1427
- id String @id @default(dbgenerated("generate_prefixed_cuid('rns'::text)"))
1428
- organizationId String
1429
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1430
- role String // "owner", "admin", "auditor", "employee", "contractor", or custom role name
1610
+ id String @id @default(dbgenerated("generate_prefixed_cuid('rns'::text)"))
1611
+ organizationId String
1612
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1613
+ role String // "owner", "admin", "auditor", "employee", "contractor", or custom role name
1431
1614
 
1432
1615
  policyNotifications Boolean @default(true)
1433
1616
  taskReminders Boolean @default(true)
@@ -1443,7 +1626,6 @@ model RoleNotificationSetting {
1443
1626
  @@map("role_notification_setting")
1444
1627
  }
1445
1628
 
1446
-
1447
1629
  // ===== onboarding.prisma =====
1448
1630
  model Onboarding {
1449
1631
  organizationId String @id
@@ -1464,7 +1646,6 @@ model Onboarding {
1464
1646
  @@index([organizationId])
1465
1647
  }
1466
1648
 
1467
-
1468
1649
  // ===== org-chart.prisma =====
1469
1650
  model OrganizationChart {
1470
1651
  id String @id @default(dbgenerated("generate_prefixed_cuid('och'::text)"))
@@ -1481,7 +1662,6 @@ model OrganizationChart {
1481
1662
  @@index([organizationId])
1482
1663
  }
1483
1664
 
1484
-
1485
1665
  // ===== organization-billing.prisma =====
1486
1666
  model OrganizationBilling {
1487
1667
  id String @id @default(dbgenerated("generate_prefixed_cuid('obil'::text)"))
@@ -1490,31 +1670,30 @@ model OrganizationBilling {
1490
1670
  createdAt DateTime @default(now()) @map("created_at")
1491
1671
  updatedAt DateTime @updatedAt @map("updated_at")
1492
1672
 
1493
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1673
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1494
1674
  pentestSubscription PentestSubscription?
1495
1675
 
1496
1676
  @@map("organization_billing")
1497
1677
  }
1498
1678
 
1499
-
1500
1679
  // ===== organization.prisma =====
1501
1680
  model Organization {
1502
- id String @id @default(dbgenerated("generate_prefixed_cuid('org'::text)"))
1503
- name String
1504
- slug String @unique @default(dbgenerated("generate_prefixed_cuid('slug'::text)"))
1505
- logo String?
1506
- createdAt DateTime @default(now())
1507
- metadata String?
1508
- onboarding Onboarding?
1509
- website String?
1510
- onboardingCompleted Boolean @default(false)
1511
- hasAccess Boolean @default(false)
1512
- advancedModeEnabled Boolean @default(false)
1513
- evidenceApprovalEnabled Boolean @default(false)
1514
- deviceAgentStepEnabled Boolean @default(true)
1515
- securityTrainingStepEnabled Boolean @default(true)
1516
- whistleblowerReportEnabled Boolean @default(true)
1517
- accessRequestFormEnabled Boolean @default(true)
1681
+ id String @id @default(dbgenerated("generate_prefixed_cuid('org'::text)"))
1682
+ name String
1683
+ slug String @unique @default(dbgenerated("generate_prefixed_cuid('slug'::text)"))
1684
+ logo String?
1685
+ createdAt DateTime @default(now())
1686
+ metadata String?
1687
+ onboarding Onboarding?
1688
+ website String?
1689
+ onboardingCompleted Boolean @default(false)
1690
+ hasAccess Boolean @default(false)
1691
+ advancedModeEnabled Boolean @default(false)
1692
+ evidenceApprovalEnabled Boolean @default(false)
1693
+ deviceAgentStepEnabled Boolean @default(true)
1694
+ securityTrainingStepEnabled Boolean @default(true)
1695
+ whistleblowerReportEnabled Boolean @default(true)
1696
+ accessRequestFormEnabled Boolean @default(true)
1518
1697
 
1519
1698
  // FleetDM
1520
1699
  fleetDmLabelId Int?
@@ -1578,13 +1757,19 @@ model Organization {
1578
1757
  organizationChart OrganizationChart?
1579
1758
 
1580
1759
  // RBAC
1581
- organizationRoles OrganizationRole[]
1582
- roleNotificationSettings RoleNotificationSetting[]
1760
+ organizationRoles OrganizationRole[]
1761
+ roleNotificationSettings RoleNotificationSetting[]
1762
+
1763
+ // Timeline
1764
+ timelineInstances TimelineInstance[]
1765
+
1766
+ // Custom frameworks / requirements authored by this org
1767
+ customFrameworks CustomFramework[]
1768
+ customRequirements CustomRequirement[]
1583
1769
 
1584
1770
  @@index([slug])
1585
1771
  }
1586
1772
 
1587
-
1588
1773
  // ===== pentest-subscription.prisma =====
1589
1774
  model PentestSubscription {
1590
1775
  id String @id @default(dbgenerated("generate_prefixed_cuid('psub'::text)"))
@@ -1607,7 +1792,6 @@ model PentestSubscription {
1607
1792
  @@map("pentest_subscriptions")
1608
1793
  }
1609
1794
 
1610
-
1611
1795
  // ===== policy.prisma =====
1612
1796
  enum PolicyDisplayFormat {
1613
1797
  EDITOR
@@ -1615,7 +1799,7 @@ enum PolicyDisplayFormat {
1615
1799
  }
1616
1800
 
1617
1801
  enum PolicyVisibility {
1618
- ALL // Visible to everyone in organization
1802
+ ALL // Visible to everyone in organization
1619
1803
  DEPARTMENT // Only visible to specified departments
1620
1804
  }
1621
1805
 
@@ -1645,6 +1829,12 @@ model Policy {
1645
1829
  lastArchivedAt DateTime?
1646
1830
  lastPublishedAt DateTime?
1647
1831
 
1832
+ // Sync-driven archive. Distinct from `isArchived` (which is user-initiated
1833
+ // archiving of a published policy). UI should hide a policy if EITHER is
1834
+ // set: `WHERE isArchived = false AND archivedAt IS NULL`. Rollback restores
1835
+ // only `archivedAt`, never touches `isArchived`.
1836
+ archivedAt DateTime?
1837
+
1648
1838
  // Relationships
1649
1839
  organizationId String
1650
1840
  organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
@@ -1659,8 +1849,10 @@ model Policy {
1659
1849
  currentVersion PolicyVersion? @relation("PolicyCurrentVersion", fields: [currentVersionId], references: [id])
1660
1850
  pendingVersionId String?
1661
1851
  versions PolicyVersion[] @relation("PolicyVersions")
1852
+ findings Finding[]
1662
1853
 
1663
1854
  @@index([organizationId])
1855
+ @@index([organizationId, archivedAt])
1664
1856
  }
1665
1857
 
1666
1858
  model PolicyVersion {
@@ -1669,8 +1861,8 @@ model PolicyVersion {
1669
1861
  updatedAt DateTime @updatedAt
1670
1862
 
1671
1863
  // Relations
1672
- policyId String
1673
- policy Policy @relation("PolicyVersions", fields: [policyId], references: [id], onDelete: Cascade)
1864
+ policyId String
1865
+ policy Policy @relation("PolicyVersions", fields: [policyId], references: [id], onDelete: Cascade)
1674
1866
  currentForPolicy Policy? @relation("PolicyCurrentVersion")
1675
1867
 
1676
1868
  // Version details
@@ -1686,7 +1878,6 @@ model PolicyVersion {
1686
1878
  @@index([createdAt])
1687
1879
  }
1688
1880
 
1689
-
1690
1881
  // ===== questionnaire.prisma =====
1691
1882
  model Questionnaire {
1692
1883
  id String @id @default(dbgenerated("generate_prefixed_cuid('qst'::text)"))
@@ -1751,13 +1942,68 @@ enum QuestionnaireAnswerStatus {
1751
1942
  manual // Manually written/edited by user
1752
1943
  }
1753
1944
 
1945
+ // ===== remediation-action.prisma =====
1946
+ model RemediationAction {
1947
+ id String @id @default(dbgenerated("generate_prefixed_cuid('rma'::text)"))
1948
+ checkResultId String
1949
+ connectionId String
1950
+ organizationId String
1951
+ initiatedById String
1952
+ remediationKey String
1953
+ resourceId String
1954
+ resourceType String
1955
+ previousState Json
1956
+ appliedState Json
1957
+ status String @default("pending")
1958
+ riskLevel String?
1959
+ acknowledgmentText String?
1960
+ acknowledgedAt DateTime?
1961
+ errorMessage String?
1962
+ executedAt DateTime?
1963
+ rolledBackAt DateTime?
1964
+ createdAt DateTime @default(now())
1965
+ updatedAt DateTime @updatedAt
1966
+
1967
+ checkResult IntegrationCheckResult @relation(fields: [checkResultId], references: [id], onDelete: Cascade)
1968
+ connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1969
+
1970
+ @@index([connectionId])
1971
+ @@index([organizationId])
1972
+ @@index([checkResultId])
1973
+ }
1974
+
1975
+ // ===== remediation-batch.prisma =====
1976
+ model RemediationBatch {
1977
+ id String @id @default(dbgenerated("generate_prefixed_cuid('rmb'::text)"))
1978
+ connectionId String
1979
+ organizationId String
1980
+ initiatedById String
1981
+ triggerRunId String?
1982
+ status String @default("pending") // pending, running, done, cancelled
1983
+ findings Json @default("[]") // Array of { id, key, title, status, error? }
1984
+ fixed Int @default(0)
1985
+ skipped Int @default(0)
1986
+ failed Int @default(0)
1987
+ createdAt DateTime @default(now())
1988
+ updatedAt DateTime @updatedAt
1989
+
1990
+ connection IntegrationConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
1991
+
1992
+ @@index([connectionId])
1993
+ @@index([organizationId])
1994
+ @@index([status])
1995
+ }
1754
1996
 
1755
1997
  // ===== requirement.prisma =====
1756
1998
  model RequirementMap {
1757
1999
  id String @id @default(dbgenerated("generate_prefixed_cuid('req'::text)"))
1758
2000
 
1759
- requirementId String
1760
- requirement FrameworkEditorRequirement @relation(fields: [requirementId], references: [id], onDelete: Cascade)
2001
+ // Exactly one of requirementId / customRequirementId is set (enforced by DB CHECK constraint).
2002
+ requirementId String?
2003
+ requirement FrameworkEditorRequirement? @relation(fields: [requirementId], references: [id], onDelete: Cascade)
2004
+
2005
+ customRequirementId String?
2006
+ customRequirement CustomRequirement? @relation(fields: [customRequirementId], references: [id], onDelete: Cascade)
1761
2007
 
1762
2008
  controlId String
1763
2009
  control Control @relation(fields: [controlId], references: [id], onDelete: Cascade)
@@ -1765,11 +2011,17 @@ model RequirementMap {
1765
2011
  frameworkInstanceId String
1766
2012
  frameworkInstance FrameworkInstance @relation(fields: [frameworkInstanceId], references: [id], onDelete: Cascade)
1767
2013
 
2014
+ // Sync-driven archive — edges are framework-scoped, so these always archive
2015
+ // cleanly when the mapping disappears from the framework's latest version.
2016
+ archivedAt DateTime?
2017
+
1768
2018
  @@unique([controlId, frameworkInstanceId, requirementId])
2019
+ @@unique([controlId, frameworkInstanceId, customRequirementId])
1769
2020
  @@index([requirementId, frameworkInstanceId])
2021
+ @@index([customRequirementId, frameworkInstanceId])
2022
+ @@index([frameworkInstanceId, archivedAt])
1770
2023
  }
1771
2024
 
1772
-
1773
2025
  // ===== risk.prisma =====
1774
2026
  model Risk {
1775
2027
  // Metadata
@@ -1796,6 +2048,7 @@ model Risk {
1796
2048
  assigneeId String?
1797
2049
  assignee Member? @relation(fields: [assigneeId], references: [id])
1798
2050
  tasks Task[]
2051
+ findings Finding[]
1799
2052
 
1800
2053
  @@index([organizationId])
1801
2054
  @@index([category])
@@ -1830,7 +2083,6 @@ enum RiskStatus {
1830
2083
  archived
1831
2084
  }
1832
2085
 
1833
-
1834
2086
  // ===== secret.prisma =====
1835
2087
  model Secret {
1836
2088
  id String @id @default(dbgenerated("generate_prefixed_cuid('sec'::text)"))
@@ -1849,14 +2101,13 @@ model Secret {
1849
2101
  @@map("secrets")
1850
2102
  }
1851
2103
 
1852
-
1853
2104
  // ===== security-penetration-test-run.prisma =====
1854
2105
  model SecurityPenetrationTestRun {
1855
- id String @id @default(dbgenerated("generate_prefixed_cuid('ptr'::text)"))
1856
- organizationId String @map("organization_id")
1857
- providerRunId String @map("provider_run_id")
1858
- createdAt DateTime @default(now()) @map("created_at")
1859
- updatedAt DateTime @updatedAt @map("updated_at")
2106
+ id String @id @default(dbgenerated("generate_prefixed_cuid('ptr'::text)"))
2107
+ organizationId String @map("organization_id")
2108
+ providerRunId String @map("provider_run_id")
2109
+ createdAt DateTime @default(now()) @map("created_at")
2110
+ updatedAt DateTime @updatedAt @map("updated_at")
1860
2111
 
1861
2112
  organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1862
2113
 
@@ -1865,7 +2116,6 @@ model SecurityPenetrationTestRun {
1865
2116
  @@map("security_penetration_test_runs")
1866
2117
  }
1867
2118
 
1868
-
1869
2119
  // ===== security-questionnaire-manual-answer.prisma =====
1870
2120
  model SecurityQuestionnaireManualAnswer {
1871
2121
  id String @id @default(dbgenerated("generate_prefixed_cuid('sqma'::text)"))
@@ -1896,7 +2146,6 @@ model SecurityQuestionnaireManualAnswer {
1896
2146
  @@index([createdAt])
1897
2147
  }
1898
2148
 
1899
-
1900
2149
  // ===== shared.prisma =====
1901
2150
  model ApiKey {
1902
2151
  id String @id @default(dbgenerated("generate_prefixed_cuid('apk'::text)"))
@@ -2028,7 +2277,6 @@ enum Impact {
2028
2277
  severe
2029
2278
  }
2030
2279
 
2031
-
2032
2280
  // ===== soa.prisma =====
2033
2281
  // Statement of Applicability (SOA) Auto-complete Configuration and Answers
2034
2282
 
@@ -2092,9 +2340,9 @@ model SOADocument {
2092
2340
  answeredQuestions Int @default(0) // Number of questions with answers
2093
2341
 
2094
2342
  // Approval tracking
2095
- preparedBy String @default("Comp AI") // Always "Comp AI"
2343
+ preparedBy String @default("Comp AI") // Always "Comp AI"
2096
2344
  approverId String? // Member ID who will approve this document (set when submitted for approval)
2097
- approver Member? @relation("SOADocumentApprover", fields: [approverId], references: [id], onDelete: SetNull, onUpdate: Cascade)
2345
+ approver Member? @relation("SOADocumentApprover", fields: [approverId], references: [id], onDelete: SetNull, onUpdate: Cascade)
2098
2346
  approvedAt DateTime? // When document was approved
2099
2347
 
2100
2348
  // Dates
@@ -2165,37 +2413,36 @@ enum SOAAnswerStatus {
2165
2413
  manual // Manually written/edited by user
2166
2414
  }
2167
2415
 
2168
-
2169
2416
  // ===== task-item.prisma =====
2170
2417
  model TaskItem {
2171
- id String @id @default(dbgenerated("generate_prefixed_cuid('tski'::text)"))
2418
+ id String @id @default(dbgenerated("generate_prefixed_cuid('tski'::text)"))
2172
2419
  title String
2173
2420
  description String?
2174
- status TaskItemStatus @default(todo)
2175
- priority TaskItemPriority @default(medium)
2176
-
2421
+ status TaskItemStatus @default(todo)
2422
+ priority TaskItemPriority @default(medium)
2423
+
2177
2424
  // Polymorphic relation (like Comment and Attachment)
2178
2425
  entityId String
2179
2426
  entityType TaskItemEntityType
2180
-
2427
+
2181
2428
  // Assignment (nullable)
2182
- assigneeId String?
2183
- assignee Member? @relation("TaskItemAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
2184
-
2429
+ assigneeId String?
2430
+ assignee Member? @relation("TaskItemAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
2431
+
2185
2432
  // Creator & Updater
2186
2433
  createdById String
2187
- createdBy Member @relation("TaskItemCreator", fields: [createdById], references: [id])
2434
+ createdBy Member @relation("TaskItemCreator", fields: [createdById], references: [id])
2188
2435
  updatedById String?
2189
- updatedBy Member? @relation("TaskItemUpdater", fields: [updatedById], references: [id])
2190
-
2436
+ updatedBy Member? @relation("TaskItemUpdater", fields: [updatedById], references: [id])
2437
+
2191
2438
  // Relationships
2192
2439
  organizationId String
2193
2440
  organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
2194
-
2441
+
2195
2442
  // Dates
2196
2443
  createdAt DateTime @default(now())
2197
2444
  updatedAt DateTime @updatedAt
2198
-
2445
+
2199
2446
  @@index([entityId, entityType])
2200
2447
  @@index([organizationId])
2201
2448
  @@index([assigneeId])
@@ -2223,18 +2470,19 @@ enum TaskItemEntityType {
2223
2470
  risk
2224
2471
  }
2225
2472
 
2226
-
2227
2473
  // ===== task.prisma =====
2228
2474
  model Task {
2229
2475
  // Metadata
2230
- id String @id @default(dbgenerated("generate_prefixed_cuid('tsk'::text)"))
2231
- title String
2232
- description String
2233
- status TaskStatus @default(todo)
2234
- automationStatus TaskAutomationStatus @default(AUTOMATED)
2235
- frequency TaskFrequency?
2236
- department Departments? @default(none)
2237
- order Int @default(0)
2476
+ id String @id @default(dbgenerated("generate_prefixed_cuid('tsk'::text)"))
2477
+ title String
2478
+ description String
2479
+ status TaskStatus @default(todo)
2480
+ automationStatus TaskAutomationStatus @default(AUTOMATED)
2481
+ frequency TaskFrequency?
2482
+ integrationScheduleFrequency TaskFrequency @default(daily)
2483
+ integrationLastRunAt DateTime?
2484
+ department Departments? @default(none)
2485
+ order Int @default(0)
2238
2486
 
2239
2487
  // Dates
2240
2488
  createdAt DateTime @default(now())
@@ -2256,14 +2504,19 @@ model Task {
2256
2504
  browserAutomations BrowserAutomation[]
2257
2505
 
2258
2506
  evidenceAutomationRuns EvidenceAutomationRun[]
2259
- integrationCheckRuns IntegrationCheckRun[]
2260
- findings Finding[]
2507
+ integrationCheckRuns IntegrationCheckRun[]
2508
+ findings Finding[]
2261
2509
 
2262
2510
  // Evidence approval
2263
2511
  approverId String?
2264
2512
  approver Member? @relation("TaskApprover", fields: [approverId], references: [id])
2265
2513
  approvedAt DateTime?
2266
2514
  previousStatus TaskStatus?
2515
+
2516
+ // Sync-driven archive — see Control.archivedAt.
2517
+ archivedAt DateTime?
2518
+
2519
+ @@index([organizationId, archivedAt])
2267
2520
  }
2268
2521
 
2269
2522
  enum TaskStatus {
@@ -2288,6 +2541,128 @@ enum TaskAutomationStatus {
2288
2541
  MANUAL
2289
2542
  }
2290
2543
 
2544
+ // ===== timeline.prisma =====
2545
+ enum TimelineStatus {
2546
+ DRAFT
2547
+ ACTIVE
2548
+ PAUSED
2549
+ COMPLETED
2550
+ }
2551
+
2552
+ enum TimelinePhaseStatus {
2553
+ PENDING
2554
+ IN_PROGRESS
2555
+ COMPLETED
2556
+ }
2557
+
2558
+ enum PhaseCompletionType {
2559
+ AUTO_TASKS
2560
+ AUTO_POLICIES
2561
+ AUTO_PEOPLE
2562
+ AUTO_FINDINGS
2563
+ AUTO_UPLOAD
2564
+ MANUAL
2565
+ }
2566
+
2567
+ model TimelineTemplate {
2568
+ id String @id @default(dbgenerated("generate_prefixed_cuid('tml'::text)"))
2569
+ frameworkId String
2570
+ name String
2571
+ trackKey String @default("primary")
2572
+ cycleNumber Int
2573
+ templateKey String?
2574
+ nextTemplateKey String?
2575
+ createdAt DateTime @default(now())
2576
+ updatedAt DateTime @updatedAt
2577
+
2578
+ framework FrameworkEditorFramework @relation(fields: [frameworkId], references: [id])
2579
+ phases TimelinePhaseTemplate[]
2580
+ instances TimelineInstance[]
2581
+
2582
+ @@unique([frameworkId, trackKey, cycleNumber])
2583
+ // Note: Postgres treats NULLs as distinct in unique indexes, so this
2584
+ // constraint only enforces uniqueness among rows where templateKey is set.
2585
+ // That's intentional — frameworks without explicit keys (legacy defaults)
2586
+ // are uniquely identified by the (frameworkId, trackKey, cycleNumber)
2587
+ // constraint above, so multiple NULL templateKey rows are permitted.
2588
+ @@unique([frameworkId, templateKey])
2589
+ }
2590
+
2591
+ model TimelinePhaseTemplate {
2592
+ id String @id @default(dbgenerated("generate_prefixed_cuid('tpt'::text)"))
2593
+ templateId String
2594
+ name String
2595
+ description String?
2596
+ groupLabel String?
2597
+ orderIndex Int
2598
+ defaultDurationWeeks Int
2599
+ completionType PhaseCompletionType @default(MANUAL)
2600
+ locksTimelineOnComplete Boolean @default(false)
2601
+ createdAt DateTime @default(now())
2602
+ updatedAt DateTime @updatedAt
2603
+
2604
+ template TimelineTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
2605
+ phases TimelinePhase[]
2606
+ }
2607
+
2608
+ model TimelineInstance {
2609
+ id String @id @default(dbgenerated("generate_prefixed_cuid('tli'::text)"))
2610
+ organizationId String
2611
+ frameworkInstanceId String
2612
+ templateId String
2613
+ trackKey String @default("primary")
2614
+ cycleNumber Int
2615
+ status TimelineStatus @default(DRAFT)
2616
+ startDate DateTime?
2617
+ pausedAt DateTime?
2618
+ lockedAt DateTime?
2619
+ lockedById String?
2620
+ unlockedAt DateTime?
2621
+ unlockedById String?
2622
+ unlockReason String?
2623
+ completedAt DateTime?
2624
+ createdAt DateTime @default(now())
2625
+ updatedAt DateTime @updatedAt
2626
+
2627
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
2628
+ frameworkInstance FrameworkInstance @relation(fields: [frameworkInstanceId], references: [id], onDelete: Cascade)
2629
+ template TimelineTemplate @relation(fields: [templateId], references: [id])
2630
+ lockedBy User? @relation("TimelineInstanceLockedBy", fields: [lockedById], references: [id])
2631
+ unlockedBy User? @relation("TimelineInstanceUnlockedBy", fields: [unlockedById], references: [id])
2632
+ phases TimelinePhase[]
2633
+
2634
+ @@unique([frameworkInstanceId, trackKey, cycleNumber])
2635
+ }
2636
+
2637
+ model TimelinePhase {
2638
+ id String @id @default(dbgenerated("generate_prefixed_cuid('tlp'::text)"))
2639
+ instanceId String
2640
+ phaseTemplateId String?
2641
+ name String
2642
+ description String?
2643
+ groupLabel String?
2644
+ orderIndex Int
2645
+ status TimelinePhaseStatus @default(PENDING)
2646
+ startDate DateTime?
2647
+ endDate DateTime?
2648
+ durationWeeks Int
2649
+ completionType PhaseCompletionType @default(MANUAL)
2650
+ locksTimelineOnComplete Boolean @default(false)
2651
+ regressedAt DateTime?
2652
+ datesPinned Boolean @default(false)
2653
+ completedAt DateTime?
2654
+ completedById String?
2655
+ readyForReview Boolean @default(false)
2656
+ readyForReviewAt DateTime?
2657
+ documentUrl String?
2658
+ documentName String?
2659
+ createdAt DateTime @default(now())
2660
+ updatedAt DateTime @updatedAt
2661
+
2662
+ instance TimelineInstance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
2663
+ phaseTemplate TimelinePhaseTemplate? @relation(fields: [phaseTemplateId], references: [id])
2664
+ completedBy User? @relation(fields: [completedById], references: [id])
2665
+ }
2291
2666
 
2292
2667
  // ===== trust.prisma =====
2293
2668
  model Trust {
@@ -2542,7 +2917,6 @@ model TrustCustomLink {
2542
2917
  @@index([organizationId, isActive, order])
2543
2918
  }
2544
2919
 
2545
-
2546
2920
  // ===== vendor.prisma =====
2547
2921
  model Vendor {
2548
2922
  id String @id @default(dbgenerated("generate_prefixed_cuid('vnd'::text)"))
@@ -2572,6 +2946,7 @@ model Vendor {
2572
2946
  assignee Member? @relation(fields: [assigneeId], references: [id], onDelete: Cascade)
2573
2947
  contacts VendorContact[]
2574
2948
  tasks Task[]
2949
+ findings Finding[]
2575
2950
 
2576
2951
  @@index([organizationId])
2577
2952
  @@index([assigneeId])