@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,210 @@
1
+ import { NextResponse } from "next/server";
2
+ import { resolveFeatureAccess } from "../../../../../lib/time-tracking/featureAccess.js";
3
+ import { z } from "zod";
4
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
5
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
6
+ import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
7
+ import { CrudHttpError, forbidden, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
8
+ import { runRouteMutationGuards } from "@open-mercato/shared/lib/crud/route-mutation-guard";
9
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
10
+ import { serializeOperationMetadata } from "@open-mercato/shared/lib/commands/operationMetadata";
11
+ import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
12
+ import { createLogger } from "@open-mercato/shared/lib/logger";
13
+ import { StaffTimeTask } from "../../../../../data/entities.js";
14
+ import { staffTimeTaskStatusChangeSchema } from "../../../../../data/validators.js";
15
+ import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
16
+ import { STAFF_TIME_TRACKING_RESOURCE_KINDS } from "../../../../guards.js";
17
+ import { runTimesheetInterceptors } from "../../../_shared/withTimesheetInterceptors.js";
18
+ import {
19
+ staffTimeTaskCommandIds
20
+ } from "../../../../../commands/timesheets-tasks.js";
21
+ import { assertProjectAccess } from "../../../../../lib/time-tracking/access.js";
22
+ import { resolveListProjectAccess } from "../../route.js";
23
+ const logger = createLogger("staff").child({ component: "api/timesheets/tasks/status" });
24
+ const MANAGE_FEATURE = "staff.timesheets.tasks.manage";
25
+ const metadata = {
26
+ PATCH: { requireAuth: true, requireFeatures: [MANAGE_FEATURE] }
27
+ };
28
+ function extractTaskIdFromUrl(request) {
29
+ if (!request?.url) return null;
30
+ try {
31
+ const url = new URL(request.url);
32
+ const match = url.pathname.match(/\/tasks\/([^/]+)\/status/);
33
+ return match?.[1] ?? null;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+ async function resolveTaskId(req, context) {
39
+ const params = context?.params ? await context.params : null;
40
+ const fromParams = params?.id;
41
+ if (typeof fromParams === "string" && fromParams.length > 0) return fromParams;
42
+ return extractTaskIdFromUrl(req);
43
+ }
44
+ async function PATCH(req, context) {
45
+ try {
46
+ const container = await createRequestContainer();
47
+ const auth = await getAuthFromRequest(req);
48
+ const { translate } = await resolveTranslations();
49
+ if (!auth) {
50
+ throw new CrudHttpError(401, { error: translate("staff.errors.unauthorized", "Unauthorized") });
51
+ }
52
+ const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
53
+ const tenantId = scope?.tenantId ?? auth.tenantId ?? null;
54
+ const organizationId = scope?.selectedId ?? auth.orgId ?? null;
55
+ if (!tenantId || !organizationId) {
56
+ throw new CrudHttpError(400, {
57
+ error: translate("staff.errors.missingScope", "Missing tenant or organization scope.")
58
+ });
59
+ }
60
+ const taskId = await resolveTaskId(req, context);
61
+ if (!taskId || !z.string().uuid().safeParse(taskId).success) {
62
+ throw new CrudHttpError(400, {
63
+ error: translate("staff.time_tracking.tasks.errors.idRequired", "Task id is required.")
64
+ });
65
+ }
66
+ const actorId = auth.sub ?? "";
67
+ const manageTasks = await resolveFeatureAccess(container, actorId, [MANAGE_FEATURE], { tenantId, organizationId });
68
+ if (!manageTasks.allowed) {
69
+ throw forbidden(translate("staff.errors.forbidden", "Forbidden"));
70
+ }
71
+ const grantedFeatures = manageTasks.grantedFeatures;
72
+ const interceptors = await runTimesheetInterceptors({
73
+ request: req,
74
+ method: "PATCH",
75
+ scope: { container, userId: actorId, tenantId, organizationId, userFeatures: grantedFeatures },
76
+ body: await readJsonSafe(req, {})
77
+ });
78
+ if (!interceptors.ok) return interceptors.response;
79
+ const { session } = interceptors;
80
+ const parsed = staffTimeTaskStatusChangeSchema.parse(session.body);
81
+ const routeCtx = {
82
+ container,
83
+ auth,
84
+ organizationScope: scope,
85
+ selectedOrganizationId: organizationId,
86
+ organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),
87
+ request: req
88
+ };
89
+ const em = container.resolve("em").fork();
90
+ const task = await em.findOne(StaffTimeTask, { id: taskId, tenantId, organizationId, deletedAt: null });
91
+ const access = task ? await resolveListProjectAccess(routeCtx) : null;
92
+ if (!task || !access || !assertProjectAccess(access, task.timeProjectId)) {
93
+ throw new CrudHttpError(404, {
94
+ error: translate("staff.time_tracking.tasks.errors.notFound", "Task not found or not accessible.")
95
+ });
96
+ }
97
+ const guardResult = await runRouteMutationGuards({
98
+ container,
99
+ req,
100
+ auth: {
101
+ userId: actorId,
102
+ tenantId,
103
+ organizationId,
104
+ userFeatures: grantedFeatures
105
+ },
106
+ input: {
107
+ resourceKind: STAFF_TIME_TRACKING_RESOURCE_KINDS.timeTask,
108
+ resourceId: taskId,
109
+ operation: "update",
110
+ mutationPayload: parsed
111
+ }
112
+ });
113
+ if (!guardResult.ok) return guardResult.response;
114
+ const effective = guardResult.modifiedPayload ? staffTimeTaskStatusChangeSchema.parse({ ...parsed, ...guardResult.modifiedPayload }) : parsed;
115
+ const commandBus = container.resolve("commandBus");
116
+ const { result, logEntry } = await commandBus.execute(staffTimeTaskCommandIds.statusChange, {
117
+ input: { ...effective, id: taskId },
118
+ ctx: routeCtx
119
+ });
120
+ await guardResult.runAfterSuccess();
121
+ const response = await session.respond(200, {
122
+ id: result?.taskId ?? taskId,
123
+ timeProjectId: result?.timeProjectId ?? task.timeProjectId,
124
+ previousTaskStatusId: result?.previousTaskStatusId ?? null,
125
+ taskStatusId: result?.taskStatusId ?? effective.taskStatusId,
126
+ position: result?.position ?? null,
127
+ closedAt: result?.closedAt ?? null,
128
+ updatedAt: result?.updatedAt ?? null
129
+ });
130
+ if (logEntry?.undoToken && logEntry?.id && logEntry?.commandId) {
131
+ response.headers.set(
132
+ "x-om-operation",
133
+ serializeOperationMetadata({
134
+ id: logEntry.id,
135
+ undoToken: logEntry.undoToken,
136
+ commandId: logEntry.commandId,
137
+ actionLabel: logEntry.actionLabel ?? null,
138
+ resourceKind: logEntry.resourceKind ?? STAFF_TIME_TRACKING_RESOURCE_KINDS.timeTask,
139
+ resourceId: logEntry.resourceId ?? taskId,
140
+ executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : void 0
141
+ })
142
+ );
143
+ }
144
+ return response;
145
+ } catch (err) {
146
+ if (isCrudHttpError(err)) {
147
+ return NextResponse.json(err.body, { status: err.status });
148
+ }
149
+ const interceptorRejection = getCommandInterceptorHttpRejection(err);
150
+ if (interceptorRejection) {
151
+ return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status });
152
+ }
153
+ const { translate } = await resolveTranslations();
154
+ if (err instanceof z.ZodError) {
155
+ return NextResponse.json(
156
+ { error: translate("staff.errors.invalid_request", "Invalid request"), details: err.issues },
157
+ { status: 400 }
158
+ );
159
+ }
160
+ logger.error("staff.timesheets.tasks.status PATCH failed", { err });
161
+ return NextResponse.json(
162
+ { error: translate("staff.errors.internal", "Internal server error") },
163
+ { status: 500 }
164
+ );
165
+ }
166
+ }
167
+ const statusChangeResponseSchema = z.object({
168
+ id: z.string().uuid(),
169
+ timeProjectId: z.string().uuid(),
170
+ previousTaskStatusId: z.string().uuid().nullable(),
171
+ taskStatusId: z.string().uuid(),
172
+ position: z.number().int().nullable(),
173
+ closedAt: z.string().nullable(),
174
+ updatedAt: z.string().nullable()
175
+ });
176
+ const conflictSchema = z.object({
177
+ code: z.literal("optimistic_lock_conflict"),
178
+ error: z.string(),
179
+ currentUpdatedAt: z.string(),
180
+ expectedUpdatedAt: z.string()
181
+ });
182
+ const openApi = {
183
+ tag: "Staff",
184
+ summary: "Move a task to another board column",
185
+ methods: {
186
+ PATCH: {
187
+ summary: "Move a task to another board column",
188
+ description: "Moves a task to the requested status column and slot. `position` is optional \u2014 omitting it appends the task to the end of the target column, which is what the drawer subtask tick does. The target status must belong to the task project (422 otherwise). Landing on a done column stamps `closedAt`, leaving one clears it. Send the record version in `x-om-ext-optimistic-lock-expected-updated-at`: a stale version answers 409 so an optimistic board can roll the card back to its origin column. Emits `staff.timesheets.time_task.status_changed`, which is bridged to connected boards.",
189
+ requestBody: {
190
+ contentType: "application/json",
191
+ schema: staffTimeTaskStatusChangeSchema
192
+ },
193
+ responses: [{ status: 200, description: "Task moved", schema: statusChangeResponseSchema }],
194
+ errors: [
195
+ { status: 400, description: "Invalid task id or body" },
196
+ { status: 401, description: "Unauthorized" },
197
+ { status: 403, description: "Missing staff.timesheets.tasks.manage" },
198
+ { status: 404, description: "Task not found, or not on a project the caller can see" },
199
+ { status: 409, description: "The task changed since the version the caller sent", schema: conflictSchema },
200
+ { status: 422, description: "The target column does not belong to this project" }
201
+ ]
202
+ }
203
+ }
204
+ };
205
+ export {
206
+ PATCH,
207
+ metadata,
208
+ openApi
209
+ };
210
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../src/modules/staff/api/timesheets/tasks/%5Bid%5D/status/route.ts"],
4
+ "sourcesContent": ["/**\n * The Kanban drag of screen 6 (US-C2), and the drawer's subtask tick, which is the\n * same move without a meaningful position.\n *\n * The board writes optimistically \u2014 the card lands in the new column before the\n * request completes \u2014 so this endpoint's contract is what makes the rollback in the\n * mockup's note 2 correct:\n *\n * 1. **The `updated_at` version travels with the drag.** Two people moving the same\n * card is the one genuinely likely conflict on this board, so a stale\n * `x-om-ext-optimistic-lock-expected-updated-at` answers 409 and the client puts\n * the card back where it came from instead of overwriting the other move.\n * 2. **Project access is intersected before anything else is revealed.** The access\n * decision reuses the tasks list route's memoised resolver, and a caller who is\n * not a member gets the same 404 a missing task gets \u2014 the body never confirms\n * the task exists.\n * 3. **The target column must belong to the task's own project.** A foreign column\n * is refused by the command (422) rather than quietly accepted, because a task\n * lives in exactly one project (\u00A72) and its board is that project's.\n *\n * The write itself is the `staff.timesheets.tasks.status_change` command, which owns\n * the `closed_at` stamping and emits `staff.timesheets.time_task.status_changed`.\n */\n\nimport { NextResponse } from 'next/server'\nimport { resolveFeatureAccess } from '../../../../../lib/time-tracking/featureAccess'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { CrudHttpError, forbidden, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { runRouteMutationGuards } from '@open-mercato/shared/lib/crud/route-mutation-guard'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { StaffTimeTask } from '../../../../../data/entities'\nimport { staffTimeTaskStatusChangeSchema } from '../../../../../data/validators'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { STAFF_TIME_TRACKING_RESOURCE_KINDS } from '../../../../guards'\nimport { runTimesheetInterceptors } from '../../../_shared/withTimesheetInterceptors'\nimport {\n staffTimeTaskCommandIds,\n type StaffTimeTaskStatusChangeCommandInput,\n type StaffTimeTaskStatusChangeResult,\n} from '../../../../../commands/timesheets-tasks'\nimport { assertProjectAccess } from '../../../../../lib/time-tracking/access'\nimport { resolveListProjectAccess } from '../../route'\n\nconst logger = createLogger('staff').child({ component: 'api/timesheets/tasks/status' })\n\nconst MANAGE_FEATURE = 'staff.timesheets.tasks.manage'\n\nexport const metadata = {\n PATCH: { requireAuth: true, requireFeatures: [MANAGE_FEATURE] },\n}\n\ntype RouteContext = {\n params?: Promise<Record<string, string | string[]>> | Record<string, string | string[]>\n}\n\nfunction extractTaskIdFromUrl(request?: Request): string | null {\n if (!request?.url) return null\n try {\n const url = new URL(request.url)\n const match = url.pathname.match(/\\/tasks\\/([^/]+)\\/status/)\n return match?.[1] ?? null\n } catch {\n return null\n }\n}\n\nasync function resolveTaskId(req: Request, context?: RouteContext): Promise<string | null> {\n const params = context?.params ? await context.params : null\n const fromParams = params?.id\n if (typeof fromParams === 'string' && fromParams.length > 0) return fromParams\n return extractTaskIdFromUrl(req)\n}\n\nexport async function PATCH(req: Request, context?: RouteContext): Promise<Response> {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth) {\n throw new CrudHttpError(401, { error: translate('staff.errors.unauthorized', 'Unauthorized') })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const tenantId = scope?.tenantId ?? auth.tenantId ?? null\n const organizationId = scope?.selectedId ?? auth.orgId ?? null\n if (!tenantId || !organizationId) {\n throw new CrudHttpError(400, {\n error: translate('staff.errors.missingScope', 'Missing tenant or organization scope.'),\n })\n }\n\n const taskId = await resolveTaskId(req, context)\n if (!taskId || !z.string().uuid().safeParse(taskId).success) {\n throw new CrudHttpError(400, {\n error: translate('staff.time_tracking.tasks.errors.idRequired', 'Task id is required.'),\n })\n }\n\n const actorId = auth.sub ?? ''\n // One lookup through the module's single RBAC authority, answering both\n // questions this route asks: may the caller manage tasks, and what grant list\n // do the interceptors and the mutation-guard registry gate on. The decision is\n // checked unconditionally and fails closed; the list is plumbing and is empty \u2014\n // never absent \u2014 when RBAC could not produce it.\n const manageTasks = await resolveFeatureAccess(container, actorId, [MANAGE_FEATURE], { tenantId, organizationId })\n if (!manageTasks.allowed) {\n throw forbidden(translate('staff.errors.forbidden', 'Forbidden'))\n }\n const grantedFeatures = manageTasks.grantedFeatures\n\n const interceptors = await runTimesheetInterceptors({\n request: req,\n method: 'PATCH',\n scope: { container, userId: actorId, tenantId, organizationId, userFeatures: grantedFeatures },\n body: await readJsonSafe<Record<string, unknown>>(req, {}),\n })\n if (!interceptors.ok) return interceptors.response\n const { session } = interceptors\n\n const parsed = staffTimeTaskStatusChangeSchema.parse(session.body)\n\n const routeCtx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n // Membership is resolved against the task's project, so the lookup has to happen\n // here. Both \"no such task\" and \"not your project\" answer with the same body.\n const em = (container.resolve('em') as EntityManager).fork()\n const task = await em.findOne(StaffTimeTask, { id: taskId, tenantId, organizationId, deletedAt: null })\n const access = task ? await resolveListProjectAccess(routeCtx) : null\n if (!task || !access || !assertProjectAccess(access, task.timeProjectId)) {\n throw new CrudHttpError(404, {\n error: translate('staff.time_tracking.tasks.errors.notFound', 'Task not found or not accessible.'),\n })\n }\n\n const guardResult = await runRouteMutationGuards({\n container,\n req,\n auth: {\n userId: actorId,\n tenantId,\n organizationId,\n userFeatures: grantedFeatures,\n },\n input: {\n resourceKind: STAFF_TIME_TRACKING_RESOURCE_KINDS.timeTask,\n resourceId: taskId,\n operation: 'update',\n mutationPayload: parsed,\n },\n })\n if (!guardResult.ok) return guardResult.response\n\n const effective = guardResult.modifiedPayload\n ? staffTimeTaskStatusChangeSchema.parse({ ...parsed, ...guardResult.modifiedPayload })\n : parsed\n\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute<\n StaffTimeTaskStatusChangeCommandInput,\n StaffTimeTaskStatusChangeResult\n >(staffTimeTaskCommandIds.statusChange, {\n input: { ...effective, id: taskId },\n ctx: routeCtx,\n })\n\n await guardResult.runAfterSuccess()\n\n const response = await session.respond(200, {\n id: result?.taskId ?? taskId,\n timeProjectId: result?.timeProjectId ?? task.timeProjectId,\n previousTaskStatusId: result?.previousTaskStatusId ?? null,\n taskStatusId: result?.taskStatusId ?? effective.taskStatusId,\n position: result?.position ?? null,\n closedAt: result?.closedAt ?? null,\n updatedAt: result?.updatedAt ?? null,\n })\n if (logEntry?.undoToken && logEntry?.id && logEntry?.commandId) {\n response.headers.set(\n 'x-om-operation',\n serializeOperationMetadata({\n id: logEntry.id,\n undoToken: logEntry.undoToken,\n commandId: logEntry.commandId,\n actionLabel: logEntry.actionLabel ?? null,\n resourceKind: logEntry.resourceKind ?? STAFF_TIME_TRACKING_RESOURCE_KINDS.timeTask,\n resourceId: logEntry.resourceId ?? taskId,\n executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : undefined,\n }),\n )\n }\n return response\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const interceptorRejection = getCommandInterceptorHttpRejection(err)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n const { translate } = await resolveTranslations()\n if (err instanceof z.ZodError) {\n return NextResponse.json(\n { error: translate('staff.errors.invalid_request', 'Invalid request'), details: err.issues },\n { status: 400 },\n )\n }\n logger.error('staff.timesheets.tasks.status PATCH failed', { err })\n return NextResponse.json(\n { error: translate('staff.errors.internal', 'Internal server error') },\n { status: 500 },\n )\n }\n}\n\nconst statusChangeResponseSchema = z.object({\n id: z.string().uuid(),\n timeProjectId: z.string().uuid(),\n previousTaskStatusId: z.string().uuid().nullable(),\n taskStatusId: z.string().uuid(),\n position: z.number().int().nullable(),\n closedAt: z.string().nullable(),\n updatedAt: z.string().nullable(),\n})\n\nconst conflictSchema = z.object({\n code: z.literal('optimistic_lock_conflict'),\n error: z.string(),\n currentUpdatedAt: z.string(),\n expectedUpdatedAt: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Staff',\n summary: 'Move a task to another board column',\n methods: {\n PATCH: {\n summary: 'Move a task to another board column',\n description:\n 'Moves a task to the requested status column and slot. `position` is optional \u2014 omitting it appends the task to the end of the target column, which is what the drawer subtask tick does. The target status must belong to the task project (422 otherwise). Landing on a done column stamps `closedAt`, leaving one clears it. Send the record version in `x-om-ext-optimistic-lock-expected-updated-at`: a stale version answers 409 so an optimistic board can roll the card back to its origin column. Emits `staff.timesheets.time_task.status_changed`, which is bridged to connected boards.',\n requestBody: {\n contentType: 'application/json',\n schema: staffTimeTaskStatusChangeSchema,\n },\n responses: [{ status: 200, description: 'Task moved', schema: statusChangeResponseSchema }],\n errors: [\n { status: 400, description: 'Invalid task id or body' },\n { status: 401, description: 'Unauthorized' },\n { status: 403, description: 'Missing staff.timesheets.tasks.manage' },\n { status: 404, description: 'Task not found, or not on a project the caller can see' },\n { status: 409, description: 'The task changed since the version the caller sent', schema: conflictSchema },\n { status: 422, description: 'The target column does not belong to this project' },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,333 @@
1
+ import { z } from "zod";
2
+ import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
3
+ import { staffTimeTaskCrudEvents } from "../../../lib/crud.js";
4
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
5
+ import { resolveCrudRecordId, parseScopedCommandInput } from "@open-mercato/shared/lib/api/scoped";
6
+ import { escapeLikePattern } from "@open-mercato/shared/lib/db/escapeLikePattern";
7
+ import { createLogger } from "@open-mercato/shared/lib/logger";
8
+ import { StaffTimeTask, StaffTimeTaskTag } from "../../../data/entities.js";
9
+ import { staffTimeTaskCreateSchema, staffTimeTaskUpdateSchema } from "../../../data/validators.js";
10
+ import { staffTimeTaskCommandIds } from "../../../commands/timesheets-tasks.js";
11
+ import { resolveFeatureAccess } from "../../../lib/time-tracking/featureAccess.js";
12
+ import { MANAGE_PROJECTS_FEATURE, resolveProjectAccess } from "../../../lib/time-tracking/access.js";
13
+ import { readTimeTrackingSettings } from "../../../lib/time-tracking/settings.js";
14
+ import { sanitizeSearchTerm, parseBooleanFlag } from "../../helpers.js";
15
+ import { createStaffCrudOpenApi, createPagedListResponseSchema, defaultOkResponseSchema } from "../../openapi.js";
16
+ const logger = createLogger("staff").child({ component: "api/timesheets/tasks" });
17
+ const F = {
18
+ id: "id",
19
+ tenant_id: "tenant_id",
20
+ organization_id: "organization_id",
21
+ time_project_id: "time_project_id",
22
+ parent_task_id: "parent_task_id",
23
+ task_status_id: "task_status_id",
24
+ sequence_number: "sequence_number",
25
+ reference: "reference",
26
+ title: "title",
27
+ description: "description",
28
+ assignee_staff_member_id: "assignee_staff_member_id",
29
+ position: "position",
30
+ created_by_user_id: "created_by_user_id",
31
+ closed_at: "closed_at",
32
+ created_at: "created_at",
33
+ updated_at: "updated_at"
34
+ };
35
+ const routeMetadata = {
36
+ GET: { requireAuth: true, requireFeatures: ["staff.timesheets.tasks.view"] },
37
+ POST: { requireAuth: true, requireFeatures: ["staff.timesheets.tasks.manage"] },
38
+ PUT: { requireAuth: true, requireFeatures: ["staff.timesheets.tasks.manage"] },
39
+ DELETE: { requireAuth: true, requireFeatures: ["staff.timesheets.tasks.manage"] }
40
+ };
41
+ const metadata = routeMetadata;
42
+ const rawBodySchema = z.object({}).passthrough();
43
+ const listSchema = z.object({
44
+ page: z.coerce.number().min(1).default(1),
45
+ pageSize: z.coerce.number().min(1).max(100).default(50),
46
+ q: z.string().optional(),
47
+ /** Prefix match on the denormalised `<CODE>-<n>` reference. */
48
+ reference: z.string().optional(),
49
+ id: z.string().optional(),
50
+ ids: z.string().optional(),
51
+ timeProjectId: z.string().uuid().optional(),
52
+ taskStatusId: z.string().uuid().optional(),
53
+ assigneeStaffMemberId: z.string().uuid().optional(),
54
+ parentTaskId: z.string().uuid().optional(),
55
+ tagIds: z.string().optional(),
56
+ topLevelOnly: z.string().optional(),
57
+ sortField: z.string().optional(),
58
+ sortDir: z.enum(["asc", "desc"]).optional()
59
+ }).passthrough();
60
+ const IMPOSSIBLE_ID = "00000000-0000-0000-0000-000000000000";
61
+ const DENIED_ACCESS = { canManageAll: false, projectIds: [], staffMemberId: null };
62
+ const accessByRequest = /* @__PURE__ */ new WeakMap();
63
+ async function resolveAssignmentGraceDays(container, tenantId) {
64
+ try {
65
+ const configService = container.resolve("moduleConfigService");
66
+ const settings = await readTimeTrackingSettings(configService, { tenantId });
67
+ return settings.access.assignmentGraceDays;
68
+ } catch {
69
+ return null;
70
+ }
71
+ }
72
+ async function loadProjectAccess(container, userId, tenantId, organizationId) {
73
+ if (!tenantId || !organizationId) return { ...DENIED_ACCESS };
74
+ const scope = { tenantId, organizationId };
75
+ try {
76
+ const access = await resolveFeatureAccess(container, userId, [MANAGE_PROJECTS_FEATURE], scope);
77
+ const em = container.resolve("em");
78
+ return await resolveProjectAccess({
79
+ em: em.fork(),
80
+ userId,
81
+ tenantId,
82
+ organizationId,
83
+ canManageAll: access.allowed,
84
+ userFeatures: access.grantedFeatures,
85
+ assignmentGraceDays: await resolveAssignmentGraceDays(container, tenantId)
86
+ });
87
+ } catch (err) {
88
+ logger.error("staff.timesheets.tasks access resolution failed", { err });
89
+ return { ...DENIED_ACCESS };
90
+ }
91
+ }
92
+ async function resolveListProjectAccess(ctx) {
93
+ const tenantId = ctx.auth?.tenantId ?? null;
94
+ const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
95
+ const load = () => loadProjectAccess(ctx.container, ctx.auth?.sub ?? null, tenantId, organizationId);
96
+ const request = ctx.request;
97
+ if (!request) return load();
98
+ const cached = accessByRequest.get(request);
99
+ if (cached) return cached;
100
+ const pending = load();
101
+ accessByRequest.set(request, pending);
102
+ return pending;
103
+ }
104
+ function splitIdList(value) {
105
+ if (typeof value !== "string" || value.trim().length === 0) return null;
106
+ const ids = value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
107
+ return ids.length > 0 ? ids : [];
108
+ }
109
+ async function resolveTaskIdsForTags(ctx, tagIds) {
110
+ const tenantId = ctx.auth?.tenantId ?? null;
111
+ const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
112
+ if (!tenantId || !organizationId) return [];
113
+ try {
114
+ const em = ctx.container.resolve("em").fork();
115
+ const rows = await em.find(
116
+ StaffTimeTaskTag,
117
+ { tagId: { $in: tagIds }, tenantId, organizationId },
118
+ { fields: ["taskId", "tagId"] }
119
+ );
120
+ const seen = /* @__PURE__ */ new Map();
121
+ for (const row of rows) {
122
+ const taskId = row.taskId;
123
+ if (!taskId) continue;
124
+ const bucket = seen.get(taskId) ?? /* @__PURE__ */ new Set();
125
+ bucket.add(row.tagId);
126
+ seen.set(taskId, bucket);
127
+ }
128
+ const required = new Set(tagIds).size;
129
+ return [...seen.entries()].filter(([, tags]) => tags.size >= required).map(([taskId]) => taskId);
130
+ } catch (err) {
131
+ logger.error("staff.timesheets.tasks tag filter resolution failed", { err });
132
+ return [];
133
+ }
134
+ }
135
+ async function buildTaskListFilters(query, ctx) {
136
+ const filters = {};
137
+ let narrowIds = null;
138
+ for (const raw of [query.ids, query.id]) {
139
+ const parsed = splitIdList(raw);
140
+ if (parsed === null) continue;
141
+ narrowIds = narrowIds ? narrowIds.filter((id) => parsed.includes(id)) : parsed;
142
+ }
143
+ const requestedTagIds = splitIdList(query.tagIds);
144
+ if (requestedTagIds !== null) {
145
+ const tagged = requestedTagIds.length === 0 ? [] : await resolveTaskIdsForTags(ctx, requestedTagIds);
146
+ narrowIds = narrowIds ? narrowIds.filter((id) => tagged.includes(id)) : tagged;
147
+ }
148
+ const access = await resolveListProjectAccess(ctx);
149
+ let projectIds = null;
150
+ if (!access.canManageAll) {
151
+ projectIds = [...access.projectIds];
152
+ if (typeof query.timeProjectId === "string" && query.timeProjectId.trim().length > 0) {
153
+ const requested = query.timeProjectId.trim();
154
+ projectIds = projectIds.filter((id) => id === requested);
155
+ }
156
+ if (projectIds.length === 0) {
157
+ filters[F.time_project_id] = { $in: [IMPOSSIBLE_ID] };
158
+ return filters;
159
+ }
160
+ filters[F.time_project_id] = { $in: projectIds };
161
+ } else if (typeof query.timeProjectId === "string" && query.timeProjectId.trim().length > 0) {
162
+ filters[F.time_project_id] = query.timeProjectId.trim();
163
+ }
164
+ if (narrowIds !== null) {
165
+ if (narrowIds.length === 0) {
166
+ filters[F.id] = { $in: [IMPOSSIBLE_ID] };
167
+ return filters;
168
+ }
169
+ filters[F.id] = { $in: narrowIds };
170
+ }
171
+ if (typeof query.taskStatusId === "string" && query.taskStatusId.trim().length > 0) {
172
+ filters[F.task_status_id] = query.taskStatusId.trim();
173
+ }
174
+ if (typeof query.assigneeStaffMemberId === "string" && query.assigneeStaffMemberId.trim().length > 0) {
175
+ filters[F.assignee_staff_member_id] = query.assigneeStaffMemberId.trim();
176
+ }
177
+ if (typeof query.parentTaskId === "string" && query.parentTaskId.trim().length > 0) {
178
+ filters[F.parent_task_id] = query.parentTaskId.trim();
179
+ } else if (parseBooleanFlag(query.topLevelOnly)) {
180
+ filters[F.parent_task_id] = { $eq: null };
181
+ }
182
+ const term = sanitizeSearchTerm(query.q);
183
+ if (term) {
184
+ filters[F.title] = { $ilike: `%${escapeLikePattern(term)}%` };
185
+ }
186
+ const referenceTerm = sanitizeSearchTerm(query.reference);
187
+ if (referenceTerm) {
188
+ filters[F.reference] = { $ilike: `${escapeLikePattern(referenceTerm)}%` };
189
+ }
190
+ return filters;
191
+ }
192
+ const taskListFields = [
193
+ F.id,
194
+ F.organization_id,
195
+ F.tenant_id,
196
+ F.time_project_id,
197
+ F.parent_task_id,
198
+ F.task_status_id,
199
+ F.sequence_number,
200
+ F.reference,
201
+ F.title,
202
+ F.description,
203
+ F.assignee_staff_member_id,
204
+ F.position,
205
+ F.created_by_user_id,
206
+ F.closed_at,
207
+ F.created_at,
208
+ F.updated_at
209
+ ];
210
+ const crud = makeCrudRoute({
211
+ metadata: routeMetadata,
212
+ orm: {
213
+ entity: StaffTimeTask,
214
+ idField: "id",
215
+ orgField: "organizationId",
216
+ tenantField: "tenantId",
217
+ softDeleteField: "deletedAt"
218
+ },
219
+ events: staffTimeTaskCrudEvents,
220
+ indexer: { entityType: "staff:staff_time_task" },
221
+ list: {
222
+ schema: listSchema,
223
+ entityId: "staff:staff_time_task",
224
+ fields: [...taskListFields],
225
+ // Cards stack in `position` order inside their column, so that is the board's
226
+ // natural sort rather than created-at.
227
+ defaultSort: { field: F.position, dir: "asc" },
228
+ tiebreakSortField: F.created_at,
229
+ sortFieldMap: {
230
+ position: F.position,
231
+ title: F.title,
232
+ reference: F.reference,
233
+ sequenceNumber: F.sequence_number,
234
+ createdAt: F.created_at,
235
+ updatedAt: F.updated_at,
236
+ closedAt: F.closed_at
237
+ },
238
+ buildFilters: buildTaskListFilters
239
+ },
240
+ enrichers: { entityId: "staff:staff_time_task" },
241
+ actions: {
242
+ create: {
243
+ commandId: staffTimeTaskCommandIds.create,
244
+ schema: rawBodySchema,
245
+ mapInput: async ({ raw, ctx }) => {
246
+ const { translate } = await resolveTranslations();
247
+ return parseScopedCommandInput(staffTimeTaskCreateSchema, raw ?? {}, ctx, translate);
248
+ },
249
+ response: ({ result }) => ({ id: result?.taskId ?? null }),
250
+ status: 201
251
+ },
252
+ update: {
253
+ commandId: staffTimeTaskCommandIds.update,
254
+ schema: rawBodySchema,
255
+ mapInput: async ({ raw, ctx }) => {
256
+ const { translate } = await resolveTranslations();
257
+ return parseScopedCommandInput(staffTimeTaskUpdateSchema, raw ?? {}, ctx, translate);
258
+ },
259
+ response: () => ({ ok: true })
260
+ },
261
+ delete: {
262
+ commandId: staffTimeTaskCommandIds.delete,
263
+ schema: rawBodySchema,
264
+ mapInput: async ({ parsed, ctx }) => {
265
+ const { translate } = await resolveTranslations();
266
+ const id = resolveCrudRecordId(parsed, ctx, translate);
267
+ return { id };
268
+ },
269
+ response: () => ({ ok: true })
270
+ }
271
+ }
272
+ });
273
+ const GET = crud.GET;
274
+ const POST = crud.POST;
275
+ const PUT = crud.PUT;
276
+ const DELETE = crud.DELETE;
277
+ const taskListItemSchema = z.object({
278
+ id: z.string().uuid().nullable().optional(),
279
+ organization_id: z.string().uuid().nullable().optional(),
280
+ tenant_id: z.string().uuid().nullable().optional(),
281
+ time_project_id: z.string().uuid().nullable().optional(),
282
+ parent_task_id: z.string().uuid().nullable().optional(),
283
+ task_status_id: z.string().uuid().nullable().optional(),
284
+ sequence_number: z.number().int().nullable().optional(),
285
+ reference: z.string().nullable().optional(),
286
+ title: z.string().nullable().optional(),
287
+ description: z.string().nullable().optional(),
288
+ assignee_staff_member_id: z.string().uuid().nullable().optional(),
289
+ position: z.number().int().nullable().optional(),
290
+ created_by_user_id: z.string().uuid().nullable().optional(),
291
+ closed_at: z.string().nullable().optional(),
292
+ created_at: z.string().nullable().optional(),
293
+ updated_at: z.string().nullable().optional(),
294
+ /** This task's own entries, in raw minutes. */
295
+ ownMinutes: z.number().int().optional(),
296
+ /** The inclusive rollup: own entries plus every live child's (D-2). */
297
+ loggedMinutes: z.number().int().optional(),
298
+ /** Live children only — soft-deleted subtasks are not counted. */
299
+ childCount: z.number().int().optional()
300
+ });
301
+ const openApi = createStaffCrudOpenApi({
302
+ resourceName: "TimeTask",
303
+ pluralName: "Time Tasks",
304
+ querySchema: listSchema,
305
+ listResponseSchema: createPagedListResponseSchema(taskListItemSchema),
306
+ create: {
307
+ schema: staffTimeTaskCreateSchema,
308
+ description: "Creates a task. Only `title` is required beyond scoping and `timeProjectId`: the task lands on the project default column with the creator assigned unless the request says otherwise. Supplying `parentTaskId` creates a subtask; a parent that is itself a subtask is refused with 400 subtask_depth_exceeded."
309
+ },
310
+ update: {
311
+ schema: staffTimeTaskUpdateSchema,
312
+ responseSchema: defaultOkResponseSchema,
313
+ description: "Updates a task. Re-parenting under a subtask, or turning a task that already has subtasks into one, is refused with 400 subtask_depth_exceeded; moving a task to another project is refused with 400 task_project_move_unsupported. Moving into a done column stamps closed_at, moving out clears it."
314
+ },
315
+ del: {
316
+ schema: z.object({ id: z.string().uuid() }),
317
+ responseSchema: defaultOkResponseSchema,
318
+ description: "Soft-deletes a task. Deleting a parent soft-deletes its subtasks in the same transaction; time entries keep pointing at the deleted task so closed reports still resolve their labels."
319
+ }
320
+ });
321
+ export {
322
+ DELETE,
323
+ GET,
324
+ POST,
325
+ PUT,
326
+ buildTaskListFilters,
327
+ metadata,
328
+ openApi,
329
+ resolveListProjectAccess,
330
+ taskListFields,
331
+ taskListItemSchema
332
+ };
333
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/staff/api/timesheets/tasks/route.ts"],
4
+ "sourcesContent": ["/**\n * Tasks \u2014 the board of screen 6, the drawer of screen 7 and the subtask checklist\n * inside it, all served from one collection (D-2: a subtask is a child task).\n *\n * Two things this route is responsible for beyond plain CRUD:\n *\n * 1. **Project access is intersected into every query.** A caller without\n * `staff.timesheets.projects.manage` only sees tasks belonging to projects they\n * are an active member of \u2014 including when they ask for one id. A route that\n * leaves that to the caller leaks another client's task titles, which is exactly\n * the defect the projects route was fixed for; the resolution is memoised per\n * request and fails closed, so an access decision that could not be made denies.\n * 2. **`topLevelOnly` is what the board asks for.** Children render inside their\n * parent's drawer, never as their own card, so the board filters\n * `parent_task_id IS NULL` rather than post-filtering a page it already paid for.\n *\n * The rollup fields (`ownMinutes`, `loggedMinutes`, `childCount`) are added by the\n * `staff.timesheets-tasks-rollup` response enricher rather than by a query in this\n * file, so the board pays one grouped aggregate per page instead of one per card.\n * `loggedMinutes` is the inclusive rollup (own + children, D-2); `ownMinutes` is this\n * task's entries alone. They are never summed together \u2014 see the enricher's note on\n * risk R10.\n */\n\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { staffTimeTaskCrudEvents } from '../../../lib/crud'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveCrudRecordId, parseScopedCommandInput } from '@open-mercato/shared/lib/api/scoped'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport type { ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'\nimport { StaffTimeTask, StaffTimeTaskTag } from '../../../data/entities'\nimport { staffTimeTaskCreateSchema, staffTimeTaskUpdateSchema } from '../../../data/validators'\nimport { staffTimeTaskCommandIds } from '../../../commands/timesheets-tasks'\nimport { resolveFeatureAccess } from '../../../lib/time-tracking/featureAccess'\nimport { MANAGE_PROJECTS_FEATURE, resolveProjectAccess, type ProjectAccess } from '../../../lib/time-tracking/access'\nimport { readTimeTrackingSettings } from '../../../lib/time-tracking/settings'\nimport { sanitizeSearchTerm, parseBooleanFlag } from '../../helpers'\nimport { createStaffCrudOpenApi, createPagedListResponseSchema, defaultOkResponseSchema } from '../../openapi'\n\nconst logger = createLogger('staff').child({ component: 'api/timesheets/tasks' })\n\nconst F = {\n id: 'id',\n tenant_id: 'tenant_id',\n organization_id: 'organization_id',\n time_project_id: 'time_project_id',\n parent_task_id: 'parent_task_id',\n task_status_id: 'task_status_id',\n sequence_number: 'sequence_number',\n reference: 'reference',\n title: 'title',\n description: 'description',\n assignee_staff_member_id: 'assignee_staff_member_id',\n position: 'position',\n created_by_user_id: 'created_by_user_id',\n closed_at: 'closed_at',\n created_at: 'created_at',\n updated_at: 'updated_at',\n} as const\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['staff.timesheets.tasks.view'] },\n POST: { requireAuth: true, requireFeatures: ['staff.timesheets.tasks.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['staff.timesheets.tasks.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['staff.timesheets.tasks.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n q: z.string().optional(),\n /** Prefix match on the denormalised `<CODE>-<n>` reference. */\n reference: z.string().optional(),\n id: z.string().optional(),\n ids: z.string().optional(),\n timeProjectId: z.string().uuid().optional(),\n taskStatusId: z.string().uuid().optional(),\n assigneeStaffMemberId: z.string().uuid().optional(),\n parentTaskId: z.string().uuid().optional(),\n tagIds: z.string().optional(),\n topLevelOnly: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\ntype TaskListQuery = z.infer<typeof listSchema>\n\n/**\n * Non-UUID sentinel used as the \"match nothing\" filter, mirroring the projects route\n * so both narrowing paths behave identically.\n */\nconst IMPOSSIBLE_ID = '00000000-0000-0000-0000-000000000000'\n\nconst DENIED_ACCESS: ProjectAccess = { canManageAll: false, projectIds: [], staffMemberId: null }\n\ntype RbacServiceLike = {\n getGrantedFeatures?: (\n userId: string,\n options: { tenantId: string | null; organizationId: string | null },\n ) => Promise<string[]>\n}\n\ntype ContainerLike = { resolve: (name: string) => unknown }\n\n/** One access decision per request, shared by every filter that needs it. */\nconst accessByRequest = new WeakMap<Request, Promise<ProjectAccess>>()\n\nasync function resolveAssignmentGraceDays(container: ContainerLike, tenantId: string): Promise<number | null> {\n try {\n const configService = container.resolve('moduleConfigService') as ModuleConfigService\n const settings = await readTimeTrackingSettings(configService, { tenantId })\n return settings.access.assignmentGraceDays\n } catch {\n // Fail safe to the documented default rather than widening the window.\n return null\n }\n}\n\nasync function loadProjectAccess(\n container: ContainerLike,\n userId: string | null,\n tenantId: string | null,\n organizationId: string | null,\n): Promise<ProjectAccess> {\n if (!tenantId || !organizationId) return { ...DENIED_ACCESS }\n const scope = { tenantId, organizationId }\n try {\n // One lookup, one authority, and a failure that says so. The previous\n // `catch \u2192 []` could not tell \"denied\" from \"could not ask\", so an RBAC\n // hiccup silently demoted a manager to their own memberships.\n const access = await resolveFeatureAccess(container, userId, [MANAGE_PROJECTS_FEATURE], scope)\n const em = container.resolve('em') as EntityManager\n return await resolveProjectAccess({\n em: em.fork(),\n userId,\n tenantId,\n organizationId,\n canManageAll: access.allowed,\n userFeatures: access.grantedFeatures,\n assignmentGraceDays: await resolveAssignmentGraceDays(container, tenantId),\n })\n } catch (err) {\n logger.error('staff.timesheets.tasks access resolution failed', { err })\n return { ...DENIED_ACCESS }\n }\n}\n\nexport async function resolveListProjectAccess(ctx: CrudCtx): Promise<ProjectAccess> {\n const tenantId = ctx.auth?.tenantId ?? null\n const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null\n const load = () => loadProjectAccess(ctx.container, ctx.auth?.sub ?? null, tenantId, organizationId)\n const request = ctx.request\n if (!request) return load()\n const cached = accessByRequest.get(request)\n if (cached) return cached\n const pending = load()\n accessByRequest.set(request, pending)\n return pending\n}\n\nfunction splitIdList(value: unknown): string[] | null {\n if (typeof value !== 'string' || value.trim().length === 0) return null\n const ids = value\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0)\n return ids.length > 0 ? ids : []\n}\n\n/**\n * Task ids carrying **every** requested tag (W9).\n *\n * AND rather than OR, because that is what the board's chips already mean\n * (`matchesBoardTagFilter` requires every selected tag), and a server filter that\n * disagreed with the chips would change the result set on the same selection.\n *\n * Returning `[]` narrows to nothing, which is the correct answer both when no task\n * carries the combination and when the lookup failed: a filter that cannot be\n * applied must not silently widen the page back to every task.\n */\nasync function resolveTaskIdsForTags(ctx: CrudCtx, tagIds: string[]): Promise<string[]> {\n const tenantId = ctx.auth?.tenantId ?? null\n const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null\n if (!tenantId || !organizationId) return []\n try {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const rows = await em.find(\n StaffTimeTaskTag,\n { tagId: { $in: tagIds }, tenantId, organizationId },\n { fields: ['taskId', 'tagId'] },\n )\n const seen = new Map<string, Set<string>>()\n for (const row of rows) {\n const taskId = row.taskId\n if (!taskId) continue\n const bucket = seen.get(taskId) ?? new Set<string>()\n bucket.add(row.tagId)\n seen.set(taskId, bucket)\n }\n const required = new Set(tagIds).size\n return [...seen.entries()].filter(([, tags]) => tags.size >= required).map(([taskId]) => taskId)\n } catch (err) {\n logger.error('staff.timesheets.tasks tag filter resolution failed', { err })\n return []\n }\n}\n\n/**\n * Every task query narrows to the projects the caller may actually see. Exported so\n * the access intersection is testable without standing up the CRUD factory.\n */\nexport async function buildTaskListFilters(\n query: TaskListQuery,\n ctx: CrudCtx,\n): Promise<Record<string, unknown>> {\n const filters: Record<string, unknown> = {}\n\n let narrowIds: string[] | null = null\n for (const raw of [query.ids, query.id]) {\n const parsed = splitIdList(raw)\n if (parsed === null) continue\n narrowIds = narrowIds ? narrowIds.filter((id) => parsed.includes(id)) : parsed\n }\n\n const requestedTagIds = splitIdList(query.tagIds)\n if (requestedTagIds !== null) {\n const tagged = requestedTagIds.length === 0 ? [] : await resolveTaskIdsForTags(ctx, requestedTagIds)\n narrowIds = narrowIds ? narrowIds.filter((id) => tagged.includes(id)) : tagged\n }\n\n const access = await resolveListProjectAccess(ctx)\n let projectIds: string[] | null = null\n if (!access.canManageAll) {\n projectIds = [...access.projectIds]\n if (typeof query.timeProjectId === 'string' && query.timeProjectId.trim().length > 0) {\n const requested = query.timeProjectId.trim()\n projectIds = projectIds.filter((id) => id === requested)\n }\n if (projectIds.length === 0) {\n // A non-member gets no row at all \u2014 not a redacted one \u2014 so a task title and\n // its project never leave the server.\n filters[F.time_project_id] = { $in: [IMPOSSIBLE_ID] }\n return filters\n }\n filters[F.time_project_id] = { $in: projectIds }\n } else if (typeof query.timeProjectId === 'string' && query.timeProjectId.trim().length > 0) {\n filters[F.time_project_id] = query.timeProjectId.trim()\n }\n\n if (narrowIds !== null) {\n if (narrowIds.length === 0) {\n filters[F.id] = { $in: [IMPOSSIBLE_ID] }\n return filters\n }\n filters[F.id] = { $in: narrowIds }\n }\n\n if (typeof query.taskStatusId === 'string' && query.taskStatusId.trim().length > 0) {\n filters[F.task_status_id] = query.taskStatusId.trim()\n }\n if (typeof query.assigneeStaffMemberId === 'string' && query.assigneeStaffMemberId.trim().length > 0) {\n filters[F.assignee_staff_member_id] = query.assigneeStaffMemberId.trim()\n }\n if (typeof query.parentTaskId === 'string' && query.parentTaskId.trim().length > 0) {\n // The drawer's checklist: one parent's children, in position order.\n filters[F.parent_task_id] = query.parentTaskId.trim()\n } else if (parseBooleanFlag(query.topLevelOnly)) {\n // The board: cards only, never a child that already renders inside a drawer.\n filters[F.parent_task_id] = { $eq: null }\n }\n\n const term = sanitizeSearchTerm(query.q)\n if (term) {\n // A reference is the thing people actually type \u2014 \"AWR-9\" is how a task is\n // named out loud \u2014 so searching only the title made the one identifier the\n // UI shows everywhere unusable as a search key.\n //\n // The query engine's filter compiler has no OR across fields (`normalizeFilters`\n // treats a top-level `$or` array as a field name), so the term is routed by\n // shape instead: anything that looks like a code or a code-and-number goes to\n // `reference`, everything else to `title`. A reference is `<CODE>-<n>` with no\n // spaces, which is not a shape task titles take.\n filters[F.title] = { $ilike: `%${escapeLikePattern(term)}%` }\n }\n\n // Searching by reference is a separate parameter rather than a shape-guess on\n // `q`, because the guess is not decidable: \"Booking\" is a title word and \"AWR\"\n // is a code, and both are single alphanumeric tokens. The query engine's filter\n // compiler has no OR across fields \u2014 `normalizeFilters` reads a top-level `$or`\n // array as a field name \u2014 so a caller that wants both asks for both and merges.\n const referenceTerm = sanitizeSearchTerm(query.reference)\n if (referenceTerm) {\n filters[F.reference] = { $ilike: `${escapeLikePattern(referenceTerm)}%` }\n }\n\n return filters\n}\n\nexport const taskListFields = [\n F.id,\n F.organization_id,\n F.tenant_id,\n F.time_project_id,\n F.parent_task_id,\n F.task_status_id,\n F.sequence_number,\n F.reference,\n F.title,\n F.description,\n F.assignee_staff_member_id,\n F.position,\n F.created_by_user_id,\n F.closed_at,\n F.created_at,\n F.updated_at,\n] as const\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: StaffTimeTask,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n events: staffTimeTaskCrudEvents,\n indexer: { entityType: 'staff:staff_time_task' },\n list: {\n schema: listSchema,\n entityId: 'staff:staff_time_task',\n fields: [...taskListFields],\n // Cards stack in `position` order inside their column, so that is the board's\n // natural sort rather than created-at.\n defaultSort: { field: F.position, dir: 'asc' },\n tiebreakSortField: F.created_at,\n sortFieldMap: {\n position: F.position,\n title: F.title,\n reference: F.reference,\n sequenceNumber: F.sequence_number,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n closedAt: F.closed_at,\n },\n buildFilters: buildTaskListFilters,\n },\n enrichers: { entityId: 'staff:staff_time_task' },\n actions: {\n create: {\n commandId: staffTimeTaskCommandIds.create,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(staffTimeTaskCreateSchema, raw ?? {}, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.taskId ?? null }),\n status: 201,\n },\n update: {\n commandId: staffTimeTaskCommandIds.update,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(staffTimeTaskUpdateSchema, raw ?? {}, ctx, translate)\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: staffTimeTaskCommandIds.delete,\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nexport const taskListItemSchema = z.object({\n id: z.string().uuid().nullable().optional(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n time_project_id: z.string().uuid().nullable().optional(),\n parent_task_id: z.string().uuid().nullable().optional(),\n task_status_id: z.string().uuid().nullable().optional(),\n sequence_number: z.number().int().nullable().optional(),\n reference: z.string().nullable().optional(),\n title: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n assignee_staff_member_id: z.string().uuid().nullable().optional(),\n position: z.number().int().nullable().optional(),\n created_by_user_id: z.string().uuid().nullable().optional(),\n closed_at: z.string().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n /** This task's own entries, in raw minutes. */\n ownMinutes: z.number().int().optional(),\n /** The inclusive rollup: own entries plus every live child's (D-2). */\n loggedMinutes: z.number().int().optional(),\n /** Live children only \u2014 soft-deleted subtasks are not counted. */\n childCount: z.number().int().optional(),\n})\n\nexport const openApi = createStaffCrudOpenApi({\n resourceName: 'TimeTask',\n pluralName: 'Time Tasks',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(taskListItemSchema),\n create: {\n schema: staffTimeTaskCreateSchema,\n description:\n 'Creates a task. Only `title` is required beyond scoping and `timeProjectId`: the task lands on the project default column with the creator assigned unless the request says otherwise. Supplying `parentTaskId` creates a subtask; a parent that is itself a subtask is refused with 400 subtask_depth_exceeded.',\n },\n update: {\n schema: staffTimeTaskUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description:\n 'Updates a task. Re-parenting under a subtask, or turning a task that already has subtasks into one, is refused with 400 subtask_depth_exceeded; moving a task to another project is refused with 400 task_project_move_unsupported. Moving into a done column stamps closed_at, moving out clears it.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description:\n 'Soft-deletes a task. Deleting a parent soft-deletes its subtasks in the same transaction; time entries keep pointing at the deleted task so closed reports still resolve their labels.',\n },\n})\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }