@open-mercato/core 0.7.1-develop.7178.1.ab93fbaf4e → 0.7.1-develop.7180.1.9717fbbb43

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 (808) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/staff_time_entry/index.js +14 -0
  3. package/dist/generated/entities/staff_time_entry/index.js.map +2 -2
  4. package/dist/generated/entities/staff_time_entry_tag/index.js +15 -0
  5. package/dist/generated/entities/staff_time_entry_tag/index.js.map +7 -0
  6. package/dist/generated/entities/staff_time_project/index.js +16 -0
  7. package/dist/generated/entities/staff_time_project/index.js.map +2 -2
  8. package/dist/generated/entities/staff_time_report/index.js +57 -0
  9. package/dist/generated/entities/staff_time_report/index.js.map +7 -0
  10. package/dist/generated/entities/staff_time_report_entry/index.js +27 -0
  11. package/dist/generated/entities/staff_time_report_entry/index.js.map +7 -0
  12. package/dist/generated/entities/staff_time_report_event/index.js +21 -0
  13. package/dist/generated/entities/staff_time_report_event/index.js.map +7 -0
  14. package/dist/generated/entities/staff_time_report_project/index.js +15 -0
  15. package/dist/generated/entities/staff_time_report_project/index.js.map +7 -0
  16. package/dist/generated/entities/staff_time_tag/index.js +21 -0
  17. package/dist/generated/entities/staff_time_tag/index.js.map +7 -0
  18. package/dist/generated/entities/staff_time_task/index.js +37 -0
  19. package/dist/generated/entities/staff_time_task/index.js.map +7 -0
  20. package/dist/generated/entities/staff_time_task_comment/index.js +21 -0
  21. package/dist/generated/entities/staff_time_task_comment/index.js.map +7 -0
  22. package/dist/generated/entities/staff_time_task_status/index.js +29 -0
  23. package/dist/generated/entities/staff_time_task_status/index.js.map +7 -0
  24. package/dist/generated/entities/staff_time_task_tag/index.js +15 -0
  25. package/dist/generated/entities/staff_time_task_tag/index.js.map +7 -0
  26. package/dist/generated/entities.ids.generated.js +11 -1
  27. package/dist/generated/entities.ids.generated.js.map +2 -2
  28. package/dist/generated/entity-fields-registry.js +149 -0
  29. package/dist/generated/entity-fields-registry.js.map +2 -2
  30. package/dist/helpers/integration/timesheetFixtures.js +7 -0
  31. package/dist/helpers/integration/timesheetFixtures.js.map +2 -2
  32. package/dist/modules/auth/cli.js +16 -0
  33. package/dist/modules/auth/cli.js.map +2 -2
  34. package/dist/modules/auth/lib/backendChrome.js +1 -0
  35. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  36. package/dist/modules/customer_accounts/lib/customerRoleAcls.js +44 -0
  37. package/dist/modules/customer_accounts/lib/customerRoleAcls.js.map +7 -0
  38. package/dist/modules/customer_accounts/setup.js +1 -28
  39. package/dist/modules/customer_accounts/setup.js.map +2 -2
  40. package/dist/modules/data_sync/api/options.js +2 -0
  41. package/dist/modules/data_sync/api/options.js.map +2 -2
  42. package/dist/modules/data_sync/backend/data-sync/page.js +39 -17
  43. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  44. package/dist/modules/data_sync/lib/start-controls.js +42 -0
  45. package/dist/modules/data_sync/lib/start-controls.js.map +7 -0
  46. package/dist/modules/staff/acl.js +9 -1
  47. package/dist/modules/staff/acl.js.map +2 -2
  48. package/dist/modules/staff/ai-agents.js +142 -0
  49. package/dist/modules/staff/ai-agents.js.map +7 -0
  50. package/dist/modules/staff/ai-tools/time-tracking-pack.js +348 -0
  51. package/dist/modules/staff/ai-tools/time-tracking-pack.js.map +7 -0
  52. package/dist/modules/staff/ai-tools/types.js +54 -0
  53. package/dist/modules/staff/ai-tools/types.js.map +7 -0
  54. package/dist/modules/staff/ai-tools.js +8 -0
  55. package/dist/modules/staff/ai-tools.js.map +7 -0
  56. package/dist/modules/staff/analytics.js +84 -1
  57. package/dist/modules/staff/analytics.js.map +2 -2
  58. package/dist/modules/staff/api/guards.js +37 -3
  59. package/dist/modules/staff/api/guards.js.map +2 -2
  60. package/dist/modules/staff/api/leave-requests/accept/route.js +1 -3
  61. package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
  62. package/dist/modules/staff/api/leave-requests/reject/route.js +1 -3
  63. package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
  64. package/dist/modules/staff/api/portal/time-reports/[id]/route.js +131 -0
  65. package/dist/modules/staff/api/portal/time-reports/[id]/route.js.map +7 -0
  66. package/dist/modules/staff/api/portal/time-reports/route.js +179 -0
  67. package/dist/modules/staff/api/portal/time-reports/route.js.map +7 -0
  68. package/dist/modules/staff/api/team-members/self/route.js +1 -3
  69. package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
  70. package/dist/modules/staff/api/team-members/tags/assign/route.js +1 -3
  71. package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
  72. package/dist/modules/staff/api/team-members/tags/unassign/route.js +1 -3
  73. package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
  74. package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js +174 -0
  75. package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js.map +7 -0
  76. package/dist/modules/staff/api/timesheets/access-requests/route.js +226 -0
  77. package/dist/modules/staff/api/timesheets/access-requests/route.js.map +7 -0
  78. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +15 -8
  79. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +2 -2
  80. package/dist/modules/staff/api/timesheets/my-projects/route.js +13 -1
  81. package/dist/modules/staff/api/timesheets/my-projects/route.js.map +2 -2
  82. package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js +42 -0
  83. package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js.map +7 -0
  84. package/dist/modules/staff/api/timesheets/my-work/route.js +383 -0
  85. package/dist/modules/staff/api/timesheets/my-work/route.js.map +7 -0
  86. package/dist/modules/staff/api/timesheets/projects/kpis/route.js +14 -2
  87. package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +2 -2
  88. package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js +168 -0
  89. package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js.map +7 -0
  90. package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js +246 -0
  91. package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js.map +7 -0
  92. package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js +183 -0
  93. package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js.map +7 -0
  94. package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js +164 -0
  95. package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js.map +7 -0
  96. package/dist/modules/staff/api/timesheets/reports/preview/route.js +360 -0
  97. package/dist/modules/staff/api/timesheets/reports/preview/route.js.map +7 -0
  98. package/dist/modules/staff/api/timesheets/reports/route.js +316 -0
  99. package/dist/modules/staff/api/timesheets/reports/route.js.map +7 -0
  100. package/dist/modules/staff/api/timesheets/reports/shared.js +63 -0
  101. package/dist/modules/staff/api/timesheets/reports/shared.js.map +7 -0
  102. package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js +164 -0
  103. package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js.map +7 -0
  104. package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js +168 -0
  105. package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js.map +7 -0
  106. package/dist/modules/staff/api/timesheets/settings/route.js +199 -0
  107. package/dist/modules/staff/api/timesheets/settings/route.js.map +7 -0
  108. package/dist/modules/staff/api/timesheets/tags/access.js +76 -0
  109. package/dist/modules/staff/api/timesheets/tags/access.js.map +7 -0
  110. package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js +235 -0
  111. package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js.map +7 -0
  112. package/dist/modules/staff/api/timesheets/tags/route.js +160 -0
  113. package/dist/modules/staff/api/timesheets/tags/route.js.map +7 -0
  114. package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js +233 -0
  115. package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js.map +7 -0
  116. package/dist/modules/staff/api/timesheets/task-statuses/route.js +188 -0
  117. package/dist/modules/staff/api/timesheets/task-statuses/route.js.map +7 -0
  118. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +399 -0
  119. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +7 -0
  120. package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js +210 -0
  121. package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js.map +7 -0
  122. package/dist/modules/staff/api/timesheets/tasks/route.js +333 -0
  123. package/dist/modules/staff/api/timesheets/tasks/route.js.map +7 -0
  124. package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js +228 -0
  125. package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js.map +7 -0
  126. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +29 -10
  127. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +2 -2
  128. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +31 -18
  129. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +2 -2
  130. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +21 -7
  131. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
  132. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +27 -7
  133. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +2 -2
  134. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +215 -32
  135. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +2 -2
  136. package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js +378 -0
  137. package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js.map +7 -0
  138. package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js +340 -0
  139. package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js.map +7 -0
  140. package/dist/modules/staff/api/timesheets/time-entries/route.js +238 -26
  141. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
  142. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +23 -8
  143. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
  144. package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js +209 -0
  145. package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js.map +7 -0
  146. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +59 -2
  147. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +2 -2
  148. package/dist/modules/staff/api/timesheets/time-projects/route.js +264 -22
  149. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
  150. package/dist/modules/staff/backend/staff/time-tracking/board/page.js +110 -0
  151. package/dist/modules/staff/backend/staff/time-tracking/board/page.js.map +7 -0
  152. package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js +18 -0
  153. package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js.map +7 -0
  154. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js +981 -0
  155. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js.map +7 -0
  156. package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js +18 -0
  157. package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js.map +7 -0
  158. package/dist/modules/staff/backend/staff/time-tracking/page.js +583 -0
  159. package/dist/modules/staff/backend/staff/time-tracking/page.js.map +7 -0
  160. package/dist/modules/staff/backend/staff/time-tracking/page.meta.js +15 -0
  161. package/dist/modules/staff/backend/staff/time-tracking/page.meta.js.map +7 -0
  162. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js +65 -0
  163. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js.map +7 -0
  164. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js +16 -0
  165. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js.map +7 -0
  166. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +229 -0
  167. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +7 -0
  168. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js +16 -0
  169. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js.map +7 -0
  170. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +1014 -0
  171. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +7 -0
  172. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js +16 -0
  173. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js.map +7 -0
  174. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js +97 -0
  175. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js.map +7 -0
  176. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js +16 -0
  177. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js.map +7 -0
  178. package/dist/modules/staff/backend/staff/time-tracking/projects/page.js +1040 -0
  179. package/dist/modules/staff/backend/staff/time-tracking/projects/page.js.map +7 -0
  180. package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js +19 -0
  181. package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js.map +7 -0
  182. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js +353 -0
  183. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js.map +7 -0
  184. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js +457 -0
  185. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js.map +7 -0
  186. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js +16 -0
  187. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js.map +7 -0
  188. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js +697 -0
  189. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js.map +7 -0
  190. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js +16 -0
  191. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js.map +7 -0
  192. package/dist/modules/staff/backend/staff/time-tracking/reports/page.js +174 -0
  193. package/dist/modules/staff/backend/staff/time-tracking/reports/page.js.map +7 -0
  194. package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js +18 -0
  195. package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js.map +7 -0
  196. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js +546 -0
  197. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js.map +7 -0
  198. package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js +18 -0
  199. package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js.map +7 -0
  200. package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js +710 -0
  201. package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js.map +7 -0
  202. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js +646 -0
  203. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js.map +7 -0
  204. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js +18 -0
  205. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js.map +7 -0
  206. package/dist/modules/staff/backend/staff/timesheets/page.js +4 -793
  207. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  208. package/dist/modules/staff/backend/staff/timesheets/page.meta.js +2 -7
  209. package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +2 -2
  210. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +5 -136
  211. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +2 -2
  212. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +1 -7
  213. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +2 -2
  214. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +5 -445
  215. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +3 -3
  216. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +1 -7
  217. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +2 -2
  218. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +4 -76
  219. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +2 -2
  220. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +1 -7
  221. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +2 -2
  222. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +4 -613
  223. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  224. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +2 -17
  225. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +2 -2
  226. package/dist/modules/staff/ce.js +40 -0
  227. package/dist/modules/staff/ce.js.map +2 -2
  228. package/dist/modules/staff/cli.js +166 -1
  229. package/dist/modules/staff/cli.js.map +2 -2
  230. package/dist/modules/staff/commands/index.js +5 -0
  231. package/dist/modules/staff/commands/index.js.map +2 -2
  232. package/dist/modules/staff/commands/timesheets-entries.js +569 -21
  233. package/dist/modules/staff/commands/timesheets-entries.js.map +3 -3
  234. package/dist/modules/staff/commands/timesheets-projects.js +450 -7
  235. package/dist/modules/staff/commands/timesheets-projects.js.map +2 -2
  236. package/dist/modules/staff/commands/timesheets-reports.js +1036 -0
  237. package/dist/modules/staff/commands/timesheets-reports.js.map +7 -0
  238. package/dist/modules/staff/commands/timesheets-tags.js +1015 -0
  239. package/dist/modules/staff/commands/timesheets-tags.js.map +7 -0
  240. package/dist/modules/staff/commands/timesheets-task-comments.js +438 -0
  241. package/dist/modules/staff/commands/timesheets-task-comments.js.map +7 -0
  242. package/dist/modules/staff/commands/timesheets-task-statuses.js +723 -0
  243. package/dist/modules/staff/commands/timesheets-task-statuses.js.map +7 -0
  244. package/dist/modules/staff/commands/timesheets-tasks.js +834 -0
  245. package/dist/modules/staff/commands/timesheets-tasks.js.map +7 -0
  246. package/dist/modules/staff/data/enrichers.js +426 -12
  247. package/dist/modules/staff/data/enrichers.js.map +2 -2
  248. package/dist/modules/staff/data/entities.js +552 -3
  249. package/dist/modules/staff/data/entities.js.map +2 -2
  250. package/dist/modules/staff/data/extensions.js +41 -0
  251. package/dist/modules/staff/data/extensions.js.map +7 -0
  252. package/dist/modules/staff/data/validators.js +254 -9
  253. package/dist/modules/staff/data/validators.js.map +2 -2
  254. package/dist/modules/staff/di.js +42 -1
  255. package/dist/modules/staff/di.js.map +2 -2
  256. package/dist/modules/staff/events.js +84 -6
  257. package/dist/modules/staff/events.js.map +2 -2
  258. package/dist/modules/staff/events.payloads.js +158 -0
  259. package/dist/modules/staff/events.payloads.js.map +7 -0
  260. package/dist/modules/staff/extension-points.js +261 -0
  261. package/dist/modules/staff/extension-points.js.map +7 -0
  262. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js +138 -0
  263. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js.map +7 -0
  264. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js +12 -0
  265. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js.map +7 -0
  266. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js +133 -0
  267. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js.map +7 -0
  268. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js +19 -0
  269. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js.map +7 -0
  270. package/dist/modules/staff/lib/crud.js +11 -1
  271. package/dist/modules/staff/lib/crud.js.map +2 -2
  272. package/dist/modules/staff/lib/time-tracking/access.js +92 -0
  273. package/dist/modules/staff/lib/time-tracking/access.js.map +7 -0
  274. package/dist/modules/staff/lib/time-tracking/billability.js +39 -0
  275. package/dist/modules/staff/lib/time-tracking/billability.js.map +7 -0
  276. package/dist/modules/staff/lib/time-tracking/capacity.js +68 -0
  277. package/dist/modules/staff/lib/time-tracking/capacity.js.map +7 -0
  278. package/dist/modules/staff/lib/time-tracking/componentContracts.js +15 -0
  279. package/dist/modules/staff/lib/time-tracking/componentContracts.js.map +7 -0
  280. package/dist/modules/staff/lib/time-tracking/cost.js +82 -0
  281. package/dist/modules/staff/lib/time-tracking/cost.js.map +7 -0
  282. package/dist/modules/staff/lib/time-tracking/duration.js +55 -0
  283. package/dist/modules/staff/lib/time-tracking/duration.js.map +7 -0
  284. package/dist/modules/staff/lib/time-tracking/featureAccess.js +41 -0
  285. package/dist/modules/staff/lib/time-tracking/featureAccess.js.map +7 -0
  286. package/dist/modules/staff/lib/time-tracking/interval.js +72 -0
  287. package/dist/modules/staff/lib/time-tracking/interval.js.map +7 -0
  288. package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js +88 -0
  289. package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js.map +7 -0
  290. package/dist/modules/staff/lib/time-tracking/moneyVisibility.js +10 -0
  291. package/dist/modules/staff/lib/time-tracking/moneyVisibility.js.map +7 -0
  292. package/dist/modules/staff/lib/time-tracking/overlap.js +87 -0
  293. package/dist/modules/staff/lib/time-tracking/overlap.js.map +7 -0
  294. package/dist/modules/staff/lib/time-tracking/portalRecipients.js +27 -0
  295. package/dist/modules/staff/lib/time-tracking/portalRecipients.js.map +7 -0
  296. package/dist/modules/staff/lib/time-tracking/portalReports.js +16 -0
  297. package/dist/modules/staff/lib/time-tracking/portalReports.js.map +7 -0
  298. package/dist/modules/staff/lib/time-tracking/projectCode.js +135 -0
  299. package/dist/modules/staff/lib/time-tracking/projectCode.js.map +7 -0
  300. package/dist/modules/staff/lib/time-tracking/reapplyRounding.js +187 -0
  301. package/dist/modules/staff/lib/time-tracking/reapplyRounding.js.map +7 -0
  302. package/dist/modules/staff/lib/time-tracking/recalculationRunner.js +80 -0
  303. package/dist/modules/staff/lib/time-tracking/recalculationRunner.js.map +7 -0
  304. package/dist/modules/staff/lib/time-tracking/recalculations.js +56 -0
  305. package/dist/modules/staff/lib/time-tracking/recalculations.js.map +7 -0
  306. package/dist/modules/staff/lib/time-tracking/registries/invoke.js +63 -0
  307. package/dist/modules/staff/lib/time-tracking/registries/invoke.js.map +7 -0
  308. package/dist/modules/staff/lib/time-tracking/registries/registry.js +62 -0
  309. package/dist/modules/staff/lib/time-tracking/registries/registry.js.map +7 -0
  310. package/dist/modules/staff/lib/time-tracking/registries/scope.js +21 -0
  311. package/dist/modules/staff/lib/time-tracking/registries/scope.js.map +7 -0
  312. package/dist/modules/staff/lib/time-tracking/rollup.js +34 -0
  313. package/dist/modules/staff/lib/time-tracking/rollup.js.map +7 -0
  314. package/dist/modules/staff/lib/time-tracking/rounding.js +66 -0
  315. package/dist/modules/staff/lib/time-tracking/rounding.js.map +7 -0
  316. package/dist/modules/staff/lib/time-tracking/roundingImpact.js +39 -0
  317. package/dist/modules/staff/lib/time-tracking/roundingImpact.js.map +7 -0
  318. package/dist/modules/staff/lib/time-tracking/settingKeys.js +214 -0
  319. package/dist/modules/staff/lib/time-tracking/settingKeys.js.map +7 -0
  320. package/dist/modules/staff/lib/time-tracking/settings.js +87 -0
  321. package/dist/modules/staff/lib/time-tracking/settings.js.map +7 -0
  322. package/dist/modules/staff/lib/time-tracking/sqlInClause.js +9 -0
  323. package/dist/modules/staff/lib/time-tracking/sqlInClause.js.map +7 -0
  324. package/dist/modules/staff/lib/time-tracking/timeEntrySources.js +48 -0
  325. package/dist/modules/staff/lib/time-tracking/timeEntrySources.js.map +7 -0
  326. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js +283 -0
  327. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js.map +7 -0
  328. package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js +324 -0
  329. package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js.map +7 -0
  330. package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js +121 -0
  331. package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js.map +7 -0
  332. package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js +188 -0
  333. package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js.map +7 -0
  334. package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js +89 -0
  335. package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js.map +7 -0
  336. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js +855 -0
  337. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js.map +7 -0
  338. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js +360 -0
  339. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js.map +7 -0
  340. package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js +259 -0
  341. package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js.map +7 -0
  342. package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js +238 -0
  343. package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js.map +7 -0
  344. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js +130 -0
  345. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js.map +7 -0
  346. package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js +98 -0
  347. package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js.map +7 -0
  348. package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js +27 -0
  349. package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js.map +7 -0
  350. package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js +166 -0
  351. package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js.map +7 -0
  352. package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js +295 -0
  353. package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js.map +7 -0
  354. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js +212 -0
  355. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js.map +7 -0
  356. package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js +729 -0
  357. package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js.map +7 -0
  358. package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js +217 -0
  359. package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js.map +7 -0
  360. package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js +158 -0
  361. package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js.map +7 -0
  362. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js +224 -0
  363. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js.map +7 -0
  364. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js +93 -0
  365. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js.map +7 -0
  366. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js +1196 -0
  367. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js.map +7 -0
  368. package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js +176 -0
  369. package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js.map +7 -0
  370. package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js +307 -0
  371. package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js.map +7 -0
  372. package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js +284 -0
  373. package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js.map +7 -0
  374. package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js +73 -0
  375. package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js.map +7 -0
  376. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js +1499 -0
  377. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js.map +7 -0
  378. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js +95 -0
  379. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js.map +7 -0
  380. package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js +188 -0
  381. package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js.map +7 -0
  382. package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js +61 -0
  383. package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js.map +7 -0
  384. package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js +45 -0
  385. package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js.map +7 -0
  386. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js +176 -0
  387. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js.map +7 -0
  388. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js +82 -0
  389. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js.map +7 -0
  390. package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js +5 -0
  391. package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js.map +7 -0
  392. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js +152 -0
  393. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js.map +7 -0
  394. package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js +92 -0
  395. package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js.map +7 -0
  396. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js +111 -0
  397. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js.map +7 -0
  398. package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js +243 -0
  399. package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js.map +7 -0
  400. package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js +151 -0
  401. package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js.map +7 -0
  402. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js +105 -0
  403. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js.map +7 -0
  404. package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js +132 -0
  405. package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js.map +7 -0
  406. package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js +205 -0
  407. package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js.map +7 -0
  408. package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js +53 -0
  409. package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js.map +7 -0
  410. package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js +77 -0
  411. package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js.map +7 -0
  412. package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js +151 -0
  413. package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js.map +7 -0
  414. package/dist/modules/staff/lib/timeTrackingSeeds.js +809 -0
  415. package/dist/modules/staff/lib/timeTrackingSeeds.js.map +7 -0
  416. package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js +2 -3
  417. package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js.map +2 -2
  418. package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js +152 -0
  419. package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js.map +7 -0
  420. package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js +36 -0
  421. package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js.map +7 -0
  422. package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js +66 -0
  423. package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js.map +7 -0
  424. package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js +78 -0
  425. package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js.map +7 -0
  426. package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js +81 -0
  427. package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js.map +7 -0
  428. package/dist/modules/staff/lib/timesheets-projects/reportSelection.js +44 -0
  429. package/dist/modules/staff/lib/timesheets-projects/reportSelection.js.map +7 -0
  430. package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js +169 -0
  431. package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js.map +7 -0
  432. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js +22 -0
  433. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js.map +7 -0
  434. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +51 -1
  435. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +2 -2
  436. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js +70 -0
  437. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js.map +7 -0
  438. package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js +63 -0
  439. package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js.map +7 -0
  440. package/dist/modules/staff/lib/timesheets-reports/loadReportData.js +170 -0
  441. package/dist/modules/staff/lib/timesheets-reports/loadReportData.js.map +7 -0
  442. package/dist/modules/staff/lib/timesheets-reports/pdf.js +205 -0
  443. package/dist/modules/staff/lib/timesheets-reports/pdf.js.map +7 -0
  444. package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js +68 -0
  445. package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js.map +7 -0
  446. package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js +135 -0
  447. package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js.map +7 -0
  448. package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js +48 -0
  449. package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js.map +7 -0
  450. package/dist/modules/staff/lib/timesheets-reports/reportExport.js +262 -0
  451. package/dist/modules/staff/lib/timesheets-reports/reportExport.js.map +7 -0
  452. package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js +34 -0
  453. package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js.map +7 -0
  454. package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js +79 -0
  455. package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js.map +7 -0
  456. package/dist/modules/staff/lib/timesheets-reports/reportLabels.js +11 -0
  457. package/dist/modules/staff/lib/timesheets-reports/reportLabels.js.map +7 -0
  458. package/dist/modules/staff/lib/timesheets-reports/reportReference.js +83 -0
  459. package/dist/modules/staff/lib/timesheets-reports/reportReference.js.map +7 -0
  460. package/dist/modules/staff/lib/timesheets-reports/reportRows.js +42 -0
  461. package/dist/modules/staff/lib/timesheets-reports/reportRows.js.map +7 -0
  462. package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js +107 -0
  463. package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js.map +7 -0
  464. package/dist/modules/staff/lib/timesheets-reports/reportTotals.js +289 -0
  465. package/dist/modules/staff/lib/timesheets-reports/reportTotals.js.map +7 -0
  466. package/dist/modules/staff/lib/timesheets-reports/xlsx.js +145 -0
  467. package/dist/modules/staff/lib/timesheets-reports/xlsx.js.map +7 -0
  468. package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js +116 -0
  469. package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js.map +7 -0
  470. package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js +50 -0
  471. package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js.map +7 -0
  472. package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js +27 -0
  473. package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js.map +7 -0
  474. package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js +65 -0
  475. package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js.map +7 -0
  476. package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js +31 -0
  477. package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js.map +7 -0
  478. package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js +31 -0
  479. package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js.map +7 -0
  480. package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js +17 -0
  481. package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js.map +7 -0
  482. package/dist/modules/staff/lib/timesheets-tasks/taskReference.js +51 -0
  483. package/dist/modules/staff/lib/timesheets-tasks/taskReference.js.map +7 -0
  484. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +11 -4
  485. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +2 -2
  486. package/dist/modules/staff/lib/timesheets-ui/ListView.js +369 -111
  487. package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +2 -2
  488. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +47 -2
  489. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +2 -2
  490. package/dist/modules/staff/migrations/Migration20260813073131_staff.js +79 -0
  491. package/dist/modules/staff/migrations/Migration20260813073131_staff.js.map +7 -0
  492. package/dist/modules/staff/migrations/Migration20260824143357_staff.js +15 -0
  493. package/dist/modules/staff/migrations/Migration20260824143357_staff.js.map +7 -0
  494. package/dist/modules/staff/notifications.client.js +16 -0
  495. package/dist/modules/staff/notifications.client.js.map +7 -0
  496. package/dist/modules/staff/notifications.handlers.js +80 -0
  497. package/dist/modules/staff/notifications.handlers.js.map +7 -0
  498. package/dist/modules/staff/notifications.js +168 -0
  499. package/dist/modules/staff/notifications.js.map +2 -2
  500. package/dist/modules/staff/search.js +159 -1
  501. package/dist/modules/staff/search.js.map +2 -2
  502. package/dist/modules/staff/setup.js +20 -1
  503. package/dist/modules/staff/setup.js.map +2 -2
  504. package/dist/modules/staff/subscribers/time-project-access-requested-notification.js +68 -0
  505. package/dist/modules/staff/subscribers/time-project-access-requested-notification.js.map +7 -0
  506. package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js +149 -0
  507. package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js.map +7 -0
  508. package/dist/modules/staff/subscribers/time-report-approved-notification.js +78 -0
  509. package/dist/modules/staff/subscribers/time-report-approved-notification.js.map +7 -0
  510. package/dist/modules/staff/subscribers/time-report-portal-broadcast.js +78 -0
  511. package/dist/modules/staff/subscribers/time-report-portal-broadcast.js.map +7 -0
  512. package/dist/modules/staff/translations.js +4 -1
  513. package/dist/modules/staff/translations.js.map +2 -2
  514. package/dist/modules/staff/widgets/components.js +7 -0
  515. package/dist/modules/staff/widgets/components.js.map +7 -0
  516. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +5 -4
  517. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +2 -2
  518. package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js +135 -0
  519. package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js.map +7 -0
  520. package/dist/modules/staff/widgets/notifications/index.js +5 -0
  521. package/dist/modules/staff/widgets/notifications/index.js.map +7 -0
  522. package/dist/modules/staff/workers/timesheets-reapply-rounding.js +43 -0
  523. package/dist/modules/staff/workers/timesheets-reapply-rounding.js.map +7 -0
  524. package/generated/entities/staff_time_entry/index.ts +7 -0
  525. package/generated/entities/staff_time_entry_tag/index.ts +6 -0
  526. package/generated/entities/staff_time_project/index.ts +8 -0
  527. package/generated/entities/staff_time_report/index.ts +27 -0
  528. package/generated/entities/staff_time_report_entry/index.ts +12 -0
  529. package/generated/entities/staff_time_report_event/index.ts +9 -0
  530. package/generated/entities/staff_time_report_project/index.ts +6 -0
  531. package/generated/entities/staff_time_tag/index.ts +9 -0
  532. package/generated/entities/staff_time_task/index.ts +17 -0
  533. package/generated/entities/staff_time_task_comment/index.ts +9 -0
  534. package/generated/entities/staff_time_task_status/index.ts +13 -0
  535. package/generated/entities/staff_time_task_tag/index.ts +6 -0
  536. package/generated/entities.ids.generated.ts +11 -1
  537. package/generated/entity-fields-registry.ts +149 -0
  538. package/package.json +7 -7
  539. package/src/helpers/integration/timesheetFixtures.ts +31 -1
  540. package/src/modules/auth/README.md +1 -1
  541. package/src/modules/auth/cli.ts +35 -1
  542. package/src/modules/auth/i18n/de.json +7 -0
  543. package/src/modules/auth/i18n/en.json +7 -0
  544. package/src/modules/auth/i18n/es.json +7 -0
  545. package/src/modules/auth/i18n/ko.json +7 -0
  546. package/src/modules/auth/i18n/pl.json +7 -0
  547. package/src/modules/auth/lib/backendChrome.tsx +1 -0
  548. package/src/modules/customer_accounts/lib/customerRoleAcls.ts +79 -0
  549. package/src/modules/customer_accounts/setup.ts +1 -45
  550. package/src/modules/data_sync/AGENTS.md +34 -0
  551. package/src/modules/data_sync/api/options.ts +2 -0
  552. package/src/modules/data_sync/backend/data-sync/page.tsx +82 -33
  553. package/src/modules/data_sync/i18n/de.json +1 -0
  554. package/src/modules/data_sync/i18n/en.json +1 -0
  555. package/src/modules/data_sync/i18n/es.json +1 -0
  556. package/src/modules/data_sync/i18n/ko.json +1 -0
  557. package/src/modules/data_sync/i18n/pl.json +1 -0
  558. package/src/modules/data_sync/lib/adapter.ts +45 -0
  559. package/src/modules/data_sync/lib/start-controls.ts +89 -0
  560. package/src/modules/staff/AGENTS.md +769 -1
  561. package/src/modules/staff/acl.ts +9 -0
  562. package/src/modules/staff/ai-agents.ts +189 -0
  563. package/src/modules/staff/ai-tools/time-tracking-pack.ts +494 -0
  564. package/src/modules/staff/ai-tools/types.ts +82 -0
  565. package/src/modules/staff/ai-tools.ts +13 -0
  566. package/src/modules/staff/analytics.ts +113 -0
  567. package/src/modules/staff/api/guards.ts +85 -3
  568. package/src/modules/staff/api/leave-requests/accept/route.ts +0 -2
  569. package/src/modules/staff/api/leave-requests/reject/route.ts +0 -2
  570. package/src/modules/staff/api/portal/time-reports/[id]/route.ts +182 -0
  571. package/src/modules/staff/api/portal/time-reports/route.ts +270 -0
  572. package/src/modules/staff/api/team-members/self/route.ts +0 -2
  573. package/src/modules/staff/api/team-members/tags/assign/route.ts +0 -2
  574. package/src/modules/staff/api/team-members/tags/unassign/route.ts +0 -2
  575. package/src/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.ts +292 -0
  576. package/src/modules/staff/api/timesheets/access-requests/route.ts +299 -0
  577. package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +15 -7
  578. package/src/modules/staff/api/timesheets/my-projects/route.ts +14 -1
  579. package/src/modules/staff/api/timesheets/my-work/myWorkAggregate.ts +90 -0
  580. package/src/modules/staff/api/timesheets/my-work/route.ts +475 -0
  581. package/src/modules/staff/api/timesheets/projects/kpis/route.ts +15 -2
  582. package/src/modules/staff/api/timesheets/reports/[id]/close/route.ts +203 -0
  583. package/src/modules/staff/api/timesheets/reports/[id]/export/route.ts +315 -0
  584. package/src/modules/staff/api/timesheets/reports/[id]/sheet/route.ts +220 -0
  585. package/src/modules/staff/api/timesheets/reports/[id]/unlock/route.ts +208 -0
  586. package/src/modules/staff/api/timesheets/reports/preview/route.ts +449 -0
  587. package/src/modules/staff/api/timesheets/reports/route.ts +386 -0
  588. package/src/modules/staff/api/timesheets/reports/shared.ts +121 -0
  589. package/src/modules/staff/api/timesheets/settings/reapply-rounding/route.ts +205 -0
  590. package/src/modules/staff/api/timesheets/settings/rounding-impact/route.ts +226 -0
  591. package/src/modules/staff/api/timesheets/settings/route.ts +242 -0
  592. package/src/modules/staff/api/timesheets/tags/access.ts +134 -0
  593. package/src/modules/staff/api/timesheets/tags/entry-assignments/route.ts +290 -0
  594. package/src/modules/staff/api/timesheets/tags/route.ts +177 -0
  595. package/src/modules/staff/api/timesheets/tags/task-assignments/route.ts +294 -0
  596. package/src/modules/staff/api/timesheets/task-statuses/route.ts +232 -0
  597. package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +532 -0
  598. package/src/modules/staff/api/timesheets/tasks/[id]/status/route.ts +271 -0
  599. package/src/modules/staff/api/timesheets/tasks/route.ts +443 -0
  600. package/src/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.ts +306 -0
  601. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +32 -10
  602. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +32 -17
  603. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +27 -6
  604. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +36 -6
  605. package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +331 -34
  606. package/src/modules/staff/api/timesheets/time-entries/copy-day/route.ts +533 -0
  607. package/src/modules/staff/api/timesheets/time-entries/overlaps/route.ts +457 -0
  608. package/src/modules/staff/api/timesheets/time-entries/route.ts +378 -24
  609. package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +31 -9
  610. package/src/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.ts +246 -0
  611. package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +62 -2
  612. package/src/modules/staff/api/timesheets/time-projects/route.ts +397 -22
  613. package/src/modules/staff/backend/staff/time-tracking/board/page.meta.ts +14 -0
  614. package/src/modules/staff/backend/staff/time-tracking/board/page.tsx +151 -0
  615. package/src/modules/staff/backend/staff/time-tracking/entries/page.meta.ts +14 -0
  616. package/src/modules/staff/backend/staff/time-tracking/entries/page.tsx +1229 -0
  617. package/src/modules/staff/backend/staff/time-tracking/page.meta.ts +11 -0
  618. package/src/modules/staff/backend/staff/time-tracking/page.tsx +823 -0
  619. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.ts +12 -0
  620. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.tsx +81 -0
  621. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.ts +12 -0
  622. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +275 -0
  623. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.ts +12 -0
  624. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +1420 -0
  625. package/src/modules/staff/backend/staff/time-tracking/projects/create/page.meta.ts +12 -0
  626. package/src/modules/staff/backend/staff/time-tracking/projects/create/page.tsx +109 -0
  627. package/src/modules/staff/backend/staff/time-tracking/projects/page.meta.ts +15 -0
  628. package/src/modules/staff/backend/staff/time-tracking/projects/page.tsx +1254 -0
  629. package/src/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.ts +466 -0
  630. package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.ts +12 -0
  631. package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.tsx +632 -0
  632. package/src/modules/staff/backend/staff/time-tracking/reports/create/page.meta.ts +12 -0
  633. package/src/modules/staff/backend/staff/time-tracking/reports/create/page.tsx +867 -0
  634. package/src/modules/staff/backend/staff/time-tracking/reports/page.meta.ts +14 -0
  635. package/src/modules/staff/backend/staff/time-tracking/reports/page.tsx +246 -0
  636. package/src/modules/staff/backend/staff/time-tracking/settings/page.meta.ts +14 -0
  637. package/src/modules/staff/backend/staff/time-tracking/settings/page.tsx +701 -0
  638. package/src/modules/staff/backend/staff/time-tracking/timesheet/GridView.tsx +953 -0
  639. package/src/modules/staff/backend/staff/time-tracking/timesheet/page.meta.ts +14 -0
  640. package/src/modules/staff/backend/staff/time-tracking/timesheet/page.tsx +800 -0
  641. package/src/modules/staff/backend/staff/timesheets/page.meta.ts +6 -6
  642. package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1010
  643. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +0 -6
  644. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +4 -158
  645. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +0 -6
  646. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -609
  647. package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +0 -6
  648. package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +3 -89
  649. package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +2 -19
  650. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +3 -778
  651. package/src/modules/staff/ce.ts +63 -0
  652. package/src/modules/staff/cli.ts +207 -1
  653. package/src/modules/staff/commands/index.ts +5 -0
  654. package/src/modules/staff/commands/timesheets-entries.ts +1006 -28
  655. package/src/modules/staff/commands/timesheets-projects.ts +593 -7
  656. package/src/modules/staff/commands/timesheets-reports.ts +1329 -0
  657. package/src/modules/staff/commands/timesheets-tags.ts +1315 -0
  658. package/src/modules/staff/commands/timesheets-task-comments.ts +583 -0
  659. package/src/modules/staff/commands/timesheets-task-statuses.ts +889 -0
  660. package/src/modules/staff/commands/timesheets-tasks.ts +1121 -0
  661. package/src/modules/staff/data/enrichers.ts +675 -10
  662. package/src/modules/staff/data/entities.ts +494 -2
  663. package/src/modules/staff/data/extensions.ts +68 -0
  664. package/src/modules/staff/data/validators.ts +348 -3
  665. package/src/modules/staff/di.ts +96 -0
  666. package/src/modules/staff/events.payloads.ts +268 -0
  667. package/src/modules/staff/events.ts +87 -5
  668. package/src/modules/staff/extension-points.ts +308 -0
  669. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.ts +10 -0
  670. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.tsx +225 -0
  671. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.ts +17 -0
  672. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.tsx +182 -0
  673. package/src/modules/staff/i18n/de.json +899 -0
  674. package/src/modules/staff/i18n/en.json +899 -0
  675. package/src/modules/staff/i18n/es.json +899 -0
  676. package/src/modules/staff/i18n/ko.json +899 -0
  677. package/src/modules/staff/i18n/pl.json +899 -0
  678. package/src/modules/staff/lib/crud.ts +14 -3
  679. package/src/modules/staff/lib/time-tracking/access.ts +155 -0
  680. package/src/modules/staff/lib/time-tracking/billability.ts +68 -0
  681. package/src/modules/staff/lib/time-tracking/capacity.ts +124 -0
  682. package/src/modules/staff/lib/time-tracking/componentContracts.ts +26 -0
  683. package/src/modules/staff/lib/time-tracking/cost.ts +144 -0
  684. package/src/modules/staff/lib/time-tracking/duration.ts +68 -0
  685. package/src/modules/staff/lib/time-tracking/featureAccess.ts +115 -0
  686. package/src/modules/staff/lib/time-tracking/interval.ts +90 -0
  687. package/src/modules/staff/lib/time-tracking/migrateProjectCodes.ts +161 -0
  688. package/src/modules/staff/lib/time-tracking/moneyVisibility.ts +37 -0
  689. package/src/modules/staff/lib/time-tracking/overlap.ts +159 -0
  690. package/src/modules/staff/lib/time-tracking/portalRecipients.ts +76 -0
  691. package/src/modules/staff/lib/time-tracking/portalReports.ts +31 -0
  692. package/src/modules/staff/lib/time-tracking/projectCode.ts +221 -0
  693. package/src/modules/staff/lib/time-tracking/reapplyRounding.ts +313 -0
  694. package/src/modules/staff/lib/time-tracking/recalculationRunner.ts +118 -0
  695. package/src/modules/staff/lib/time-tracking/recalculations.ts +135 -0
  696. package/src/modules/staff/lib/time-tracking/registries/invoke.ts +122 -0
  697. package/src/modules/staff/lib/time-tracking/registries/registry.ts +124 -0
  698. package/src/modules/staff/lib/time-tracking/registries/scope.ts +56 -0
  699. package/src/modules/staff/lib/time-tracking/rollup.ts +59 -0
  700. package/src/modules/staff/lib/time-tracking/rounding.ts +126 -0
  701. package/src/modules/staff/lib/time-tracking/roundingImpact.ts +75 -0
  702. package/src/modules/staff/lib/time-tracking/settingKeys.ts +274 -0
  703. package/src/modules/staff/lib/time-tracking/settings.ts +168 -0
  704. package/src/modules/staff/lib/time-tracking/sqlInClause.ts +22 -0
  705. package/src/modules/staff/lib/time-tracking/timeEntrySources.ts +85 -0
  706. package/src/modules/staff/lib/time-tracking-ui/BoardFilterChips.tsx +360 -0
  707. package/src/modules/staff/lib/time-tracking-ui/CustomerPicker.tsx +427 -0
  708. package/src/modules/staff/lib/time-tracking-ui/DurationInput.tsx +192 -0
  709. package/src/modules/staff/lib/time-tracking-ui/EntryDetailsFields.tsx +224 -0
  710. package/src/modules/staff/lib/time-tracking-ui/EntryFilterBar.tsx +144 -0
  711. package/src/modules/staff/lib/time-tracking-ui/KanbanBoard.tsx +1065 -0
  712. package/src/modules/staff/lib/time-tracking-ui/KanbanCard.tsx +435 -0
  713. package/src/modules/staff/lib/time-tracking-ui/KanbanColumn.tsx +316 -0
  714. package/src/modules/staff/lib/time-tracking-ui/NewTaskDialog.tsx +291 -0
  715. package/src/modules/staff/lib/time-tracking-ui/NoProjectAccess.tsx +162 -0
  716. package/src/modules/staff/lib/time-tracking-ui/PeriodSelector.tsx +149 -0
  717. package/src/modules/staff/lib/time-tracking-ui/PhasePlaceholder.tsx +31 -0
  718. package/src/modules/staff/lib/time-tracking-ui/ProjectCodeField.tsx +230 -0
  719. package/src/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.tsx +432 -0
  720. package/src/modules/staff/lib/time-tracking-ui/ProjectFormSections.tsx +323 -0
  721. package/src/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.tsx +930 -0
  722. package/src/modules/staff/lib/time-tracking-ui/ReportSheet.tsx +357 -0
  723. package/src/modules/staff/lib/time-tracking-ui/TagPicker.tsx +195 -0
  724. package/src/modules/staff/lib/time-tracking-ui/TaskBoardScreen.tsx +243 -0
  725. package/src/modules/staff/lib/time-tracking-ui/TaskCommentThread.tsx +137 -0
  726. package/src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx +1405 -0
  727. package/src/modules/staff/lib/time-tracking-ui/TaskListView.tsx +260 -0
  728. package/src/modules/staff/lib/time-tracking-ui/TaskPicker.tsx +435 -0
  729. package/src/modules/staff/lib/time-tracking-ui/TaskQuickLog.tsx +296 -0
  730. package/src/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.tsx +97 -0
  731. package/src/modules/staff/lib/time-tracking-ui/TimeEntryDialog.tsx +1929 -0
  732. package/src/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.tsx +126 -0
  733. package/src/modules/staff/lib/time-tracking-ui/TimesheetCalendar.tsx +265 -0
  734. package/src/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.tsx +78 -0
  735. package/src/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.tsx +70 -0
  736. package/src/modules/staff/lib/time-tracking-ui/boardDirectory.ts +231 -0
  737. package/src/modules/staff/lib/time-tracking-ui/boardFilters.ts +128 -0
  738. package/src/modules/staff/lib/time-tracking-ui/boardSummary.ts +20 -0
  739. package/src/modules/staff/lib/time-tracking-ui/kanbanBoardData.ts +228 -0
  740. package/src/modules/staff/lib/time-tracking-ui/projectTeamAssignment.ts +143 -0
  741. package/src/modules/staff/lib/time-tracking-ui/taskDrawerData.ts +194 -0
  742. package/src/modules/staff/lib/time-tracking-ui/timeEntryDialogState.ts +400 -0
  743. package/src/modules/staff/lib/time-tracking-ui/timeEntryListData.ts +271 -0
  744. package/src/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.ts +168 -0
  745. package/src/modules/staff/lib/time-tracking-ui/timesheetData.ts +225 -0
  746. package/src/modules/staff/lib/time-tracking-ui/timesheetPeriod.ts +278 -0
  747. package/src/modules/staff/lib/time-tracking-ui/timesheetTargets.ts +93 -0
  748. package/src/modules/staff/lib/time-tracking-ui/useBoardFilters.ts +107 -0
  749. package/src/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.ts +245 -0
  750. package/src/modules/staff/lib/timeTrackingSeeds.ts +1037 -0
  751. package/src/modules/staff/lib/timesheets/timeEntryCacheInvalidation.ts +11 -10
  752. package/src/modules/staff/lib/timesheets/timeEntryDecoration.ts +256 -0
  753. package/src/modules/staff/lib/timesheets-projects/budgetBurn.ts +60 -0
  754. package/src/modules/staff/lib/timesheets-projects/budgetThreshold.ts +135 -0
  755. package/src/modules/staff/lib/timesheets-projects/budgetThresholdState.ts +137 -0
  756. package/src/modules/staff/lib/timesheets-projects/computeProjectFinancials.ts +142 -0
  757. package/src/modules/staff/lib/timesheets-projects/reportSelection.ts +82 -0
  758. package/src/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.tsx +237 -0
  759. package/src/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.tsx +33 -0
  760. package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +56 -1
  761. package/src/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.tsx +90 -0
  762. package/src/modules/staff/lib/timesheets-reports/buildReportSheet.ts +125 -0
  763. package/src/modules/staff/lib/timesheets-reports/loadReportData.ts +251 -0
  764. package/src/modules/staff/lib/timesheets-reports/pdf.ts +263 -0
  765. package/src/modules/staff/lib/timesheets-reports/reportApprovalPolicies.ts +137 -0
  766. package/src/modules/staff/lib/timesheets-reports/reportConfigData.ts +247 -0
  767. package/src/modules/staff/lib/timesheets-reports/reportConfigState.ts +89 -0
  768. package/src/modules/staff/lib/timesheets-reports/reportExport.ts +373 -0
  769. package/src/modules/staff/lib/timesheets-reports/reportExportFormats.ts +71 -0
  770. package/src/modules/staff/lib/timesheets-reports/reportGroupings.ts +153 -0
  771. package/src/modules/staff/lib/timesheets-reports/reportLabels.ts +23 -0
  772. package/src/modules/staff/lib/timesheets-reports/reportReference.ts +146 -0
  773. package/src/modules/staff/lib/timesheets-reports/reportRows.ts +89 -0
  774. package/src/modules/staff/lib/timesheets-reports/reportSheetData.ts +196 -0
  775. package/src/modules/staff/lib/timesheets-reports/reportTotals.ts +544 -0
  776. package/src/modules/staff/lib/timesheets-reports/xlsx.ts +207 -0
  777. package/src/modules/staff/lib/timesheets-tasks/computeTaskRollups.ts +238 -0
  778. package/src/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.ts +90 -0
  779. package/src/modules/staff/lib/timesheets-tasks/seedProjectStatuses.ts +43 -0
  780. package/src/modules/staff/lib/timesheets-tasks/statusPositions.ts +132 -0
  781. package/src/modules/staff/lib/timesheets-tasks/statusSlug.ts +43 -0
  782. package/src/modules/staff/lib/timesheets-tasks/taskHierarchy.ts +99 -0
  783. package/src/modules/staff/lib/timesheets-tasks/taskHoursTotals.ts +42 -0
  784. package/src/modules/staff/lib/timesheets-tasks/taskReference.ts +108 -0
  785. package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +18 -4
  786. package/src/modules/staff/lib/timesheets-ui/ListView.tsx +504 -149
  787. package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +50 -2
  788. package/src/modules/staff/migrations/.snapshot-open-mercato.json +3244 -228
  789. package/src/modules/staff/migrations/Migration20260813073131_staff.ts +94 -0
  790. package/src/modules/staff/migrations/Migration20260824143357_staff.ts +17 -0
  791. package/src/modules/staff/notifications.client.ts +16 -0
  792. package/src/modules/staff/notifications.handlers.ts +88 -0
  793. package/src/modules/staff/notifications.ts +163 -0
  794. package/src/modules/staff/search.ts +191 -1
  795. package/src/modules/staff/setup.ts +22 -0
  796. package/src/modules/staff/subscribers/time-project-access-requested-notification.ts +95 -0
  797. package/src/modules/staff/subscribers/time-project-budget-threshold-notification.ts +226 -0
  798. package/src/modules/staff/subscribers/time-report-approved-notification.ts +116 -0
  799. package/src/modules/staff/subscribers/time-report-portal-broadcast.ts +120 -0
  800. package/src/modules/staff/translations.ts +17 -0
  801. package/src/modules/staff/widgets/components.ts +34 -0
  802. package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +6 -5
  803. package/src/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.tsx +138 -0
  804. package/src/modules/staff/widgets/notifications/index.ts +1 -0
  805. package/src/modules/staff/workers/timesheets-reapply-rounding.ts +59 -0
  806. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +0 -123
  807. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +0 -7
  808. package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +0 -138
@@ -0,0 +1,1037 @@
1
+ /**
2
+ * Demo data for the time-tracking consulting suite.
3
+ *
4
+ * The module has a cold-start problem the team examples do not: a fresh tenant
5
+ * lands on an empty portfolio, an empty board, an empty week grid and an empty
6
+ * report list, and every screen that makes the module worth having only means
7
+ * something once hours exist. This seed fills all four at once — four projects
8
+ * against real customers, a populated Kanban board, ten weeks of logged time and
9
+ * two reports, one of them closed so the lock behaviour is visible without
10
+ * anybody having to close one first.
11
+ *
12
+ * Everything is derived from a fixed pseudo-random sequence rather than
13
+ * `Math.random`, so two people demoing the same build see the same hours and the
14
+ * same totals, and a screenshot stays true after a re-seed.
15
+ *
16
+ * Idempotency is a single check on the demo project codes: this is example data,
17
+ * not reference data, so it is written once and afterwards left alone rather
18
+ * than reconciled field by field.
19
+ *
20
+ * **Indexing.** Rows are written straight through the EntityManager rather than
21
+ * through the module's commands, so none of them reach the query index. Listing
22
+ * is unaffected — the engine reads base tables — but `$ilike` filters are
23
+ * answered from the token index, so search returns nothing for seeded data until
24
+ * `mercato query_index reindex` has run. The CLI command says so on success; a
25
+ * caller invoking this function directly has to know.
26
+ */
27
+
28
+ import type { EntityManager } from '@mikro-orm/postgresql'
29
+ import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
30
+ import { User } from '@open-mercato/core/modules/auth/data/entities'
31
+ import { CustomerEntity } from '@open-mercato/core/modules/customers/data/entities'
32
+ import {
33
+ StaffTeamMember,
34
+ StaffTimeEntry,
35
+ StaffTimeEntryTag,
36
+ StaffTimeProject,
37
+ StaffTimeProjectMember,
38
+ StaffTimeReport,
39
+ StaffTimeReportEntry,
40
+ StaffTimeReportEvent,
41
+ StaffTimeReportProject,
42
+ StaffTimeTag,
43
+ StaffTimeTask,
44
+ StaffTimeTaskComment,
45
+ StaffTimeTaskStatus,
46
+ StaffTimeTaskTag,
47
+ } from '../data/entities'
48
+ import { seedProjectTaskStatuses } from './timesheets-tasks/seedProjectStatuses'
49
+ import { formatTaskReference } from './timesheets-tasks/taskReference'
50
+ import { allocateReportReference, highestReportSequenceNumber } from './timesheets-reports/reportReference'
51
+ import { entryAmount, round2, sumAmounts } from './time-tracking/cost'
52
+ import { DEFAULT_ROUNDING_SETTINGS, roundMinutes } from './time-tracking/rounding'
53
+ import type { ProjectColorKey } from './timesheets-ui/colors'
54
+
55
+ export type StaffTimeTrackingSeedScope = { tenantId: string; organizationId: string }
56
+
57
+ type ProjectSeed = {
58
+ code: string
59
+ name: string
60
+ description: string
61
+ projectType: string
62
+ color: ProjectColorKey
63
+ status: 'active' | 'on_hold' | 'completed'
64
+ hourlyRate: number
65
+ currencyCode: string
66
+ billableByDefault: boolean
67
+ budgetKind: 'none' | 'hours' | 'amount'
68
+ budgetValue: number | null
69
+ costCenter: string
70
+ customerIndex: number
71
+ startedDaysAgo: number
72
+ /** Members by index into the resolved staff list, first one is the lead. */
73
+ memberIndexes: number[]
74
+ memberRoles: string[]
75
+ }
76
+
77
+ type TaskSeed = {
78
+ statusSlug: string
79
+ title: string
80
+ description: string
81
+ assigneeIndex: number | null
82
+ tagSlugs: string[]
83
+ comments?: string[]
84
+ subtasks?: { statusSlug: string; title: string; assigneeIndex: number | null }[]
85
+ }
86
+
87
+ type TagSeed = { slug: string; label: string; color: ProjectColorKey }
88
+
89
+ const DEMO_TAGS: TagSeed[] = [
90
+ { slug: 'client-call', label: 'Client call', color: 'blue' },
91
+ { slug: 'development', label: 'Development', color: 'indigo' },
92
+ { slug: 'bugfix', label: 'Bugfix', color: 'red' },
93
+ { slug: 'research', label: 'Research', color: 'purple' },
94
+ { slug: 'internal', label: 'Internal', color: 'slate' },
95
+ ]
96
+
97
+ /**
98
+ * Budgets are sized against the hours this file generates so the portfolio shows
99
+ * one of each state rather than four identical red bars: Atlas and Nova sit
100
+ * comfortably inside, Apollo runs into the 80% warning, Orbit is over. The exact
101
+ * percentages drift a little with the weekday the seed runs on, which is fine —
102
+ * the states do not.
103
+ */
104
+ const DEMO_PROJECTS: ProjectSeed[] = [
105
+ {
106
+ code: 'APOLLO',
107
+ name: 'Apollo — Website Redesign',
108
+ description:
109
+ 'Full redesign of the public site and booking flow, delivered in three milestones with a fixed launch date.',
110
+ projectType: 'Fixed scope',
111
+ color: 'blue',
112
+ status: 'active',
113
+ hourlyRate: 150,
114
+ currencyCode: 'USD',
115
+ billableByDefault: true,
116
+ budgetKind: 'hours',
117
+ budgetValue: 720,
118
+ costCenter: 'CC-100',
119
+ customerIndex: 0,
120
+ startedDaysAgo: 84,
121
+ memberIndexes: [0, 1, 3],
122
+ memberRoles: ['Project manager', 'Frontend engineer', 'UX designer'],
123
+ },
124
+ {
125
+ code: 'ATLAS',
126
+ name: 'Atlas — Data Platform Integration',
127
+ description:
128
+ 'Ingest pipeline, warehouse modelling and a reporting API against the customer analytics platform.',
129
+ projectType: 'Time & materials',
130
+ color: 'emerald',
131
+ status: 'active',
132
+ hourlyRate: 175,
133
+ currencyCode: 'USD',
134
+ billableByDefault: true,
135
+ budgetKind: 'amount',
136
+ budgetValue: 100000,
137
+ costCenter: 'CC-200',
138
+ customerIndex: 1,
139
+ startedDaysAgo: 63,
140
+ memberIndexes: [0, 4, 2],
141
+ memberRoles: ['Tech lead', 'DevOps engineer', 'Product manager'],
142
+ },
143
+ {
144
+ code: 'ORBIT',
145
+ name: 'Orbit — Support Retainer',
146
+ description:
147
+ 'Monthly retainer covering incident response, small enhancements and a standing weekly check-in call.',
148
+ projectType: 'Retainer',
149
+ color: 'orange',
150
+ status: 'active',
151
+ hourlyRate: 120,
152
+ currencyCode: 'USD',
153
+ billableByDefault: true,
154
+ budgetKind: 'hours',
155
+ budgetValue: 360,
156
+ costCenter: 'CC-300',
157
+ customerIndex: 2,
158
+ startedDaysAgo: 70,
159
+ memberIndexes: [4, 1],
160
+ memberRoles: ['Support lead', 'Frontend engineer'],
161
+ },
162
+ {
163
+ code: 'NOVA',
164
+ name: 'Nova — ERP Migration Discovery',
165
+ description:
166
+ 'Discovery phase for the ERP migration. Paused while the customer finalises the vendor short-list.',
167
+ projectType: 'Discovery',
168
+ color: 'purple',
169
+ status: 'on_hold',
170
+ hourlyRate: 165,
171
+ currencyCode: 'USD',
172
+ billableByDefault: true,
173
+ budgetKind: 'hours',
174
+ budgetValue: 240,
175
+ costCenter: 'CC-400',
176
+ customerIndex: 0,
177
+ startedDaysAgo: 49,
178
+ memberIndexes: [2, 0],
179
+ memberRoles: ['Product manager', 'Solution architect'],
180
+ },
181
+ ]
182
+
183
+ const DEMO_TASKS: Record<string, TaskSeed[]> = {
184
+ APOLLO: [
185
+ {
186
+ statusSlug: 'done',
187
+ title: 'Discovery workshop with the client',
188
+ description: 'Two half-day sessions covering the current booking funnel and the drop-off points.',
189
+ assigneeIndex: 0,
190
+ tagSlugs: ['client-call', 'research'],
191
+ comments: ['Recording and notes shared with the client the same afternoon.'],
192
+ },
193
+ {
194
+ statusSlug: 'done',
195
+ title: 'Information architecture and sitemap',
196
+ description: 'Consolidate 40 pages into 18 and agree the new navigation.',
197
+ assigneeIndex: 3,
198
+ tagSlugs: ['research'],
199
+ },
200
+ {
201
+ statusSlug: 'in-review',
202
+ title: 'Design system and component library',
203
+ description: 'Tokens, typography scale and the twelve components the new pages are built from.',
204
+ assigneeIndex: 3,
205
+ tagSlugs: ['development'],
206
+ comments: ['Waiting on brand sign-off for the secondary palette.'],
207
+ subtasks: [
208
+ { statusSlug: 'done', title: 'Colour and typography tokens', assigneeIndex: 3 },
209
+ { statusSlug: 'in-review', title: 'Form and input components', assigneeIndex: 1 },
210
+ ],
211
+ },
212
+ {
213
+ statusSlug: 'in-progress',
214
+ title: 'Booking flow rebuild',
215
+ description: 'Rebuild the four-step booking flow on the new component library.',
216
+ assigneeIndex: 1,
217
+ tagSlugs: ['development'],
218
+ subtasks: [
219
+ { statusSlug: 'done', title: 'Step 1 — date and party size', assigneeIndex: 1 },
220
+ { statusSlug: 'in-progress', title: 'Step 2 — table selection', assigneeIndex: 1 },
221
+ { statusSlug: 'backlog', title: 'Step 3 — guest details', assigneeIndex: null },
222
+ ],
223
+ },
224
+ {
225
+ statusSlug: 'in-progress',
226
+ title: 'Fix layout shift on the gallery page',
227
+ description: 'Images without intrinsic dimensions push the footer around on first paint.',
228
+ assigneeIndex: 1,
229
+ tagSlugs: ['bugfix'],
230
+ },
231
+ {
232
+ statusSlug: 'backlog',
233
+ title: 'Analytics and conversion tracking',
234
+ description: 'Event map for the new funnel plus the dashboard the client reviews weekly.',
235
+ assigneeIndex: 0,
236
+ tagSlugs: ['development'],
237
+ },
238
+ {
239
+ statusSlug: 'backlog',
240
+ title: 'Content migration',
241
+ description: 'Move and re-edit the existing copy into the new page templates.',
242
+ assigneeIndex: null,
243
+ tagSlugs: [],
244
+ },
245
+ ],
246
+ ATLAS: [
247
+ {
248
+ statusSlug: 'done',
249
+ title: 'Source system audit',
250
+ description: 'Catalogue the six source systems, their volumes and their refresh windows.',
251
+ assigneeIndex: 0,
252
+ tagSlugs: ['research'],
253
+ },
254
+ {
255
+ statusSlug: 'in-progress',
256
+ title: 'Ingest pipeline',
257
+ description: 'Incremental loads with replay, running on the customer scheduler.',
258
+ assigneeIndex: 4,
259
+ tagSlugs: ['development'],
260
+ comments: [
261
+ 'Replay from an arbitrary watermark works; still tuning the batch size for the largest table.',
262
+ ],
263
+ subtasks: [
264
+ { statusSlug: 'done', title: 'Connector framework', assigneeIndex: 4 },
265
+ { statusSlug: 'in-progress', title: 'Incremental watermarks', assigneeIndex: 4 },
266
+ ],
267
+ },
268
+ {
269
+ statusSlug: 'in-progress',
270
+ title: 'Warehouse dimensional model',
271
+ description: 'Star schema for orders, customers and merchandising decisions.',
272
+ assigneeIndex: 0,
273
+ tagSlugs: ['development'],
274
+ },
275
+ {
276
+ statusSlug: 'in-review',
277
+ title: 'Reporting API contract',
278
+ description: 'The endpoints the customer BI layer reads, versioned and documented.',
279
+ assigneeIndex: 2,
280
+ tagSlugs: ['client-call'],
281
+ },
282
+ {
283
+ statusSlug: 'backlog',
284
+ title: 'Data quality monitors',
285
+ description: 'Freshness, row-count and null-rate checks with alerting into the customer channel.',
286
+ assigneeIndex: 4,
287
+ tagSlugs: ['development'],
288
+ },
289
+ {
290
+ statusSlug: 'backlog',
291
+ title: 'Handover documentation',
292
+ description: 'Runbook, architecture note and the on-call escalation path.',
293
+ assigneeIndex: null,
294
+ tagSlugs: ['internal'],
295
+ },
296
+ ],
297
+ ORBIT: [
298
+ {
299
+ statusSlug: 'done',
300
+ title: 'March incident — checkout timeouts',
301
+ description: 'Connection pool exhaustion under the promotion traffic spike.',
302
+ assigneeIndex: 4,
303
+ tagSlugs: ['bugfix'],
304
+ comments: ['Root cause and the pool sizing change written up for the customer.'],
305
+ },
306
+ {
307
+ statusSlug: 'in-progress',
308
+ title: 'Monthly dependency and security updates',
309
+ description: 'Patch level, CVE review and a staged rollout.',
310
+ assigneeIndex: 4,
311
+ tagSlugs: ['internal'],
312
+ },
313
+ {
314
+ statusSlug: 'in-progress',
315
+ title: 'Weekly check-in call',
316
+ description: 'Standing Thursday call — backlog triage and the week ahead.',
317
+ assigneeIndex: 1,
318
+ tagSlugs: ['client-call'],
319
+ },
320
+ {
321
+ statusSlug: 'backlog',
322
+ title: 'Search relevance tuning',
323
+ description: 'Synonyms and boosting for the ten highest-volume queries.',
324
+ assigneeIndex: 1,
325
+ tagSlugs: ['development'],
326
+ },
327
+ ],
328
+ NOVA: [
329
+ {
330
+ statusSlug: 'done',
331
+ title: 'Stakeholder interviews',
332
+ description: 'Nine interviews across finance, warehouse and customer service.',
333
+ assigneeIndex: 2,
334
+ tagSlugs: ['client-call', 'research'],
335
+ },
336
+ {
337
+ statusSlug: 'in-review',
338
+ title: 'Process gap analysis',
339
+ description: 'Where the current ERP is worked around, and what that costs per month.',
340
+ assigneeIndex: 2,
341
+ tagSlugs: ['research'],
342
+ comments: ['Draft with the client; feedback expected once the vendor short-list closes.'],
343
+ },
344
+ {
345
+ statusSlug: 'backlog',
346
+ title: 'Migration options and estimates',
347
+ description: 'Three options with cost, risk and a rough delivery window each.',
348
+ assigneeIndex: 0,
349
+ tagSlugs: [],
350
+ },
351
+ ],
352
+ }
353
+
354
+ const ENTRY_NOTES = [
355
+ 'Pairing session on the open items',
356
+ 'Implementation and self-review',
357
+ 'Client call and follow-up notes',
358
+ 'Code review and feedback round',
359
+ 'Debugging the reported regression',
360
+ 'Refinement and estimates for the next sprint',
361
+ 'Documentation and handover notes',
362
+ 'Environment and deployment work',
363
+ 'Design review with the team',
364
+ 'Investigating the reported edge case',
365
+ ]
366
+
367
+ const NONBILLABLE_NOTES = [
368
+ 'Internal team sync',
369
+ 'Knowledge sharing session',
370
+ 'Onboarding a new team member',
371
+ ]
372
+
373
+ /** Names used by `seedStaffTeamExamples`, in the order the demo projects expect them. */
374
+ const PREFERRED_MEMBER_NAMES = [
375
+ 'Alex Chen',
376
+ 'Priya Nair',
377
+ 'Marta Lopez',
378
+ 'Samir Haddad',
379
+ 'Jordan Kim',
380
+ ]
381
+
382
+ const WEEKS_OF_HISTORY = 10
383
+
384
+ /**
385
+ * Deterministic LCG. The demo has to produce the same hours on every machine —
386
+ * a screenshot of the portfolio should still be true after somebody re-seeds.
387
+ */
388
+ function createRandom(seed: number): () => number {
389
+ let state = seed >>> 0
390
+ return () => {
391
+ state = (Math.imul(state, 1664525) + 1013904223) >>> 0
392
+ return state / 0x1_0000_0000
393
+ }
394
+ }
395
+
396
+ function pick<T>(random: () => number, values: readonly T[]): T {
397
+ return values[Math.floor(random() * values.length) % values.length]
398
+ }
399
+
400
+ function startOfUtcDay(date: Date): Date {
401
+ return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()))
402
+ }
403
+
404
+ function addDays(date: Date, days: number): Date {
405
+ const next = new Date(date.getTime())
406
+ next.setUTCDate(next.getUTCDate() + days)
407
+ return next
408
+ }
409
+
410
+ function isWeekend(date: Date): boolean {
411
+ const day = date.getUTCDay()
412
+ return day === 0 || day === 6
413
+ }
414
+
415
+ function atMinutes(date: Date, minutesFromMidnight: number): Date {
416
+ return new Date(date.getTime() + minutesFromMidnight * 60_000)
417
+ }
418
+
419
+ type ResolvedCustomer = { id: string | null; name: string }
420
+
421
+ /**
422
+ * Customers are read softly. The projects are worth having even in a tenant that
423
+ * never seeded the CRM examples, so a missing customer degrades to a snapshot
424
+ * name with no id rather than skipping the project — the portfolio still renders,
425
+ * and only the edit form asks for a customer to be picked.
426
+ */
427
+ async function resolveCustomers(
428
+ em: EntityManager,
429
+ scope: StaffTimeTrackingSeedScope,
430
+ ): Promise<ResolvedCustomer[]> {
431
+ const fallback: ResolvedCustomer[] = [
432
+ { id: null, name: 'Copperleaf Design Co.' },
433
+ { id: null, name: 'Harborview Analytics' },
434
+ { id: null, name: 'Northwind Retail Group' },
435
+ ]
436
+ try {
437
+ const entities = await findWithDecryption(
438
+ em,
439
+ CustomerEntity,
440
+ { tenantId: scope.tenantId, organizationId: scope.organizationId, kind: 'company', deletedAt: null },
441
+ { limit: 25 },
442
+ scope,
443
+ )
444
+ const named = entities
445
+ .map((entity) => ({ id: entity.id, name: (entity.displayName ?? '').trim() }))
446
+ .filter((entity) => entity.name.length > 0)
447
+ .sort((left, right) => left.name.localeCompare(right.name))
448
+ if (named.length === 0) return fallback
449
+ return fallback.map((entry, index) => named[index % named.length] ?? entry)
450
+ } catch {
451
+ return fallback
452
+ }
453
+ }
454
+
455
+ async function resolveMembers(
456
+ em: EntityManager,
457
+ scope: StaffTimeTrackingSeedScope,
458
+ ): Promise<StaffTeamMember[]> {
459
+ const members = await findWithDecryption(
460
+ em,
461
+ StaffTeamMember,
462
+ { tenantId: scope.tenantId, organizationId: scope.organizationId, isActive: true, deletedAt: null },
463
+ { limit: 50 },
464
+ scope,
465
+ )
466
+ if (members.length === 0) return []
467
+ const byName = new Map(members.map((member) => [(member.displayName ?? '').trim(), member]))
468
+ const preferred = PREFERRED_MEMBER_NAMES.map((name) => byName.get(name)).filter(
469
+ (member): member is StaffTeamMember => Boolean(member),
470
+ )
471
+ const remaining = members.filter((member) => !preferred.includes(member))
472
+ const ordered = [...preferred, ...remaining]
473
+ // Every project seed indexes up to five members; a smaller team wraps around so
474
+ // a two-person tenant still gets every project staffed.
475
+ return ordered
476
+ }
477
+
478
+ function memberAt(members: StaffTeamMember[], index: number): StaffTeamMember {
479
+ return members[index % members.length]
480
+ }
481
+
482
+ export async function seedStaffTimeTrackingExamples(
483
+ em: EntityManager,
484
+ scope: StaffTimeTrackingSeedScope,
485
+ ): Promise<boolean> {
486
+ const codes = DEMO_PROJECTS.map((project) => project.code)
487
+ const existing = await em.find(StaffTimeProject, {
488
+ tenantId: scope.tenantId,
489
+ organizationId: scope.organizationId,
490
+ code: { $in: codes },
491
+ deletedAt: null,
492
+ })
493
+ if (existing.length > 0) return false
494
+
495
+ const members = await resolveMembers(em, scope)
496
+ if (members.length === 0) return false
497
+
498
+ const customers = await resolveCustomers(em, scope)
499
+ const users = await findWithDecryption(
500
+ em,
501
+ User,
502
+ { tenantId: scope.tenantId, organizationId: scope.organizationId, deletedAt: null },
503
+ { limit: 10 },
504
+ scope,
505
+ )
506
+ const actorUserId = [...users]
507
+ .sort((left, right) => (left.email ?? '').localeCompare(right.email ?? ''))[0]?.id ?? null
508
+
509
+ const random = createRandom(20260812)
510
+ const now = new Date()
511
+ const today = startOfUtcDay(now)
512
+
513
+ const tagBySlug = new Map<string, StaffTimeTag>()
514
+ for (const seed of DEMO_TAGS) {
515
+ const tag = em.create(StaffTimeTag, {
516
+ tenantId: scope.tenantId,
517
+ organizationId: scope.organizationId,
518
+ slug: seed.slug,
519
+ label: seed.label,
520
+ color: seed.color,
521
+ createdAt: now,
522
+ updatedAt: now,
523
+ deletedAt: null,
524
+ })
525
+ em.persist(tag)
526
+ tagBySlug.set(seed.slug, tag)
527
+ }
528
+ await em.flush()
529
+
530
+ type ProjectContext = {
531
+ seed: ProjectSeed
532
+ project: StaffTimeProject
533
+ statusBySlug: Map<string, StaffTimeTaskStatus>
534
+ tasks: StaffTimeTask[]
535
+ /** Tasks that can carry time, keyed by the staff member they are assigned to. */
536
+ tasksByMemberId: Map<string, StaffTimeTask[]>
537
+ memberIds: string[]
538
+ }
539
+
540
+ const contexts: ProjectContext[] = []
541
+
542
+ for (const seed of DEMO_PROJECTS) {
543
+ const customer = customers[seed.customerIndex] ?? customers[0]
544
+ const startDate = addDays(today, -seed.startedDaysAgo)
545
+ const project = em.create(StaffTimeProject, {
546
+ tenantId: scope.tenantId,
547
+ organizationId: scope.organizationId,
548
+ name: seed.name,
549
+ code: seed.code,
550
+ description: seed.description,
551
+ projectType: seed.projectType,
552
+ color: seed.color,
553
+ status: seed.status,
554
+ customerId: customer.id,
555
+ customerSnapshot: { name: customer.name, kind: 'company' },
556
+ ownerUserId: actorUserId,
557
+ costCenter: seed.costCenter,
558
+ startDate,
559
+ hourlyRate: seed.hourlyRate.toFixed(4),
560
+ currencyCode: seed.currencyCode,
561
+ billableByDefault: seed.billableByDefault,
562
+ budgetKind: seed.budgetKind,
563
+ budgetValue: seed.budgetValue === null ? null : seed.budgetValue.toFixed(4),
564
+ budgetWarnAtPercent: 80,
565
+ budgetAlertedAtPercent: null,
566
+ createdAt: startDate,
567
+ updatedAt: now,
568
+ deletedAt: null,
569
+ })
570
+ em.persist(project)
571
+ await em.flush()
572
+
573
+ const statuses = seedProjectTaskStatuses(
574
+ em,
575
+ { tenantId: scope.tenantId, organizationId: scope.organizationId, timeProjectId: project.id },
576
+ (_key, fallback) => fallback,
577
+ )
578
+ await em.flush()
579
+ const statusBySlug = new Map(statuses.map((status) => [status.slug, status]))
580
+
581
+ const memberIds: string[] = []
582
+ seed.memberIndexes.forEach((memberIndex, position) => {
583
+ const member = memberAt(members, memberIndex)
584
+ if (memberIds.includes(member.id)) return
585
+ memberIds.push(member.id)
586
+ em.persist(
587
+ em.create(StaffTimeProjectMember, {
588
+ tenantId: scope.tenantId,
589
+ organizationId: scope.organizationId,
590
+ timeProjectId: project.id,
591
+ staffMemberId: member.id,
592
+ role: seed.memberRoles[position] ?? 'Consultant',
593
+ status: 'active',
594
+ // The lead and the first collaborator are pinned into the weekly grid so
595
+ // the grid has rows the moment it opens.
596
+ showInGrid: position < 2,
597
+ assignedStartDate: startDate,
598
+ assignedEndDate: null,
599
+ createdAt: startDate,
600
+ updatedAt: now,
601
+ deletedAt: null,
602
+ }),
603
+ )
604
+ })
605
+ await em.flush()
606
+
607
+ const taskSeeds = DEMO_TASKS[seed.code] ?? []
608
+ const tasks: StaffTimeTask[] = []
609
+ const tasksByMemberId = new Map<string, StaffTimeTask[]>()
610
+ let sequenceNumber = 0
611
+
612
+ const registerTask = (task: StaffTimeTask, assigneeId: string | null) => {
613
+ tasks.push(task)
614
+ if (!assigneeId) return
615
+ const bucket = tasksByMemberId.get(assigneeId) ?? []
616
+ bucket.push(task)
617
+ tasksByMemberId.set(assigneeId, bucket)
618
+ }
619
+
620
+ for (const taskSeed of taskSeeds) {
621
+ const status = statusBySlug.get(taskSeed.statusSlug) ?? statuses[0]
622
+ const assignee =
623
+ taskSeed.assigneeIndex === null ? null : memberAt(members, seed.memberIndexes[taskSeed.assigneeIndex] ?? taskSeed.assigneeIndex)
624
+ sequenceNumber += 1
625
+ const createdAt = addDays(startDate, Math.floor(random() * 10))
626
+ const parent = em.create(StaffTimeTask, {
627
+ tenantId: scope.tenantId,
628
+ organizationId: scope.organizationId,
629
+ timeProjectId: project.id,
630
+ parentTaskId: null,
631
+ taskStatusId: status.id,
632
+ sequenceNumber,
633
+ reference: formatTaskReference(seed.code, sequenceNumber),
634
+ title: taskSeed.title,
635
+ description: taskSeed.description,
636
+ assigneeStaffMemberId: assignee?.id ?? null,
637
+ position: sequenceNumber * 1000,
638
+ createdByUserId: actorUserId,
639
+ closedAt: status.isDone ? addDays(today, -Math.floor(random() * 20) - 1) : null,
640
+ createdAt,
641
+ updatedAt: now,
642
+ deletedAt: null,
643
+ })
644
+ em.persist(parent)
645
+ await em.flush()
646
+ registerTask(parent, assignee?.id ?? null)
647
+
648
+ for (const slug of taskSeed.tagSlugs) {
649
+ const tag = tagBySlug.get(slug)
650
+ if (!tag) continue
651
+ em.persist(
652
+ em.create(StaffTimeTaskTag, {
653
+ tenantId: scope.tenantId,
654
+ organizationId: scope.organizationId,
655
+ tagId: tag.id,
656
+ taskId: parent.id,
657
+ createdAt: now,
658
+ }),
659
+ )
660
+ }
661
+
662
+ for (const body of taskSeed.comments ?? []) {
663
+ em.persist(
664
+ em.create(StaffTimeTaskComment, {
665
+ tenantId: scope.tenantId,
666
+ organizationId: scope.organizationId,
667
+ taskId: parent.id,
668
+ body,
669
+ authorUserId: actorUserId,
670
+ createdAt: addDays(createdAt, 2),
671
+ updatedAt: addDays(createdAt, 2),
672
+ deletedAt: null,
673
+ }),
674
+ )
675
+ }
676
+
677
+ for (const subtaskSeed of taskSeed.subtasks ?? []) {
678
+ const subtaskStatus = statusBySlug.get(subtaskSeed.statusSlug) ?? statuses[0]
679
+ const subtaskAssignee =
680
+ subtaskSeed.assigneeIndex === null
681
+ ? null
682
+ : memberAt(members, seed.memberIndexes[subtaskSeed.assigneeIndex] ?? subtaskSeed.assigneeIndex)
683
+ sequenceNumber += 1
684
+ const subtask = em.create(StaffTimeTask, {
685
+ tenantId: scope.tenantId,
686
+ organizationId: scope.organizationId,
687
+ timeProjectId: project.id,
688
+ parentTaskId: parent.id,
689
+ taskStatusId: subtaskStatus.id,
690
+ sequenceNumber,
691
+ reference: formatTaskReference(seed.code, sequenceNumber),
692
+ title: subtaskSeed.title,
693
+ description: null,
694
+ assigneeStaffMemberId: subtaskAssignee?.id ?? null,
695
+ position: sequenceNumber * 1000,
696
+ createdByUserId: actorUserId,
697
+ closedAt: subtaskStatus.isDone ? addDays(today, -Math.floor(random() * 15) - 1) : null,
698
+ createdAt: addDays(createdAt, 1),
699
+ updatedAt: now,
700
+ deletedAt: null,
701
+ })
702
+ em.persist(subtask)
703
+ await em.flush()
704
+ registerTask(subtask, subtaskAssignee?.id ?? null)
705
+ }
706
+ await em.flush()
707
+ }
708
+
709
+ contexts.push({ seed, project, statusBySlug, tasks, tasksByMemberId, memberIds })
710
+ }
711
+
712
+ // --- Logged time -------------------------------------------------------
713
+ //
714
+ // Ten weeks of weekdays. Each member works the projects they are assigned to,
715
+ // chaining entries from 09:00 so a day never overlaps itself — the same
716
+ // invariant the entry command enforces on the write path.
717
+
718
+ // A paused project stopped accruing time when it was paused, but it did accrue
719
+ // some before — a project on hold with no history at all reads as a data bug.
720
+ const pausedAfter = addDays(today, -21)
721
+
722
+ const projectsByMemberId = new Map<string, ProjectContext[]>()
723
+ for (const context of contexts) {
724
+ for (const memberId of context.memberIds) {
725
+ const bucket = projectsByMemberId.get(memberId) ?? []
726
+ bucket.push(context)
727
+ projectsByMemberId.set(memberId, bucket)
728
+ }
729
+ }
730
+
731
+ const entriesByProjectId = new Map<string, StaffTimeEntry[]>()
732
+ const firstDay = addDays(today, -(WEEKS_OF_HISTORY * 7) + 1)
733
+
734
+ for (let offset = 0; offset < WEEKS_OF_HISTORY * 7; offset += 1) {
735
+ const day = addDays(firstDay, offset)
736
+ if (isWeekend(day)) continue
737
+
738
+ for (const [memberId, memberProjects] of projectsByMemberId) {
739
+ // Not everybody logs every day — a demo with a perfect grid reads as fake
740
+ // and hides the "missing time" states the week view is built to show.
741
+ if (random() < 0.12) continue
742
+
743
+ // Only projects that had actually started, and had not been paused, on this
744
+ // day. Filtering up front keeps the day's total intact: picking first and
745
+ // discarding after would quietly turn a full day into a half one.
746
+ const eligible = memberProjects.filter((context) => {
747
+ if (day < startOfUtcDay(context.project.startDate ?? day)) return false
748
+ return !(context.seed.status === 'on_hold' && day > pausedAfter)
749
+ })
750
+ if (eligible.length === 0) continue
751
+
752
+ // A worked day, then split across projects — 6.5 to 9 hours against the
753
+ // 8-hour default target, so the week view shows over, under and on target.
754
+ let remainingMinutes = (13 + Math.floor(random() * 6)) * 30
755
+ const entryCount = random() < 0.5 ? 2 : 3
756
+ let cursorMinutes = 9 * 60 + Math.floor(random() * 4) * 15
757
+
758
+ for (let index = 0; index < entryCount; index += 1) {
759
+ const context = eligible[Math.floor(random() * eligible.length) % eligible.length]
760
+
761
+ const candidates = context.tasksByMemberId.get(memberId) ?? context.tasks
762
+ const task = candidates.length > 0 ? pick(random, candidates) : null
763
+
764
+ const isLast = index === entryCount - 1
765
+ const share = Math.round(remainingMinutes / (entryCount - index) / 30) * 30
766
+ const durationMinutes = Math.max(30, isLast ? remainingMinutes : share)
767
+ remainingMinutes -= durationMinutes
768
+ const isBillable = random() > 0.14
769
+ const startedAt = atMinutes(day, cursorMinutes)
770
+ const endedAt = atMinutes(day, cursorMinutes + durationMinutes)
771
+ // A short break before the next block, so a day reads like a day.
772
+ cursorMinutes += durationMinutes + 15 + Math.floor(random() * 3) * 15
773
+
774
+ const entry = em.create(StaffTimeEntry, {
775
+ tenantId: scope.tenantId,
776
+ organizationId: scope.organizationId,
777
+ staffMemberId: memberId,
778
+ date: day,
779
+ durationMinutes,
780
+ startedAt,
781
+ endedAt,
782
+ notes: isBillable ? pick(random, ENTRY_NOTES) : pick(random, NONBILLABLE_NOTES),
783
+ timeProjectId: context.project.id,
784
+ taskId: task?.id ?? null,
785
+ customerId: context.project.customerId ?? null,
786
+ dealId: null,
787
+ orderId: null,
788
+ isBillable,
789
+ roundedMinutes: roundMinutes(durationMinutes, DEFAULT_ROUNDING_SETTINGS),
790
+ rateOverrideAmount: null,
791
+ rateCurrencyCode: context.project.currencyCode ?? null,
792
+ lockedReportId: null,
793
+ lockedAt: null,
794
+ source: random() < 0.25 ? 'timer' : 'manual',
795
+ createdAt: endedAt,
796
+ updatedAt: endedAt,
797
+ deletedAt: null,
798
+ })
799
+ em.persist(entry)
800
+
801
+ const bucket = entriesByProjectId.get(context.project.id) ?? []
802
+ bucket.push(entry)
803
+ entriesByProjectId.set(context.project.id, bucket)
804
+
805
+ if (random() < 0.35) {
806
+ const tag = pick(random, DEMO_TAGS)
807
+ const tagRow = tagBySlug.get(tag.slug)
808
+ if (tagRow) {
809
+ await em.flush()
810
+ em.persist(
811
+ em.create(StaffTimeEntryTag, {
812
+ tenantId: scope.tenantId,
813
+ organizationId: scope.organizationId,
814
+ tagId: tagRow.id,
815
+ timeEntryId: entry.id,
816
+ createdAt: endedAt,
817
+ }),
818
+ )
819
+ }
820
+ }
821
+ }
822
+ }
823
+ await em.flush()
824
+ }
825
+ await em.flush()
826
+
827
+ await seedDemoReports({ em, scope, contexts, entriesByProjectId, actorUserId, today, now })
828
+
829
+ return true
830
+ }
831
+
832
+ type ReportSeedArgs = {
833
+ em: EntityManager
834
+ scope: StaffTimeTrackingSeedScope
835
+ contexts: {
836
+ seed: ProjectSeed
837
+ project: StaffTimeProject
838
+ }[]
839
+ entriesByProjectId: Map<string, StaffTimeEntry[]>
840
+ actorUserId: string | null
841
+ today: Date
842
+ now: Date
843
+ }
844
+
845
+ /**
846
+ * Two reports: last month closed, this month still a draft.
847
+ *
848
+ * The closed one is written frozen — the same per-entry values
849
+ * `staff.timesheets.reports.close` would have computed — and locks the entries it
850
+ * covers. That is the state worth demoing: a report list with a locked period in
851
+ * it shows why the lock exists, and the entries it froze render read-only in the
852
+ * week grid without anybody having to close a report first.
853
+ */
854
+ async function seedDemoReports(args: ReportSeedArgs): Promise<void> {
855
+ const { em, scope, contexts, entriesByProjectId, actorUserId, today, now } = args
856
+
857
+ const monthStart = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), 1))
858
+ const previousMonthStart = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth() - 1, 1))
859
+ const previousMonthEnd = addDays(monthStart, -1)
860
+
861
+ const existingReferences = await em.find(
862
+ StaffTimeReport,
863
+ { tenantId: scope.tenantId, organizationId: scope.organizationId },
864
+ { fields: ['reference'] },
865
+ )
866
+ const year = today.getUTCFullYear()
867
+ let sequence = highestReportSequenceNumber(
868
+ existingReferences.map((report) => report.reference),
869
+ year,
870
+ )
871
+
872
+ const byCustomer = new Map<string, typeof contexts>()
873
+ for (const context of contexts) {
874
+ const customerId = context.project.customerId
875
+ if (!customerId) continue
876
+ const bucket = byCustomer.get(customerId) ?? []
877
+ bucket.push(context)
878
+ byCustomer.set(customerId, bucket)
879
+ }
880
+ if (byCustomer.size === 0) return
881
+
882
+ const customerGroups = [...byCustomer.entries()]
883
+
884
+ const createReport = async (
885
+ group: (typeof customerGroups)[number],
886
+ options: {
887
+ title: string
888
+ periodFrom: Date
889
+ periodTo: Date
890
+ close: boolean
891
+ },
892
+ ): Promise<void> => {
893
+ const [customerId, groupContexts] = group
894
+ const first = groupContexts[0]
895
+ sequence += 1
896
+ const { reference } = allocateReportReference(year, sequence - 1)
897
+ const currencyCode = first.project.currencyCode ?? 'USD'
898
+
899
+ const report = em.create(StaffTimeReport, {
900
+ tenantId: scope.tenantId,
901
+ organizationId: scope.organizationId,
902
+ customerId,
903
+ customerSnapshot: first.project.customerSnapshot ?? null,
904
+ reference,
905
+ title: options.title,
906
+ periodKind: 'month',
907
+ periodFrom: options.periodFrom,
908
+ periodTo: options.periodTo,
909
+ currencyCode,
910
+ grouping: 'project_task',
911
+ nonbillableMode: 'separate',
912
+ includeAlreadyReported: false,
913
+ showRates: true,
914
+ roundingUnitMinutes: DEFAULT_ROUNDING_SETTINGS.unitMinutes,
915
+ roundingDirection: DEFAULT_ROUNDING_SETTINGS.direction,
916
+ status: 'draft',
917
+ totalBillableMinutes: null,
918
+ totalNonbillableMinutes: null,
919
+ totalAmount: null,
920
+ closedAt: null,
921
+ closedByUserId: null,
922
+ createdByUserId: actorUserId,
923
+ createdAt: options.periodTo,
924
+ updatedAt: now,
925
+ deletedAt: null,
926
+ })
927
+ em.persist(report)
928
+ await em.flush()
929
+
930
+ for (const context of groupContexts) {
931
+ em.persist(
932
+ em.create(StaffTimeReportProject, {
933
+ tenantId: scope.tenantId,
934
+ organizationId: scope.organizationId,
935
+ reportId: report.id,
936
+ timeProjectId: context.project.id,
937
+ createdAt: now,
938
+ }),
939
+ )
940
+ }
941
+ await em.flush()
942
+
943
+ if (!options.close) return
944
+
945
+ const included = groupContexts.flatMap((context) => {
946
+ const rate = Number(context.project.hourlyRate ?? 0)
947
+ return (entriesByProjectId.get(context.project.id) ?? [])
948
+ .filter((entry) => entry.date >= options.periodFrom && entry.date <= options.periodTo)
949
+ .map((entry) => ({ entry, rate }))
950
+ })
951
+ if (included.length === 0) return
952
+
953
+ const closedAt = addDays(options.periodTo, 2)
954
+ const amounts: (number | null)[] = []
955
+ let billableMinutes = 0
956
+ let nonbillableMinutes = 0
957
+
958
+ for (const { entry, rate } of included) {
959
+ const minutes = entry.roundedMinutes ?? entry.durationMinutes
960
+ const amount = entryAmount(
961
+ { isBillable: entry.isBillable, roundedMinutes: minutes, rateOverrideAmount: null },
962
+ { hourlyRate: rate },
963
+ )
964
+ amounts.push(amount)
965
+ if (entry.isBillable) billableMinutes += minutes
966
+ else nonbillableMinutes += minutes
967
+
968
+ em.persist(
969
+ em.create(StaffTimeReportEntry, {
970
+ tenantId: scope.tenantId,
971
+ organizationId: scope.organizationId,
972
+ reportId: report.id,
973
+ timeEntryId: entry.id,
974
+ frozenRawMinutes: entry.durationMinutes,
975
+ frozenRoundedMinutes: minutes,
976
+ frozenRateAmount: entry.isBillable ? String(round2(rate)) : null,
977
+ frozenCurrencyCode: currencyCode,
978
+ frozenAmount: amount === null ? null : amount.toFixed(2),
979
+ frozenIsBillable: entry.isBillable,
980
+ createdAt: closedAt,
981
+ }),
982
+ )
983
+
984
+ entry.lockedReportId = report.id
985
+ entry.lockedAt = closedAt
986
+ entry.updatedAt = closedAt
987
+ }
988
+
989
+ const totalAmount = sumAmounts(amounts)
990
+ report.status = 'closed'
991
+ report.closedAt = closedAt
992
+ report.closedByUserId = actorUserId
993
+ report.totalBillableMinutes = billableMinutes
994
+ report.totalNonbillableMinutes = nonbillableMinutes
995
+ report.totalAmount = totalAmount.toFixed(2)
996
+ report.updatedAt = closedAt
997
+
998
+ em.persist(
999
+ em.create(StaffTimeReportEvent, {
1000
+ tenantId: scope.tenantId,
1001
+ organizationId: scope.organizationId,
1002
+ reportId: report.id,
1003
+ eventType: 'closed',
1004
+ reason: null,
1005
+ actorUserId,
1006
+ metadata: {
1007
+ frozenEntryCount: included.length,
1008
+ lockedEntryCount: included.length,
1009
+ totalAmount,
1010
+ currencyCode,
1011
+ roundingUnitMinutes: DEFAULT_ROUNDING_SETTINGS.unitMinutes,
1012
+ roundingDirection: DEFAULT_ROUNDING_SETTINGS.direction,
1013
+ },
1014
+ createdAt: closedAt,
1015
+ }),
1016
+ )
1017
+ await em.flush()
1018
+ }
1019
+
1020
+ const monthLabel = (date: Date) =>
1021
+ `${date.toLocaleString('en-US', { month: 'long', timeZone: 'UTC' })} ${date.getUTCFullYear()}`
1022
+
1023
+ await createReport(customerGroups[0], {
1024
+ title: `${monthLabel(previousMonthStart)} — time and materials`,
1025
+ periodFrom: previousMonthStart,
1026
+ periodTo: previousMonthEnd,
1027
+ close: true,
1028
+ })
1029
+
1030
+ const draftGroup = customerGroups[1] ?? customerGroups[0]
1031
+ await createReport(draftGroup, {
1032
+ title: `${monthLabel(monthStart)} — work in progress`,
1033
+ periodFrom: monthStart,
1034
+ periodTo: today,
1035
+ close: false,
1036
+ })
1037
+ }