trueppm-api 0.4.0b2__py3-none-any.whl

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 (759) hide show
  1. trueppm_api/__init__.py +14 -0
  2. trueppm_api/apps/access/__init__.py +0 -0
  3. trueppm_api/apps/access/apps.py +19 -0
  4. trueppm_api/apps/access/groups.py +518 -0
  5. trueppm_api/apps/access/management/__init__.py +0 -0
  6. trueppm_api/apps/access/management/commands/__init__.py +0 -0
  7. trueppm_api/apps/access/management/commands/create_admin.py +164 -0
  8. trueppm_api/apps/access/management/commands/migrate_locked.py +96 -0
  9. trueppm_api/apps/access/management/commands/revoke_api_tokens.py +209 -0
  10. trueppm_api/apps/access/migrations/0001_initial.py +61 -0
  11. trueppm_api/apps/access/migrations/0001_squashed_0012_programmembership_role_title.py +167 -0
  12. trueppm_api/apps/access/migrations/0002_alter_projectmembership_id.py +29 -0
  13. trueppm_api/apps/access/migrations/0003_projectmembership_soft_delete.py +24 -0
  14. trueppm_api/apps/access/migrations/0004_alter_projectmembership_role.py +34 -0
  15. trueppm_api/apps/access/migrations/0005_program_entity_and_membership.py +76 -0
  16. trueppm_api/apps/access/migrations/0006_role_ordinal_spacing.py +113 -0
  17. trueppm_api/apps/access/migrations/0007_projectmembership_joined_at_and_more.py +35 -0
  18. trueppm_api/apps/access/migrations/0008_projectmembership_source_group.py +25 -0
  19. trueppm_api/apps/access/migrations/0009_projectmembership_pm_proj_serverver_idx.py +20 -0
  20. trueppm_api/apps/access/migrations/0010_programmembership_joined_at_and_more.py +38 -0
  21. trueppm_api/apps/access/migrations/0011_alter_programmembership_unique_together_and_more.py +36 -0
  22. trueppm_api/apps/access/migrations/0012_programmembership_role_title.py +17 -0
  23. trueppm_api/apps/access/migrations/0013_userdefinedmentiongroup.py +82 -0
  24. trueppm_api/apps/access/migrations/0014_programmembership_progm_serverver_idx.py +19 -0
  25. trueppm_api/apps/access/migrations/0015_programuserdefinedmentiongroup.py +86 -0
  26. trueppm_api/apps/access/migrations/0016_externalstakeholder.py +67 -0
  27. trueppm_api/apps/access/migrations/0017_viewer_ordinal_one.py +132 -0
  28. trueppm_api/apps/access/migrations/0018_programmembership_sync_seq_and_more.py +52 -0
  29. trueppm_api/apps/access/migrations/0019_programmembership_reinstated_at_and_more.py +22 -0
  30. trueppm_api/apps/access/migrations/__init__.py +0 -0
  31. trueppm_api/apps/access/models.py +588 -0
  32. trueppm_api/apps/access/permissions.py +2837 -0
  33. trueppm_api/apps/access/serializers.py +946 -0
  34. trueppm_api/apps/access/services.py +667 -0
  35. trueppm_api/apps/access/signals.py +103 -0
  36. trueppm_api/apps/access/tasks.py +50 -0
  37. trueppm_api/apps/access/throttles.py +95 -0
  38. trueppm_api/apps/access/urls.py +191 -0
  39. trueppm_api/apps/access/views.py +1931 -0
  40. trueppm_api/apps/agents/__init__.py +6 -0
  41. trueppm_api/apps/agents/apps.py +11 -0
  42. trueppm_api/apps/agents/canonical.py +73 -0
  43. trueppm_api/apps/agents/deferred.py +108 -0
  44. trueppm_api/apps/agents/management/__init__.py +0 -0
  45. trueppm_api/apps/agents/management/commands/__init__.py +0 -0
  46. trueppm_api/apps/agents/management/commands/audit_prune.py +137 -0
  47. trueppm_api/apps/agents/management/commands/audit_verify.py +101 -0
  48. trueppm_api/apps/agents/middleware.py +44 -0
  49. trueppm_api/apps/agents/migrations/0001_initial.py +231 -0
  50. trueppm_api/apps/agents/migrations/0002_agentactioncheckpoint.py +71 -0
  51. trueppm_api/apps/agents/migrations/0003_agentactionrefusaldetail.py +58 -0
  52. trueppm_api/apps/agents/migrations/__init__.py +0 -0
  53. trueppm_api/apps/agents/models.py +371 -0
  54. trueppm_api/apps/agents/refusal.py +103 -0
  55. trueppm_api/apps/agents/serializers.py +85 -0
  56. trueppm_api/apps/agents/services.py +397 -0
  57. trueppm_api/apps/agents/signals.py +30 -0
  58. trueppm_api/apps/agents/urls.py +15 -0
  59. trueppm_api/apps/agents/views.py +108 -0
  60. trueppm_api/apps/csvimport/__init__.py +12 -0
  61. trueppm_api/apps/csvimport/apps.py +11 -0
  62. trueppm_api/apps/csvimport/mapping.py +363 -0
  63. trueppm_api/apps/csvimport/migrations/0001_initial.py +74 -0
  64. trueppm_api/apps/csvimport/migrations/0002_schedule_outline_batch_operations.py +37 -0
  65. trueppm_api/apps/csvimport/migrations/0003_csvimportrequest_date_order_and_more.py +26 -0
  66. trueppm_api/apps/csvimport/migrations/__init__.py +0 -0
  67. trueppm_api/apps/csvimport/models.py +111 -0
  68. trueppm_api/apps/csvimport/parser.py +1825 -0
  69. trueppm_api/apps/csvimport/services.py +48 -0
  70. trueppm_api/apps/csvimport/tasks.py +418 -0
  71. trueppm_api/apps/csvimport/template.py +37 -0
  72. trueppm_api/apps/csvimport/urls.py +50 -0
  73. trueppm_api/apps/csvimport/views.py +793 -0
  74. trueppm_api/apps/history/__init__.py +0 -0
  75. trueppm_api/apps/history/apps.py +12 -0
  76. trueppm_api/apps/history/changelog.py +359 -0
  77. trueppm_api/apps/history/diff_policy.py +177 -0
  78. trueppm_api/apps/history/serializers.py +104 -0
  79. trueppm_api/apps/history/signals.py +82 -0
  80. trueppm_api/apps/history/tasks.py +105 -0
  81. trueppm_api/apps/history/urls.py +38 -0
  82. trueppm_api/apps/history/views.py +443 -0
  83. trueppm_api/apps/idempotency/__init__.py +0 -0
  84. trueppm_api/apps/idempotency/apps.py +11 -0
  85. trueppm_api/apps/idempotency/migrations/0001_initial.py +71 -0
  86. trueppm_api/apps/idempotency/migrations/__init__.py +0 -0
  87. trueppm_api/apps/idempotency/mixins.py +226 -0
  88. trueppm_api/apps/idempotency/models.py +75 -0
  89. trueppm_api/apps/idempotency/tasks.py +61 -0
  90. trueppm_api/apps/integrations/__init__.py +13 -0
  91. trueppm_api/apps/integrations/apps.py +59 -0
  92. trueppm_api/apps/integrations/connections.py +806 -0
  93. trueppm_api/apps/integrations/encryption.py +92 -0
  94. trueppm_api/apps/integrations/external_sources.py +837 -0
  95. trueppm_api/apps/integrations/git_automation_services.py +231 -0
  96. trueppm_api/apps/integrations/git_webhook_auth.py +243 -0
  97. trueppm_api/apps/integrations/http.py +403 -0
  98. trueppm_api/apps/integrations/me_work.py +218 -0
  99. trueppm_api/apps/integrations/migrations/0001_initial.py +64 -0
  100. trueppm_api/apps/integrations/migrations/0001_squashed_0006_tasklink_description_tasklink_preview_type_and_more.py +187 -0
  101. trueppm_api/apps/integrations/migrations/0002_tasklink.py +67 -0
  102. trueppm_api/apps/integrations/migrations/0003_tasklink_tasklink_serverver_idx.py +17 -0
  103. trueppm_api/apps/integrations/migrations/0004_tasklink_custom_title_tasklink_labels.py +25 -0
  104. trueppm_api/apps/integrations/migrations/0005_boardautomation.py +56 -0
  105. trueppm_api/apps/integrations/migrations/0006_tasklink_description_tasklink_preview_type_and_more.py +40 -0
  106. trueppm_api/apps/integrations/migrations/0007_tasklink_created_at.py +23 -0
  107. trueppm_api/apps/integrations/migrations/0008_integrationcredential_config_externalworkitem.py +66 -0
  108. trueppm_api/apps/integrations/migrations/0009_externalsyncrequest_and_more.py +96 -0
  109. trueppm_api/apps/integrations/migrations/0010_externalworkitem_due_date.py +17 -0
  110. trueppm_api/apps/integrations/migrations/0011_tasklink_sync_seq_tasklink_tasklink_syncseq_idx.py +22 -0
  111. trueppm_api/apps/integrations/migrations/0012_boardautomation_last_delivery_at_and_more.py +42 -0
  112. trueppm_api/apps/integrations/migrations/0013_externalsyncrequest_attempt_count_and_more.py +26 -0
  113. trueppm_api/apps/integrations/migrations/__init__.py +0 -0
  114. trueppm_api/apps/integrations/models.py +622 -0
  115. trueppm_api/apps/integrations/notification_channels.py +57 -0
  116. trueppm_api/apps/integrations/opengraph.py +229 -0
  117. trueppm_api/apps/integrations/outgoing.py +201 -0
  118. trueppm_api/apps/integrations/providers.py +519 -0
  119. trueppm_api/apps/integrations/registry.py +345 -0
  120. trueppm_api/apps/integrations/serializers.py +453 -0
  121. trueppm_api/apps/integrations/services.py +171 -0
  122. trueppm_api/apps/integrations/tasks.py +731 -0
  123. trueppm_api/apps/integrations/throttles.py +165 -0
  124. trueppm_api/apps/integrations/urls.py +77 -0
  125. trueppm_api/apps/integrations/views.py +1106 -0
  126. trueppm_api/apps/jiraimport/__init__.py +8 -0
  127. trueppm_api/apps/jiraimport/apps.py +11 -0
  128. trueppm_api/apps/jiraimport/migrations/0001_initial.py +72 -0
  129. trueppm_api/apps/jiraimport/migrations/__init__.py +0 -0
  130. trueppm_api/apps/jiraimport/models.py +70 -0
  131. trueppm_api/apps/jiraimport/parser.py +350 -0
  132. trueppm_api/apps/jiraimport/services.py +46 -0
  133. trueppm_api/apps/jiraimport/tasks.py +277 -0
  134. trueppm_api/apps/jiraimport/urls.py +15 -0
  135. trueppm_api/apps/jiraimport/views.py +153 -0
  136. trueppm_api/apps/msproject/__init__.py +0 -0
  137. trueppm_api/apps/msproject/apps.py +11 -0
  138. trueppm_api/apps/msproject/dataclasses.py +153 -0
  139. trueppm_api/apps/msproject/exporter.py +500 -0
  140. trueppm_api/apps/msproject/extended_attributes.py +77 -0
  141. trueppm_api/apps/msproject/importer.py +1095 -0
  142. trueppm_api/apps/msproject/migrations/0001_import_request.py +77 -0
  143. trueppm_api/apps/msproject/migrations/0001_squashed_0002_importrequest_creates_project.py +80 -0
  144. trueppm_api/apps/msproject/migrations/0002_importrequest_creates_project.py +15 -0
  145. trueppm_api/apps/msproject/migrations/__init__.py +0 -0
  146. trueppm_api/apps/msproject/models.py +81 -0
  147. trueppm_api/apps/msproject/parser.py +1231 -0
  148. trueppm_api/apps/msproject/serializers.py +136 -0
  149. trueppm_api/apps/msproject/services.py +58 -0
  150. trueppm_api/apps/msproject/tasks.py +436 -0
  151. trueppm_api/apps/msproject/urls.py +39 -0
  152. trueppm_api/apps/msproject/views.py +531 -0
  153. trueppm_api/apps/notifications/__init__.py +7 -0
  154. trueppm_api/apps/notifications/apps.py +15 -0
  155. trueppm_api/apps/notifications/backfill.py +79 -0
  156. trueppm_api/apps/notifications/categories.py +112 -0
  157. trueppm_api/apps/notifications/delivery_limits.py +258 -0
  158. trueppm_api/apps/notifications/digests.py +447 -0
  159. trueppm_api/apps/notifications/email_backend.py +330 -0
  160. trueppm_api/apps/notifications/email_health.py +128 -0
  161. trueppm_api/apps/notifications/migrations/0001_initial.py +207 -0
  162. trueppm_api/apps/notifications/migrations/0001_squashed_0006_notification_task.py +294 -0
  163. trueppm_api/apps/notifications/migrations/0002_project_notification_preference.py +67 -0
  164. trueppm_api/apps/notifications/migrations/0003_projectnotificationpreference_paused.py +17 -0
  165. trueppm_api/apps/notifications/migrations/0004_clean_unknown_matrix_keys.py +30 -0
  166. trueppm_api/apps/notifications/migrations/0005_notification_body_notification_event_type_and_more.py +27 -0
  167. trueppm_api/apps/notifications/migrations/0006_notification_task.py +25 -0
  168. trueppm_api/apps/notifications/migrations/0007_workspaceemailsettings.py +80 -0
  169. trueppm_api/apps/notifications/migrations/0008_notification_snoozed_until.py +17 -0
  170. trueppm_api/apps/notifications/migrations/0009_usernotificationsettings.py +43 -0
  171. trueppm_api/apps/notifications/migrations/0010_projectnotificationpreference_schema_version.py +20 -0
  172. trueppm_api/apps/notifications/migrations/0011_usernotificationsettings_digest_hour_and_more.py +96 -0
  173. trueppm_api/apps/notifications/migrations/__init__.py +0 -0
  174. trueppm_api/apps/notifications/models.py +1197 -0
  175. trueppm_api/apps/notifications/receivers.py +155 -0
  176. trueppm_api/apps/notifications/schema_migrations.py +56 -0
  177. trueppm_api/apps/notifications/serializers.py +961 -0
  178. trueppm_api/apps/notifications/services.py +1451 -0
  179. trueppm_api/apps/notifications/tasks.py +711 -0
  180. trueppm_api/apps/notifications/throttles.py +98 -0
  181. trueppm_api/apps/notifications/urls.py +97 -0
  182. trueppm_api/apps/notifications/views.py +904 -0
  183. trueppm_api/apps/observability/__init__.py +0 -0
  184. trueppm_api/apps/observability/apps.py +31 -0
  185. trueppm_api/apps/observability/logging.py +213 -0
  186. trueppm_api/apps/observability/migrations/0001_initial.py +35 -0
  187. trueppm_api/apps/observability/migrations/0001_squashed_0003_alter_purgerun_trigger.py +154 -0
  188. trueppm_api/apps/observability/migrations/0002_purgerun_retentionpolicy_retentionschedule.py +131 -0
  189. trueppm_api/apps/observability/migrations/0003_alter_purgerun_trigger.py +21 -0
  190. trueppm_api/apps/observability/migrations/0004_alter_retentionpolicy_key.py +28 -0
  191. trueppm_api/apps/observability/migrations/__init__.py +0 -0
  192. trueppm_api/apps/observability/models.py +141 -0
  193. trueppm_api/apps/observability/otel/__init__.py +45 -0
  194. trueppm_api/apps/observability/otel/attributes.py +247 -0
  195. trueppm_api/apps/observability/otel/export_health.py +533 -0
  196. trueppm_api/apps/observability/otel/instrumentation.py +351 -0
  197. trueppm_api/apps/observability/otel/metrics.py +551 -0
  198. trueppm_api/apps/observability/otel/provider.py +511 -0
  199. trueppm_api/apps/observability/otel/request_attributes.py +204 -0
  200. trueppm_api/apps/observability/purge_registry.py +124 -0
  201. trueppm_api/apps/observability/retention.py +139 -0
  202. trueppm_api/apps/observability/selectors.py +969 -0
  203. trueppm_api/apps/observability/serializers.py +142 -0
  204. trueppm_api/apps/observability/services.py +407 -0
  205. trueppm_api/apps/observability/tasks.py +266 -0
  206. trueppm_api/apps/observability/urls.py +27 -0
  207. trueppm_api/apps/observability/views.py +523 -0
  208. trueppm_api/apps/profiles/__init__.py +0 -0
  209. trueppm_api/apps/profiles/apps.py +15 -0
  210. trueppm_api/apps/profiles/constants.py +54 -0
  211. trueppm_api/apps/profiles/migrations/0001_initial.py +55 -0
  212. trueppm_api/apps/profiles/migrations/0001_squashed_0004_userprofile_role_context.py +125 -0
  213. trueppm_api/apps/profiles/migrations/0002_userprofile_hidden_views.py +17 -0
  214. trueppm_api/apps/profiles/migrations/0003_projectvisit.py +63 -0
  215. trueppm_api/apps/profiles/migrations/0004_userprofile_role_context.py +26 -0
  216. trueppm_api/apps/profiles/migrations/0005_userprofile_schedule_in_deliver.py +20 -0
  217. trueppm_api/apps/profiles/migrations/0006_userprofile_date_format_userprofile_timezone.py +36 -0
  218. trueppm_api/apps/profiles/migrations/0007_userpin.py +91 -0
  219. trueppm_api/apps/profiles/migrations/0008_remove_userprofile_schedule_in_deliver.py +71 -0
  220. trueppm_api/apps/profiles/migrations/0009_auth_user_email_upper_idx.py +81 -0
  221. trueppm_api/apps/profiles/migrations/__init__.py +0 -0
  222. trueppm_api/apps/profiles/models.py +276 -0
  223. trueppm_api/apps/profiles/serializers.py +199 -0
  224. trueppm_api/apps/profiles/services.py +466 -0
  225. trueppm_api/apps/profiles/views.py +124 -0
  226. trueppm_api/apps/projects/__init__.py +0 -0
  227. trueppm_api/apps/projects/actual_date_rules.py +163 -0
  228. trueppm_api/apps/projects/amend.py +133 -0
  229. trueppm_api/apps/projects/apps.py +38 -0
  230. trueppm_api/apps/projects/asset_feed.py +459 -0
  231. trueppm_api/apps/projects/asset_views.py +317 -0
  232. trueppm_api/apps/projects/attachment_policy.py +278 -0
  233. trueppm_api/apps/projects/authentication.py +449 -0
  234. trueppm_api/apps/projects/backfill.py +287 -0
  235. trueppm_api/apps/projects/backlog_services.py +324 -0
  236. trueppm_api/apps/projects/backlog_views.py +302 -0
  237. trueppm_api/apps/projects/batch_operation_views.py +264 -0
  238. trueppm_api/apps/projects/blocker_services.py +510 -0
  239. trueppm_api/apps/projects/board_activity.py +462 -0
  240. trueppm_api/apps/projects/board_activity_views.py +186 -0
  241. trueppm_api/apps/projects/board_lanes.py +134 -0
  242. trueppm_api/apps/projects/bulk_settings.py +194 -0
  243. trueppm_api/apps/projects/bundled_templates.py +215 -0
  244. trueppm_api/apps/projects/calendar_settings.py +180 -0
  245. trueppm_api/apps/projects/ceremony_views.py +244 -0
  246. trueppm_api/apps/projects/commit_moment.py +204 -0
  247. trueppm_api/apps/projects/config_notice.py +1325 -0
  248. trueppm_api/apps/projects/custom_field_values.py +266 -0
  249. trueppm_api/apps/projects/decisions_services.py +93 -0
  250. trueppm_api/apps/projects/decisions_views.py +94 -0
  251. trueppm_api/apps/projects/estimation_scale.py +126 -0
  252. trueppm_api/apps/projects/export_bundle.py +353 -0
  253. trueppm_api/apps/projects/fixtures/seeds/atlas-platform-launch.json +4256 -0
  254. trueppm_api/apps/projects/fixtures/seeds/aurora-mobile-app.json +2000 -0
  255. trueppm_api/apps/projects/fixtures/seeds/bayside-civic-center.json +1825 -0
  256. trueppm_api/apps/projects/fixtures/seeds/ga-launch.json +1905 -0
  257. trueppm_api/apps/projects/fixtures/seeds/helios-crm-replacement.json +1409 -0
  258. trueppm_api/apps/projects/guardrail_policy_source.py +269 -0
  259. trueppm_api/apps/projects/inbound_sync.py +555 -0
  260. trueppm_api/apps/projects/iteration_label.py +85 -0
  261. trueppm_api/apps/projects/lifecycle.py +191 -0
  262. trueppm_api/apps/projects/management/__init__.py +0 -0
  263. trueppm_api/apps/projects/management/commands/__init__.py +0 -0
  264. trueppm_api/apps/projects/management/commands/backfill_in_progress_status.py +92 -0
  265. trueppm_api/apps/projects/management/commands/create_demo_share_link.py +368 -0
  266. trueppm_api/apps/projects/management/commands/export_program.py +50 -0
  267. trueppm_api/apps/projects/management/commands/import_seed.py +165 -0
  268. trueppm_api/apps/projects/management/commands/load_sample_project.py +247 -0
  269. trueppm_api/apps/projects/management/commands/seed_capacity.py +405 -0
  270. trueppm_api/apps/projects/management/commands/seed_integration_fixtures.py +178 -0
  271. trueppm_api/apps/projects/management/commands/shift_sample_dates.py +120 -0
  272. trueppm_api/apps/projects/mcp_settings.py +305 -0
  273. trueppm_api/apps/projects/methodology.py +178 -0
  274. trueppm_api/apps/projects/migrations/0001_initial.py +208 -0
  275. trueppm_api/apps/projects/migrations/0001_squashed_0094_project_decisions_policy.py +5595 -0
  276. trueppm_api/apps/projects/migrations/0002_alter_uuid_pk_serialize_false.py +57 -0
  277. trueppm_api/apps/projects/migrations/0003_rename_task_project_index.py +25 -0
  278. trueppm_api/apps/projects/migrations/0004_soft_delete_and_dependency_versioned.py +70 -0
  279. trueppm_api/apps/projects/migrations/0005_task_assignee.py +33 -0
  280. trueppm_api/apps/projects/migrations/0006_task_utilization_index.py +31 -0
  281. trueppm_api/apps/projects/migrations/0007_task_is_milestone.py +28 -0
  282. trueppm_api/apps/projects/migrations/0008_baseline.py +119 -0
  283. trueppm_api/apps/projects/migrations/0009_historicaldependency_historicalproject_and_more.py +210 -0
  284. trueppm_api/apps/projects/migrations/0010_risk.py +229 -0
  285. trueppm_api/apps/projects/migrations/0011_task_status.py +27 -0
  286. trueppm_api/apps/projects/migrations/0012_task_status.py +27 -0
  287. trueppm_api/apps/projects/migrations/0013_task_planned_start.py +24 -0
  288. trueppm_api/apps/projects/migrations/0014_short_hex_ids.py +74 -0
  289. trueppm_api/apps/projects/migrations/0015_backfill_short_ids.py +48 -0
  290. trueppm_api/apps/projects/migrations/0016_task_actual_dates.py +42 -0
  291. trueppm_api/apps/projects/migrations/0017_boardcolumnconfig.py +43 -0
  292. trueppm_api/apps/projects/migrations/0018_estimation_governance.py +62 -0
  293. trueppm_api/apps/projects/migrations/0019_backfill_wbs_paths.py +28 -0
  294. trueppm_api/apps/projects/migrations/0020_task_status_5col.py +65 -0
  295. trueppm_api/apps/projects/migrations/0021_boardsavedview.py +64 -0
  296. trueppm_api/apps/projects/migrations/0022_task_status_changed_at_priority_rank.py +35 -0
  297. trueppm_api/apps/projects/migrations/0023_risk_framework_fields.py +96 -0
  298. trueppm_api/apps/projects/migrations/0024_riskcomment.py +52 -0
  299. trueppm_api/apps/projects/migrations/0025_sprint.py +352 -0
  300. trueppm_api/apps/projects/migrations/0026_project_methodology.py +30 -0
  301. trueppm_api/apps/projects/migrations/0027_sprint_retro.py +89 -0
  302. trueppm_api/apps/projects/migrations/0028_normalize_notes_field.py +42 -0
  303. trueppm_api/apps/projects/migrations/0029_complete_implies_full_progress.py +38 -0
  304. trueppm_api/apps/projects/migrations/0030_review_implies_full_progress.py +37 -0
  305. trueppm_api/apps/projects/migrations/0031_task_remaining_points.py +22 -0
  306. trueppm_api/apps/projects/migrations/0032_task_is_subtask_and_sprint_scope_change.py +90 -0
  307. trueppm_api/apps/projects/migrations/0033_task_my_work_index.py +38 -0
  308. trueppm_api/apps/projects/migrations/0034_inbound_task_sync.py +313 -0
  309. trueppm_api/apps/projects/migrations/0035_retro_versioned_and_suggested_assignee.py +173 -0
  310. trueppm_api/apps/projects/migrations/0036_program_entity_and_membership.py +157 -0
  311. trueppm_api/apps/projects/migrations/0037_sprint_capacity_points.py +20 -0
  312. trueppm_api/apps/projects/migrations/0038_taskcomment_commentreaction_commentacknowledgement_and_more.py +233 -0
  313. trueppm_api/apps/projects/migrations/0039_apitoken_and_more.py +88 -0
  314. trueppm_api/apps/projects/migrations/0040_program_general_fields.py +119 -0
  315. trueppm_api/apps/projects/migrations/0041_ceremony_template_and_phase_gate_config.py +210 -0
  316. trueppm_api/apps/projects/migrations/0041_project_general_fields.py +106 -0
  317. trueppm_api/apps/projects/migrations/0042_merge_20260522_0410.py +12 -0
  318. trueppm_api/apps/projects/migrations/0042_program_rollup_config.py +95 -0
  319. trueppm_api/apps/projects/migrations/0042_workflow_color_and_custom_fields.py +94 -0
  320. trueppm_api/apps/projects/migrations/0043_merge_20260522_1118.py +10 -0
  321. trueppm_api/apps/projects/migrations/0044_merge_20260522_rollup.py +10 -0
  322. trueppm_api/apps/projects/migrations/0044_project_archive_program_close.py +119 -0
  323. trueppm_api/apps/projects/migrations/0045_program_risk_policy.py +78 -0
  324. trueppm_api/apps/projects/migrations/0046_merge_20260523_2248.py +12 -0
  325. trueppm_api/apps/projects/migrations/0047_apitokenauditentry_program_and_more.py +55 -0
  326. trueppm_api/apps/projects/migrations/0048_historicalprogram_color_program_color.py +32 -0
  327. trueppm_api/apps/projects/migrations/0049_backlog_item.py +112 -0
  328. trueppm_api/apps/projects/migrations/0050_backlog_item_trgm_search.py +26 -0
  329. trueppm_api/apps/projects/migrations/0051_alter_calendar_working_days_alter_dependency_lag_and_more.py +144 -0
  330. trueppm_api/apps/projects/migrations/0052_recurring_tasks.py +278 -0
  331. trueppm_api/apps/projects/migrations/0053_dependency_dep_pred_serverver_idx_and_more.py +56 -0
  332. trueppm_api/apps/projects/migrations/0054_sprintscopechange_goal_impact_and_more.py +117 -0
  333. trueppm_api/apps/projects/migrations/0055_historicaltask_sprint_pending_and_more.py +51 -0
  334. trueppm_api/apps/projects/migrations/0056_historicalproject_prioritization_model_and_more.py +276 -0
  335. trueppm_api/apps/projects/migrations/0057_historicalsprint_binding_committed_snapshot_and_more.py +58 -0
  336. trueppm_api/apps/projects/migrations/0058_historicaltask_delivery_mode_and_more.py +72 -0
  337. trueppm_api/apps/projects/migrations/0059_forecastsnapshot.py +80 -0
  338. trueppm_api/apps/projects/migrations/0060_historicalprojectsignalprivacypolicy_and_more.py +90 -0
  339. trueppm_api/apps/projects/migrations/0061_baselinetask_story_points.py +17 -0
  340. trueppm_api/apps/projects/migrations/0062_project_is_sample.py +22 -0
  341. trueppm_api/apps/projects/migrations/0063_historicalsprint_wip_limit_sprint_wip_limit.py +22 -0
  342. trueppm_api/apps/projects/migrations/0064_sprinttaskoutcome.py +97 -0
  343. trueppm_api/apps/projects/migrations/0065_historicalsprint_goal_outcome_sprint_goal_outcome.py +32 -0
  344. trueppm_api/apps/projects/migrations/0066_historicalproject_lead_project_lead.py +38 -0
  345. trueppm_api/apps/projects/migrations/0067_sprint_exclude_from_velocity.py +22 -0
  346. trueppm_api/apps/projects/migrations/0068_project_recalculated_at.py +23 -0
  347. trueppm_api/apps/projects/migrations/0069_iteration_label.py +22 -0
  348. trueppm_api/apps/projects/migrations/0070_historicalprogram_iteration_label_and_more.py +32 -0
  349. trueppm_api/apps/projects/migrations/0071_backfill_iteration_label_inherit.py +35 -0
  350. trueppm_api/apps/projects/migrations/0072_pulseresponse_retroboarditem.py +129 -0
  351. trueppm_api/apps/projects/migrations/0073_sprinttaskoutcome_demo_ready.py +17 -0
  352. trueppm_api/apps/projects/migrations/0074_historicaltask_blocked_reason_task_blocked_reason.py +30 -0
  353. trueppm_api/apps/projects/migrations/0075_risk_decimal_short_id.py +42 -0
  354. trueppm_api/apps/projects/migrations/0076_sprinttaskoutcome_review_polish.py +45 -0
  355. trueppm_api/apps/projects/migrations/0077_task_blocker_fields.py +111 -0
  356. trueppm_api/apps/projects/migrations/0078_alter_risktask_unique_together_and_more.py +22 -0
  357. trueppm_api/apps/projects/migrations/0079_historicalproject_status_date_project_status_date.py +22 -0
  358. trueppm_api/apps/projects/migrations/0080_alter_historicaltask_type_alter_task_type.py +46 -0
  359. trueppm_api/apps/projects/migrations/0081_historicalprogram_allow_guests_and_more.py +52 -0
  360. trueppm_api/apps/projects/migrations/0082_project_last_sync_version.py +90 -0
  361. trueppm_api/apps/projects/migrations/0083_historicalprogram_mc_history_attribution_audience_and_more.py +108 -0
  362. trueppm_api/apps/projects/migrations/0084_tasknote.py +71 -0
  363. trueppm_api/apps/projects/migrations/0085_sprint_ix_sprint_velocity.py +33 -0
  364. trueppm_api/apps/projects/migrations/0086_board_card_search_trgm.py +33 -0
  365. trueppm_api/apps/projects/migrations/0087_historicalprogram_task_duration_change_percent_policy_and_more.py +155 -0
  366. trueppm_api/apps/projects/migrations/0088_historicalprogram_allowed_attachment_types_and_more.py +61 -0
  367. trueppm_api/apps/projects/migrations/0089_signalceilingraiseproposal_signalceilingraisevote_and_more.py +157 -0
  368. trueppm_api/apps/projects/migrations/0090_historicaltask_proj_histdate_index.py +44 -0
  369. trueppm_api/apps/projects/migrations/0091_project_board_cadence.py +39 -0
  370. trueppm_api/apps/projects/migrations/0092_program_target_date.py +22 -0
  371. trueppm_api/apps/projects/migrations/0093_cross_project_dependency_consent.py +58 -0
  372. trueppm_api/apps/projects/migrations/0094_project_decisions_policy.py +90 -0
  373. trueppm_api/apps/projects/migrations/0095_poker_session_vote.py +127 -0
  374. trueppm_api/apps/projects/migrations/0095_squashed_0097_release_0_3.py +225 -0
  375. trueppm_api/apps/projects/migrations/0096_crossprojectslipconflict.py +91 -0
  376. trueppm_api/apps/projects/migrations/0097_backlogitem_backlogitem_tags_gin_and_more.py +32 -0
  377. trueppm_api/apps/projects/migrations/0098_historicalproject_show_baselines_and_more.py +52 -0
  378. trueppm_api/apps/projects/migrations/0099_apitoken_scopes.py +48 -0
  379. trueppm_api/apps/projects/migrations/0100_task_dep_serverver_idx_concurrent.py +61 -0
  380. trueppm_api/apps/projects/migrations/0101_dependency_deleted_at_task_deleted_at.py +22 -0
  381. trueppm_api/apps/projects/migrations/0102_project_deleted_at_project_proj_isdel_deletedat_idx.py +25 -0
  382. trueppm_api/apps/projects/migrations/0103_taskdurationchangeevent_task_dur_evt_sprint_idx.py +18 -0
  383. trueppm_api/apps/projects/migrations/0104_historicalproject_stale_task_threshold_days_and_more.py +32 -0
  384. trueppm_api/apps/projects/migrations/0104_trash_restore_1113.py +38 -0
  385. trueppm_api/apps/projects/migrations/0105_historical_changelog_indexes.py +62 -0
  386. trueppm_api/apps/projects/migrations/0106_boardsavedview_schema_version.py +20 -0
  387. trueppm_api/apps/projects/migrations/0107_task_activity_event.py +70 -0
  388. trueppm_api/apps/projects/migrations/0108_remove_apitoken_api_token_scope_xor_and_more.py +117 -0
  389. trueppm_api/apps/projects/migrations/0109_projectexportjob.py +82 -0
  390. trueppm_api/apps/projects/migrations/0110_sharelink.py +123 -0
  391. trueppm_api/apps/projects/migrations/0111_projectcalendarlayer.py +67 -0
  392. trueppm_api/apps/projects/migrations/0112_sharelink_expires_at_alter_sharelink_content_kind.py +31 -0
  393. trueppm_api/apps/projects/migrations/0113_alter_historicaltask_percent_complete_and_more.py +35 -0
  394. trueppm_api/apps/projects/migrations/0114_historicalproject_default_member_role_and_more.py +28 -0
  395. trueppm_api/apps/projects/migrations/0115_historicalproject_end_date_shift_threshold_days_and_more.py +22 -0
  396. trueppm_api/apps/projects/migrations/0116_alter_taskactivityevent_event_type.py +28 -0
  397. trueppm_api/apps/projects/migrations/0117_label_tasklabel_label_tasks_and_more.py +126 -0
  398. trueppm_api/apps/projects/migrations/0118_programexportjob.py +82 -0
  399. trueppm_api/apps/projects/migrations/0119_historicalprogram_calendar_program_calendar.py +36 -0
  400. trueppm_api/apps/projects/migrations/0120_alter_backlogitem_item_type.py +29 -0
  401. trueppm_api/apps/projects/migrations/0121_task_three_point_estimate_ordered.py +64 -0
  402. trueppm_api/apps/projects/migrations/0122_task_relation.py +173 -0
  403. trueppm_api/apps/projects/migrations/0123_remove_historicalproject_agile_features_and_more.py +20 -0
  404. trueppm_api/apps/projects/migrations/0124_dependency_is_driving.py +17 -0
  405. trueppm_api/apps/projects/migrations/0125_historicalprogram_estimation_scale_and_more.py +68 -0
  406. trueppm_api/apps/projects/migrations/0126_projectcustomfield_show_on_card_taskcustomfieldvalue.py +80 -0
  407. trueppm_api/apps/projects/migrations/0127_historicalprogram_mcp_enabled_and_more.py +32 -0
  408. trueppm_api/apps/projects/migrations/0128_acceptancecriterion_sync_seq_apitoken_sync_seq_and_more.py +192 -0
  409. trueppm_api/apps/projects/migrations/0129_sharelink_show_milestone_dates.py +20 -0
  410. trueppm_api/apps/projects/migrations/0130_programimportjob.py +85 -0
  411. trueppm_api/apps/projects/migrations/0131_historicalprogram_sprint_picker_ready_only_default_and_more.py +32 -0
  412. trueppm_api/apps/projects/migrations/0132_task_scheduled_start.py +17 -0
  413. trueppm_api/apps/projects/migrations/0133_project_status_date_floor_armed_at.py +17 -0
  414. trueppm_api/apps/projects/migrations/0134_task_edited_at_task_seeded_at_task_source_id_and_more.py +65 -0
  415. trueppm_api/apps/projects/migrations/0135_projecttemplate_templateapplication_and_more.py +175 -0
  416. trueppm_api/apps/projects/migrations/0136_schedule_outline_batch_operations.py +118 -0
  417. trueppm_api/apps/projects/migrations/0137_collapse_dual_scope_api_tokens.py +54 -0
  418. trueppm_api/apps/projects/migrations/0138_apitokenauditentry_api_token_audit_owner_idx.py +18 -0
  419. trueppm_api/apps/projects/migrations/0139_historicaltask_duration_unit_task_duration_unit.py +32 -0
  420. trueppm_api/apps/projects/migrations/0140_historicaltask_auto_container_and_more.py +113 -0
  421. trueppm_api/apps/projects/migrations/0141_historicalproject_draft_started_at_and_more.py +44 -0
  422. trueppm_api/apps/projects/migrations/0142_baseline_calendar_hours_per_day_and_more.py +31 -0
  423. trueppm_api/apps/projects/migrations/0143_sprintcloserequest_failure_reason_and_more.py +42 -0
  424. trueppm_api/apps/projects/migrations/0144_projecttemplate_source_project_and_more.py +35 -0
  425. trueppm_api/apps/projects/migrations/0145_seed_bundled_templates.py +65 -0
  426. trueppm_api/apps/projects/migrations/0146_historicaltask_board_lane_task_board_lane.py +32 -0
  427. trueppm_api/apps/projects/migrations/0147_structuraloperation.py +128 -0
  428. trueppm_api/apps/projects/migrations/0148_task_unique_task_wbs_path_per_project_live.py +76 -0
  429. trueppm_api/apps/projects/migrations/0149_drop_workshops_tables.py +42 -0
  430. trueppm_api/apps/projects/migrations/0150_clear_uncommitted_cpm_output.py +130 -0
  431. trueppm_api/apps/projects/migrations/0151_config_notice_request.py +70 -0
  432. trueppm_api/apps/projects/migrations/0152_aggregate_task_wbs_name_idx.py +20 -0
  433. trueppm_api/apps/projects/migrations/0153_program_sample_anchor_date.py +22 -0
  434. trueppm_api/apps/projects/migrations/__init__.py +0 -0
  435. trueppm_api/apps/projects/models.py +8946 -0
  436. trueppm_api/apps/projects/poker_services.py +154 -0
  437. trueppm_api/apps/projects/poker_views.py +398 -0
  438. trueppm_api/apps/projects/product_backlog_services.py +450 -0
  439. trueppm_api/apps/projects/program_label_services.py +94 -0
  440. trueppm_api/apps/projects/program_label_views.py +189 -0
  441. trueppm_api/apps/projects/program_rollup.py +575 -0
  442. trueppm_api/apps/projects/program_schedule.py +745 -0
  443. trueppm_api/apps/projects/program_views.py +3220 -0
  444. trueppm_api/apps/projects/project_templates.py +422 -0
  445. trueppm_api/apps/projects/receivers.py +234 -0
  446. trueppm_api/apps/projects/refusal_codes.py +140 -0
  447. trueppm_api/apps/projects/reorder_services.py +145 -0
  448. trueppm_api/apps/projects/restructure_hooks.py +54 -0
  449. trueppm_api/apps/projects/retro_board_services.py +368 -0
  450. trueppm_api/apps/projects/retro_services.py +285 -0
  451. trueppm_api/apps/projects/risk_import.py +396 -0
  452. trueppm_api/apps/projects/row_identity.py +113 -0
  453. trueppm_api/apps/projects/schema_migrations.py +228 -0
  454. trueppm_api/apps/projects/schemas/seed_v1.json +493 -0
  455. trueppm_api/apps/projects/schemas/seed_v2.json +892 -0
  456. trueppm_api/apps/projects/seed/__init__.py +61 -0
  457. trueppm_api/apps/projects/seed/exporter.py +1644 -0
  458. trueppm_api/apps/projects/seed/forecast_backfill.py +247 -0
  459. trueppm_api/apps/projects/seed/importer.py +2390 -0
  460. trueppm_api/apps/projects/seed/reanchor.py +551 -0
  461. trueppm_api/apps/projects/seed/reldates.py +126 -0
  462. trueppm_api/apps/projects/seed/replace.py +126 -0
  463. trueppm_api/apps/projects/seed/replay.py +1691 -0
  464. trueppm_api/apps/projects/seed/replay_ctx.py +41 -0
  465. trueppm_api/apps/projects/seed/samples.py +427 -0
  466. trueppm_api/apps/projects/seed/validation.py +1149 -0
  467. trueppm_api/apps/projects/serializers.py +12310 -0
  468. trueppm_api/apps/projects/services.py +6966 -0
  469. trueppm_api/apps/projects/share_serializers.py +132 -0
  470. trueppm_api/apps/projects/share_services.py +325 -0
  471. trueppm_api/apps/projects/share_views.py +374 -0
  472. trueppm_api/apps/projects/sharing_settings.py +187 -0
  473. trueppm_api/apps/projects/signal_privacy_services.py +909 -0
  474. trueppm_api/apps/projects/signal_privacy_views.py +476 -0
  475. trueppm_api/apps/projects/signals.py +132 -0
  476. trueppm_api/apps/projects/slip_conflict.py +266 -0
  477. trueppm_api/apps/projects/sprint_cadence.py +453 -0
  478. trueppm_api/apps/projects/sprint_picker_settings.py +132 -0
  479. trueppm_api/apps/projects/standup.py +304 -0
  480. trueppm_api/apps/projects/standup_views.py +99 -0
  481. trueppm_api/apps/projects/structural_operation_services.py +727 -0
  482. trueppm_api/apps/projects/structural_operation_views.py +311 -0
  483. trueppm_api/apps/projects/surface_visibility.py +126 -0
  484. trueppm_api/apps/projects/task_batch_services.py +379 -0
  485. trueppm_api/apps/projects/task_bulk.py +1152 -0
  486. trueppm_api/apps/projects/task_classification.py +561 -0
  487. trueppm_api/apps/projects/task_classification_defaults.py +95 -0
  488. trueppm_api/apps/projects/task_duration_settings.py +142 -0
  489. trueppm_api/apps/projects/task_grouping.py +754 -0
  490. trueppm_api/apps/projects/tasks.py +1917 -0
  491. trueppm_api/apps/projects/template_divergence.py +168 -0
  492. trueppm_api/apps/projects/template_services.py +160 -0
  493. trueppm_api/apps/projects/template_tasks.py +258 -0
  494. trueppm_api/apps/projects/template_views.py +799 -0
  495. trueppm_api/apps/projects/throttles.py +311 -0
  496. trueppm_api/apps/projects/urls.py +1011 -0
  497. trueppm_api/apps/projects/utilization.py +885 -0
  498. trueppm_api/apps/projects/views.py +20572 -0
  499. trueppm_api/apps/projects/wbs_paths.py +119 -0
  500. trueppm_api/apps/resources/__init__.py +0 -0
  501. trueppm_api/apps/resources/apps.py +8 -0
  502. trueppm_api/apps/resources/capacity.py +121 -0
  503. trueppm_api/apps/resources/migrations/0001_initial.py +68 -0
  504. trueppm_api/apps/resources/migrations/0001_squashed_0013_alter_projectresource_unique_together_and_more.py +281 -0
  505. trueppm_api/apps/resources/migrations/0002_alter_uuid_pk_serialize_false.py +36 -0
  506. trueppm_api/apps/resources/migrations/0003_resource_soft_delete.py +30 -0
  507. trueppm_api/apps/resources/migrations/0004_add_taskresource_resource_index.py +25 -0
  508. trueppm_api/apps/resources/migrations/0005_resource_job_role.py +20 -0
  509. trueppm_api/apps/resources/migrations/0006_skill.py +34 -0
  510. trueppm_api/apps/resources/migrations/0007_resource_skill.py +63 -0
  511. trueppm_api/apps/resources/migrations/0008_project_resource.py +63 -0
  512. trueppm_api/apps/resources/migrations/0009_task_skill_requirement.py +60 -0
  513. trueppm_api/apps/resources/migrations/0010_alter_resourceskill_options_and_more.py +20 -0
  514. trueppm_api/apps/resources/migrations/0011_alter_projectresource_notes.py +17 -0
  515. trueppm_api/apps/resources/migrations/0012_add_resource_user_fk.py +26 -0
  516. trueppm_api/apps/resources/migrations/0013_alter_projectresource_unique_together_and_more.py +53 -0
  517. trueppm_api/apps/resources/migrations/0014_projectresource_sync_seq_resource_sync_seq_and_more.py +37 -0
  518. trueppm_api/apps/resources/migrations/0015_projectresource_deactivated_with_resource.py +17 -0
  519. trueppm_api/apps/resources/migrations/__init__.py +0 -0
  520. trueppm_api/apps/resources/models.py +298 -0
  521. trueppm_api/apps/resources/serializers.py +426 -0
  522. trueppm_api/apps/resources/services.py +465 -0
  523. trueppm_api/apps/resources/urls.py +28 -0
  524. trueppm_api/apps/resources/views.py +1749 -0
  525. trueppm_api/apps/scheduling/__init__.py +0 -0
  526. trueppm_api/apps/scheduling/apps.py +153 -0
  527. trueppm_api/apps/scheduling/calendars.py +119 -0
  528. trueppm_api/apps/scheduling/deadletter.py +91 -0
  529. trueppm_api/apps/scheduling/forecast_history_settings.py +215 -0
  530. trueppm_api/apps/scheduling/forecast_staleness.py +313 -0
  531. trueppm_api/apps/scheduling/graph_guard.py +263 -0
  532. trueppm_api/apps/scheduling/management/__init__.py +0 -0
  533. trueppm_api/apps/scheduling/management/commands/__init__.py +0 -0
  534. trueppm_api/apps/scheduling/management/commands/prune_forecast_snapshots.py +53 -0
  535. trueppm_api/apps/scheduling/migrations/0001_failed_task.py +62 -0
  536. trueppm_api/apps/scheduling/migrations/0001_squashed_0007_projectforecastsnapshot.py +309 -0
  537. trueppm_api/apps/scheduling/migrations/0002_schedulerequest.py +78 -0
  538. trueppm_api/apps/scheduling/migrations/0003_add_schedule_request_reason.py +27 -0
  539. trueppm_api/apps/scheduling/migrations/0004_velocity_suggestion.py +94 -0
  540. trueppm_api/apps/scheduling/migrations/0005_montecarlorun.py +61 -0
  541. trueppm_api/apps/scheduling/migrations/0006_montecarlorun_distribution.py +17 -0
  542. trueppm_api/apps/scheduling/migrations/0007_projectforecastsnapshot.py +65 -0
  543. trueppm_api/apps/scheduling/migrations/0008_alter_schedulerequest_reason.py +28 -0
  544. trueppm_api/apps/scheduling/migrations/0008_folded_schedulerequest_reason.py +34 -0
  545. trueppm_api/apps/scheduling/migrations/0009_alter_schedulerequest_reason.py +29 -0
  546. trueppm_api/apps/scheduling/migrations/0010_failedtask_resolution_note_failedtask_resolved_at_and_more.py +43 -0
  547. trueppm_api/apps/scheduling/migrations/0011_failedtask_project.py +26 -0
  548. trueppm_api/apps/scheduling/migrations/0012_montecarlorun_diagnostic.py +17 -0
  549. trueppm_api/apps/scheduling/migrations/0013_montecarlorun_status_date.py +17 -0
  550. trueppm_api/apps/scheduling/migrations/0014_montecarlorun_plan_version.py +17 -0
  551. trueppm_api/apps/scheduling/migrations/__init__.py +0 -0
  552. trueppm_api/apps/scheduling/models.py +516 -0
  553. trueppm_api/apps/scheduling/receivers.py +160 -0
  554. trueppm_api/apps/scheduling/risk_premium.py +283 -0
  555. trueppm_api/apps/scheduling/serializers.py +564 -0
  556. trueppm_api/apps/scheduling/services.py +1182 -0
  557. trueppm_api/apps/scheduling/signals.py +56 -0
  558. trueppm_api/apps/scheduling/tasks.py +1984 -0
  559. trueppm_api/apps/scheduling/telemetry.py +80 -0
  560. trueppm_api/apps/scheduling/units.py +35 -0
  561. trueppm_api/apps/scheduling/urls.py +57 -0
  562. trueppm_api/apps/scheduling/views.py +2564 -0
  563. trueppm_api/apps/sso/__init__.py +0 -0
  564. trueppm_api/apps/sso/apps.py +19 -0
  565. trueppm_api/apps/sso/extensions.py +130 -0
  566. trueppm_api/apps/sso/management/__init__.py +0 -0
  567. trueppm_api/apps/sso/management/commands/__init__.py +0 -0
  568. trueppm_api/apps/sso/management/commands/seed_sso_keycloak.py +172 -0
  569. trueppm_api/apps/sso/migrations/0001_initial.py +119 -0
  570. trueppm_api/apps/sso/migrations/0002_remove_oidcprovider_workspace_ssoproviderpolicy_and_more.py +169 -0
  571. trueppm_api/apps/sso/migrations/__init__.py +0 -0
  572. trueppm_api/apps/sso/models.py +148 -0
  573. trueppm_api/apps/sso/serializers.py +437 -0
  574. trueppm_api/apps/sso/services.py +1385 -0
  575. trueppm_api/apps/sso/urls.py +47 -0
  576. trueppm_api/apps/sso/views.py +935 -0
  577. trueppm_api/apps/sync/__init__.py +0 -0
  578. trueppm_api/apps/sync/apps.py +15 -0
  579. trueppm_api/apps/sync/backfill.py +208 -0
  580. trueppm_api/apps/sync/broadcast.py +320 -0
  581. trueppm_api/apps/sync/conflict.py +262 -0
  582. trueppm_api/apps/sync/consumers.py +471 -0
  583. trueppm_api/apps/sync/migrations/0001_initial.py +59 -0
  584. trueppm_api/apps/sync/migrations/0001_squashed_0002_remove_syncbatch_syncbatch_project_client_batch_uniq_and_more.py +77 -0
  585. trueppm_api/apps/sync/migrations/0002_remove_syncbatch_syncbatch_project_client_batch_uniq_and_more.py +41 -0
  586. trueppm_api/apps/sync/migrations/0003_boardevent.py +46 -0
  587. trueppm_api/apps/sync/migrations/0004_seed_sync_seq.py +24 -0
  588. trueppm_api/apps/sync/migrations/0005_program_sync_sequence.py +35 -0
  589. trueppm_api/apps/sync/migrations/__init__.py +0 -0
  590. trueppm_api/apps/sync/models.py +225 -0
  591. trueppm_api/apps/sync/pagination.py +231 -0
  592. trueppm_api/apps/sync/sequence.py +371 -0
  593. trueppm_api/apps/sync/serializers.py +687 -0
  594. trueppm_api/apps/sync/tasks.py +260 -0
  595. trueppm_api/apps/sync/throttles.py +175 -0
  596. trueppm_api/apps/sync/upload.py +501 -0
  597. trueppm_api/apps/sync/urls.py +17 -0
  598. trueppm_api/apps/sync/views.py +930 -0
  599. trueppm_api/apps/sync/ws_auth.py +193 -0
  600. trueppm_api/apps/taskruns/__init__.py +0 -0
  601. trueppm_api/apps/taskruns/apps.py +11 -0
  602. trueppm_api/apps/taskruns/migrations/0001_initial.py +92 -0
  603. trueppm_api/apps/taskruns/migrations/__init__.py +0 -0
  604. trueppm_api/apps/taskruns/models.py +68 -0
  605. trueppm_api/apps/taskruns/serializers.py +92 -0
  606. trueppm_api/apps/taskruns/tasks.py +60 -0
  607. trueppm_api/apps/taskruns/tracker.py +286 -0
  608. trueppm_api/apps/taskruns/urls.py +46 -0
  609. trueppm_api/apps/taskruns/views.py +195 -0
  610. trueppm_api/apps/teams/__init__.py +8 -0
  611. trueppm_api/apps/teams/apps.py +16 -0
  612. trueppm_api/apps/teams/migrations/0001_initial.py +139 -0
  613. trueppm_api/apps/teams/migrations/0001_squashed_0002_default_teams.py +142 -0
  614. trueppm_api/apps/teams/migrations/0002_default_teams.py +62 -0
  615. trueppm_api/apps/teams/migrations/0003_team_sync_seq_teammembership_sync_seq.py +22 -0
  616. trueppm_api/apps/teams/migrations/__init__.py +0 -0
  617. trueppm_api/apps/teams/models.py +145 -0
  618. trueppm_api/apps/teams/permissions.py +149 -0
  619. trueppm_api/apps/teams/serializers.py +95 -0
  620. trueppm_api/apps/teams/services.py +434 -0
  621. trueppm_api/apps/teams/signals.py +61 -0
  622. trueppm_api/apps/teams/urls.py +34 -0
  623. trueppm_api/apps/teams/views.py +201 -0
  624. trueppm_api/apps/timetracking/__init__.py +0 -0
  625. trueppm_api/apps/timetracking/apps.py +9 -0
  626. trueppm_api/apps/timetracking/migrations/0001_initial.py +117 -0
  627. trueppm_api/apps/timetracking/migrations/0002_timesheetsubmission.py +46 -0
  628. trueppm_api/apps/timetracking/migrations/0003_timeentry_deleted_at_timeentry_deleted_by.py +31 -0
  629. trueppm_api/apps/timetracking/migrations/0004_timeentry_sync_seq_and_more.py +24 -0
  630. trueppm_api/apps/timetracking/migrations/__init__.py +0 -0
  631. trueppm_api/apps/timetracking/models.py +178 -0
  632. trueppm_api/apps/timetracking/serializers.py +175 -0
  633. trueppm_api/apps/timetracking/services.py +117 -0
  634. trueppm_api/apps/timetracking/urls.py +47 -0
  635. trueppm_api/apps/timetracking/views.py +526 -0
  636. trueppm_api/apps/webhooks/__init__.py +0 -0
  637. trueppm_api/apps/webhooks/apps.py +8 -0
  638. trueppm_api/apps/webhooks/backfill.py +90 -0
  639. trueppm_api/apps/webhooks/dispatch.py +144 -0
  640. trueppm_api/apps/webhooks/migrations/0001_initial.py +146 -0
  641. trueppm_api/apps/webhooks/migrations/0001_squashed_0007_sprint_lifecycle_events.py +243 -0
  642. trueppm_api/apps/webhooks/migrations/0002_alter_webhook_events.py +32 -0
  643. trueppm_api/apps/webhooks/migrations/0003_delivery_status_created_idx.py +17 -0
  644. trueppm_api/apps/webhooks/migrations/0004_webhook_program_alter_webhook_project_and_more.py +64 -0
  645. trueppm_api/apps/webhooks/migrations/0005_webhook_delivery_sequence_numbers.py +30 -0
  646. trueppm_api/apps/webhooks/migrations/0006_webhook_format_alter_webhook_events_and_more.py +61 -0
  647. trueppm_api/apps/webhooks/migrations/0007_sprint_lifecycle_events.py +63 -0
  648. trueppm_api/apps/webhooks/migrations/0008_risk_baseline_comment_events.py +73 -0
  649. trueppm_api/apps/webhooks/migrations/0009_encrypt_webhook_secret_and_failure_counters.py +90 -0
  650. trueppm_api/apps/webhooks/migrations/__init__.py +0 -0
  651. trueppm_api/apps/webhooks/models.py +372 -0
  652. trueppm_api/apps/webhooks/serializers.py +318 -0
  653. trueppm_api/apps/webhooks/tasks.py +663 -0
  654. trueppm_api/apps/webhooks/urls.py +22 -0
  655. trueppm_api/apps/webhooks/views.py +383 -0
  656. trueppm_api/apps/workflow_engine/__init__.py +0 -0
  657. trueppm_api/apps/workflow_engine/apps.py +23 -0
  658. trueppm_api/apps/workflow_engine/migrations/0001_initial.py +230 -0
  659. trueppm_api/apps/workflow_engine/migrations/0001_squashed_0002_remove_workflowhistoryevent_workflow_history_lookup_idx.py +234 -0
  660. trueppm_api/apps/workflow_engine/migrations/0002_remove_workflowhistoryevent_workflow_history_lookup_idx.py +16 -0
  661. trueppm_api/apps/workflow_engine/migrations/0003_workflowoutboxrow_workflow_outbox_recovery_idx.py +21 -0
  662. trueppm_api/apps/workflow_engine/migrations/__init__.py +0 -0
  663. trueppm_api/apps/workflow_engine/models.py +265 -0
  664. trueppm_api/apps/workflow_engine/tasks.py +368 -0
  665. trueppm_api/apps/workspace/__init__.py +0 -0
  666. trueppm_api/apps/workspace/apps.py +10 -0
  667. trueppm_api/apps/workspace/backfill.py +111 -0
  668. trueppm_api/apps/workspace/export.py +242 -0
  669. trueppm_api/apps/workspace/migrations/0001_initial.py +326 -0
  670. trueppm_api/apps/workspace/migrations/0001_squashed_0014_workspacemembership_availability_effective_from_and_more.py +829 -0
  671. trueppm_api/apps/workspace/migrations/0002_remove_workspace_fiscal_year_start_and_more.py +85 -0
  672. trueppm_api/apps/workspace/migrations/0003_workspaceexportjob.py +73 -0
  673. trueppm_api/apps/workspace/migrations/0004_alter_workspaceinvite_status.py +27 -0
  674. trueppm_api/apps/workspace/migrations/0005_workspace_iteration_label_and_more.py +26 -0
  675. trueppm_api/apps/workspace/migrations/0006_alter_groupmembership_unique_together_and_more.py +45 -0
  676. trueppm_api/apps/workspace/migrations/0007_workspace_public_sharing_override_policy.py +21 -0
  677. trueppm_api/apps/workspace/migrations/0008_workspace_mc_history_attribution_audience_and_more.py +44 -0
  678. trueppm_api/apps/workspace/migrations/0009_workspace_methodology_and_more.py +186 -0
  679. trueppm_api/apps/workspace/migrations/0010_workspace_logo.py +38 -0
  680. trueppm_api/apps/workspace/migrations/0011_historicalworkspace_task_duration_change_percent_override_policy_and_more.py +56 -0
  681. trueppm_api/apps/workspace/migrations/0012_historicalworkspace_allowed_attachment_types_and_more.py +64 -0
  682. trueppm_api/apps/workspace/migrations/0013_auditevent.py +70 -0
  683. trueppm_api/apps/workspace/migrations/0014_workspacemembership_availability_effective_from_and_more.py +39 -0
  684. trueppm_api/apps/workspace/migrations/0015_trash_restore_1113.py +34 -0
  685. trueppm_api/apps/workspace/migrations/0016_historicalworkspace_calendar_and_more.py +55 -0
  686. trueppm_api/apps/workspace/migrations/0017_historicalworkspace_estimation_scale_and_more.py +38 -0
  687. trueppm_api/apps/workspace/migrations/0018_historicalworkspace_feedback_enabled_and_more.py +32 -0
  688. trueppm_api/apps/workspace/migrations/0019_historicalworkspace_mcp_enabled_and_more.py +22 -0
  689. trueppm_api/apps/workspace/migrations/0020_viewer_ordinal_one.py +34 -0
  690. trueppm_api/apps/workspace/migrations/0021_group_sync_seq_groupmembership_sync_seq_and_more.py +27 -0
  691. trueppm_api/apps/workspace/migrations/0022_historicalworkspace_sprint_picker_ready_only_default_and_more.py +22 -0
  692. trueppm_api/apps/workspace/migrations/0023_alter_auditevent_event_type.py +32 -0
  693. trueppm_api/apps/workspace/migrations/0024_alter_auditevent_event_type.py +33 -0
  694. trueppm_api/apps/workspace/migrations/0025_alter_auditevent_event_type.py +36 -0
  695. trueppm_api/apps/workspace/migrations/0026_alter_auditevent_event_type.py +37 -0
  696. trueppm_api/apps/workspace/migrations/0027_alter_auditevent_event_type.py +42 -0
  697. trueppm_api/apps/workspace/migrations/__init__.py +0 -0
  698. trueppm_api/apps/workspace/models.py +857 -0
  699. trueppm_api/apps/workspace/permissions.py +187 -0
  700. trueppm_api/apps/workspace/serializers.py +590 -0
  701. trueppm_api/apps/workspace/services.py +919 -0
  702. trueppm_api/apps/workspace/signals.py +37 -0
  703. trueppm_api/apps/workspace/tasks.py +555 -0
  704. trueppm_api/apps/workspace/urls.py +113 -0
  705. trueppm_api/apps/workspace/views.py +1502 -0
  706. trueppm_api/asgi.py +42 -0
  707. trueppm_api/celery.py +31 -0
  708. trueppm_api/core/__init__.py +0 -0
  709. trueppm_api/core/admin_site.py +206 -0
  710. trueppm_api/core/auth_views.py +916 -0
  711. trueppm_api/core/constant_time.py +51 -0
  712. trueppm_api/core/csp.py +54 -0
  713. trueppm_api/core/db.py +87 -0
  714. trueppm_api/core/db_session.py +37 -0
  715. trueppm_api/core/exception_handlers.py +157 -0
  716. trueppm_api/core/export_downloads.py +56 -0
  717. trueppm_api/core/extension_providers.py +56 -0
  718. trueppm_api/core/extension_signals.py +147 -0
  719. trueppm_api/core/idempotent.py +260 -0
  720. trueppm_api/core/metadata.py +42 -0
  721. trueppm_api/core/middleware.py +51 -0
  722. trueppm_api/core/openapi.py +949 -0
  723. trueppm_api/core/password_reset.py +500 -0
  724. trueppm_api/core/protect_conflict.py +100 -0
  725. trueppm_api/core/ratelimit.py +148 -0
  726. trueppm_api/core/redis_throttle.py +82 -0
  727. trueppm_api/core/refresh_cookie_policy.py +156 -0
  728. trueppm_api/core/request_body.py +86 -0
  729. trueppm_api/core/security_checks.py +884 -0
  730. trueppm_api/core/storage_config.py +105 -0
  731. trueppm_api/core/text_decode.py +168 -0
  732. trueppm_api/core/throttling.py +344 -0
  733. trueppm_api/core/valkey.py +214 -0
  734. trueppm_api/core/valkey_cache.py +66 -0
  735. trueppm_api/core/valkey_checks.py +104 -0
  736. trueppm_api/core/valkey_config.py +39 -0
  737. trueppm_api/core/worker_broker_wait.py +149 -0
  738. trueppm_api/core/worker_heartbeat.py +134 -0
  739. trueppm_api/fields.py +36 -0
  740. trueppm_api/permissions.py +30 -0
  741. trueppm_api/py.typed +0 -0
  742. trueppm_api/routing.py +11 -0
  743. trueppm_api/settings/__init__.py +0 -0
  744. trueppm_api/settings/base.py +2455 -0
  745. trueppm_api/settings/dev.py +273 -0
  746. trueppm_api/settings/prod.py +228 -0
  747. trueppm_api/urls.py +153 -0
  748. trueppm_api/workflows/__init__.py +38 -0
  749. trueppm_api/workflows/backends/__init__.py +6 -0
  750. trueppm_api/workflows/backends/default.py +297 -0
  751. trueppm_api/workflows/consumers/__init__.py +11 -0
  752. trueppm_api/workflows/consumers/requeue_failed_task.py +65 -0
  753. trueppm_api/workflows/interface.py +148 -0
  754. trueppm_api/workflows/registry.py +106 -0
  755. trueppm_api/workflows/services.py +90 -0
  756. trueppm_api/wsgi.py +11 -0
  757. trueppm_api-0.4.0b2.dist-info/METADATA +70 -0
  758. trueppm_api-0.4.0b2.dist-info/RECORD +759 -0
  759. trueppm_api-0.4.0b2.dist-info/WHEEL +4 -0
@@ -0,0 +1,516 @@
1
+ """Models for the scheduling app — Celery task infrastructure."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+
7
+ from django.conf import settings
8
+ from django.db import models
9
+
10
+ # Lazy FK target — Django serializes the FK target to this resolved string, so
11
+ # using the constant produces no migration change.
12
+ _PROJECT_MODEL = "projects.Project"
13
+
14
+
15
+ class ScheduleRequestStatus(models.TextChoices):
16
+ """Lifecycle of a transactional outbox row for CPM recalculation."""
17
+
18
+ PENDING = "pending", "Pending"
19
+ DISPATCHED = "dispatched", "Dispatched"
20
+ DONE = "done", "Done"
21
+ DEAD = "dead", "Dead"
22
+
23
+
24
+ class ScheduleRequestReason(models.TextChoices):
25
+ """Why a CPM recalculation was requested — used for audit trail and drain dedup."""
26
+
27
+ TASK_CHANGE = "task_change", "Task Change"
28
+ DEPENDENCY_CHANGE = "dependency_change", "Dependency Change"
29
+ # A project's working calendar is a CPM input — lag is calendar-aware — so a
30
+ # calendar swap shifts every task's working-day math and forces a full recompute.
31
+ CALENDAR_CHANGE = "calendar_change", "Calendar Change"
32
+ # An accepted cross-project edge mutated (created/accepted/deleted): the
33
+ # project's program now needs a merged, program-scoped recompute so the
34
+ # cross-project critical path stays program-true (ADR-0120 D3). Recorded on
35
+ # the outbox rows of *both* endpoint projects; the drain/dispatch coalesces
36
+ # them into one program-scoped pass.
37
+ CROSS_PROJECT_DEPENDENCY = "cross_project_dependency", "Cross-Project Dependency"
38
+ SPRINT_CLOSED = "sprint_closed", "Sprint Closed"
39
+ MANUAL = "manual", "Manual"
40
+
41
+
42
+ class ScheduleRequest(models.Model):
43
+ """Transactional outbox record for CPM recalculation requests.
44
+
45
+ Each write operation on a project's task graph inserts one row here
46
+ (or silently ignores a duplicate via the partial unique constraint) in
47
+ the same DB transaction. A Celery Beat drain task dispatches pending rows
48
+ every 30 seconds, and recalculate_schedule marks its own row done on
49
+ completion.
50
+
51
+ Two partial unique constraints enforce at-most-one pending and at-most-one
52
+ dispatched row per project at any time, so duplicate suppression is cheap
53
+ and correct under concurrent writes.
54
+
55
+ Does NOT inherit VersionedModel — not synced to mobile clients.
56
+ """
57
+
58
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
59
+ project = models.ForeignKey(
60
+ _PROJECT_MODEL,
61
+ on_delete=models.CASCADE,
62
+ related_name="schedule_requests",
63
+ )
64
+ status = models.CharField(
65
+ max_length=16,
66
+ choices=ScheduleRequestStatus.choices,
67
+ default=ScheduleRequestStatus.PENDING,
68
+ )
69
+ reason = models.CharField(
70
+ max_length=24,
71
+ choices=ScheduleRequestReason.choices,
72
+ default=ScheduleRequestReason.TASK_CHANGE,
73
+ db_index=True,
74
+ )
75
+ requested_at = models.DateTimeField(auto_now_add=True)
76
+ dispatched_at = models.DateTimeField(null=True, blank=True)
77
+ celery_task_id = models.CharField(max_length=255, blank=True, default="")
78
+
79
+ class Meta:
80
+ ordering = ["requested_at"]
81
+ constraints = [
82
+ models.UniqueConstraint(
83
+ fields=["project"],
84
+ condition=models.Q(status="pending"),
85
+ name="schedule_request_one_pending_per_project",
86
+ ),
87
+ models.UniqueConstraint(
88
+ fields=["project"],
89
+ condition=models.Q(status="dispatched"),
90
+ name="schedule_request_one_dispatched_per_project",
91
+ ),
92
+ ]
93
+ indexes = [
94
+ models.Index(
95
+ fields=["status", "requested_at"],
96
+ name="schedule_request_status_idx",
97
+ ),
98
+ ]
99
+
100
+ def __str__(self) -> str:
101
+ return f"ScheduleRequest({self.project_id}, {self.status})"
102
+
103
+
104
+ class MCAttributionAudience(models.TextChoices):
105
+ """Who may see the run-author name on Monte Carlo forecast history (ADR-0144).
106
+
107
+ Defined here (not on Workspace) because both the per-workspace config columns
108
+ and the ``MonteCarloHistoryView`` attribution gate reference it; placing it on
109
+ the scheduling model keeps a single source and avoids a workspace ``→`` scheduling
110
+ import cycle (workspace/projects import this enum, never the reverse).
111
+
112
+ The default ``ADMIN_OWNER`` preserves the pre-0143 hardcoded Admin/Owner gate
113
+ exactly, so the three-valued enum is backward-compatible and reversible.
114
+ """
115
+
116
+ ADMIN_OWNER = "admin_owner", "Admins and Owners"
117
+ SCHEDULER_PLUS = "scheduler_plus", "Schedulers and above"
118
+ NONE = "none", "No one"
119
+
120
+
121
+ class FailedTaskStatus(models.TextChoices):
122
+ """Lifecycle of a dead-lettered Celery task."""
123
+
124
+ PENDING_RETRY = "pending_retry", "Pending Retry"
125
+ DEAD = "dead", "Dead"
126
+ DISMISSED = "dismissed", "Dismissed"
127
+ RETRIED = "retried", "Retried"
128
+
129
+
130
+ class FailedTask(models.Model):
131
+ """Persistent record of a Celery task that exhausted all retries.
132
+
133
+ Does NOT inherit VersionedModel — not synced to mobile, not part of the
134
+ project data graph. Exists for admin visibility and manual retry/dismiss.
135
+ """
136
+
137
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
138
+ task_name = models.CharField(max_length=255, db_index=True)
139
+ task_id = models.CharField(max_length=255, unique=True)
140
+ # Attribution for the dead-letter queue (#1917). Nullable: not every
141
+ # dead-lettered task is project-scoped (e.g. the nightly cross-project purge
142
+ # tasks), and existing rows predate this column. SET_NULL rather than CASCADE
143
+ # — deleting a project must never delete the failure audit trail that explains
144
+ # what it was doing when it broke; the row just loses its project reference.
145
+ # Populated by ``deadletter.record_failed_task`` from whatever ``project_id``
146
+ # the failing task already knew (most scheduling tasks take one as an arg).
147
+ project = models.ForeignKey(
148
+ _PROJECT_MODEL,
149
+ on_delete=models.SET_NULL,
150
+ null=True,
151
+ blank=True,
152
+ related_name="failed_tasks",
153
+ help_text="Project the failing task acted on, when known.",
154
+ )
155
+ args = models.JSONField(default=list)
156
+ kwargs = models.JSONField(default=dict)
157
+ exception_type = models.CharField(max_length=255)
158
+ exception_message = models.TextField()
159
+ traceback = models.TextField()
160
+ failure_count = models.PositiveIntegerField(default=1)
161
+ first_failed_at = models.DateTimeField(auto_now_add=True)
162
+ last_failed_at = models.DateTimeField(auto_now=True)
163
+ status = models.CharField(
164
+ max_length=16,
165
+ choices=FailedTaskStatus.choices,
166
+ default=FailedTaskStatus.DEAD,
167
+ db_index=True,
168
+ )
169
+ # Operator-action audit (ADR-0210). Stamped on both requeue and drop so every
170
+ # write action against a parked task is attributable (who/when), and drop can
171
+ # carry a free-text reason. Nullable/defaulted because the vast majority of
172
+ # rows are written by the automatic dead-letter path, which never resolves them
173
+ # — only an explicit operator action sets these. Retained (never hard-deleted)
174
+ # so the audit survives a drop; ADR-0084 "no silent discards".
175
+ resolution_note = models.TextField(
176
+ blank=True,
177
+ default="",
178
+ help_text="Operator's free-text note recorded when the task was dropped.",
179
+ )
180
+ resolved_by = models.ForeignKey(
181
+ settings.AUTH_USER_MODEL,
182
+ on_delete=models.SET_NULL,
183
+ null=True,
184
+ blank=True,
185
+ related_name="+",
186
+ help_text="Workspace admin who requeued or dropped this task.",
187
+ )
188
+ resolved_at = models.DateTimeField(
189
+ null=True,
190
+ blank=True,
191
+ help_text="When an operator requeued or dropped this task.",
192
+ )
193
+
194
+ class Meta:
195
+ ordering = ["-last_failed_at"]
196
+ indexes = [
197
+ models.Index(fields=["status", "last_failed_at"], name="failed_task_status_idx"),
198
+ ]
199
+
200
+ def __str__(self) -> str:
201
+ return f"{self.task_name} ({self.task_id}) — {self.status}"
202
+
203
+
204
+ class VelocitySuggestion(models.Model):
205
+ """Non-destructive duration recommendation generated on sprint close (ADR-0065).
206
+
207
+ When a sprint closes, the drain computes a rolling 6-sprint team velocity
208
+ (``completed_points / sprint_working_days``) and, for tasks in the closing
209
+ sprint with ``story_points`` set, records a suggested
210
+ ``most_likely_duration = story_points / team_velocity_per_day`` here. The
211
+ PM accepts or dismisses each suggestion from the Task Detail Drawer; the
212
+ underlying ``Task.most_likely_duration`` is never overwritten without
213
+ explicit consent so PM-committed baselines stay intact and the
214
+ accept/dismiss history is auditable per (task, sprint).
215
+
216
+ A unique constraint on (task, sprint) makes the sprint-close drain
217
+ idempotent: a duplicate run upserts the row rather than producing
218
+ duplicate prompts.
219
+
220
+ Not synced to mobile clients — surfaces only in the PM-facing Task Detail
221
+ Drawer.
222
+ """
223
+
224
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
225
+ task = models.ForeignKey(
226
+ "projects.Task",
227
+ on_delete=models.CASCADE,
228
+ related_name="velocity_suggestions",
229
+ )
230
+ sprint = models.ForeignKey(
231
+ "projects.Sprint",
232
+ on_delete=models.CASCADE,
233
+ related_name="velocity_suggestions",
234
+ )
235
+ # Suggested most_likely_duration in working days. Stored as integer to match
236
+ # Task.most_likely_duration; rounding happens in the service layer.
237
+ suggested_duration = models.PositiveIntegerField()
238
+ team_velocity_per_day = models.DecimalField(
239
+ max_digits=6,
240
+ decimal_places=3,
241
+ help_text="Rolling 6-sprint average of completed_points / sprint_working_days.",
242
+ )
243
+ # When estimation_mode=SUGGEST_APPROVE the suggestion is flagged so the
244
+ # governance review surface can route the accept decision through a
245
+ # Scheduler-role user; in OPEN and PM_ONLY modes any PM may accept directly.
246
+ flag_for_review = models.BooleanField(default=False)
247
+ created_at = models.DateTimeField(auto_now_add=True)
248
+ # Exactly one of accepted_at / dismissed_at is non-null at a time; the
249
+ # other stays null. The pair encodes the PM decision lifecycle without an
250
+ # extra status enum (similar to the actual_start / actual_finish pattern).
251
+ accepted_at = models.DateTimeField(null=True, blank=True)
252
+ accepted_by = models.ForeignKey(
253
+ settings.AUTH_USER_MODEL,
254
+ on_delete=models.SET_NULL,
255
+ null=True,
256
+ blank=True,
257
+ related_name="accepted_velocity_suggestions",
258
+ )
259
+ dismissed_at = models.DateTimeField(null=True, blank=True)
260
+ dismissed_by = models.ForeignKey(
261
+ settings.AUTH_USER_MODEL,
262
+ on_delete=models.SET_NULL,
263
+ null=True,
264
+ blank=True,
265
+ related_name="dismissed_velocity_suggestions",
266
+ )
267
+
268
+ class Meta:
269
+ ordering = ["-created_at"]
270
+ constraints = [
271
+ models.UniqueConstraint(
272
+ fields=["task", "sprint"],
273
+ name="unique_velocity_suggestion_per_task_sprint",
274
+ ),
275
+ ]
276
+ indexes = [
277
+ # Pending suggestions for a task — the Task Detail Drawer query.
278
+ models.Index(
279
+ fields=["task", "accepted_at", "dismissed_at"],
280
+ name="velocity_sugg_task_pending_idx",
281
+ ),
282
+ ]
283
+
284
+ def __str__(self) -> str:
285
+ return f"VelocitySuggestion(task={self.task_id}, sprint={self.sprint_id})"
286
+
287
+ @property
288
+ def project_id(self) -> object:
289
+ """Expose the task's project_id so _get_project_id_from_obj can find it.
290
+
291
+ Required for IsProjectAdmin.has_object_permission to resolve the project
292
+ context when DRF's get_object() runs check_object_permissions on a
293
+ VelocitySuggestion (no direct FK to Project). Mirrors the same pattern
294
+ used by resources.TaskResource.
295
+ """
296
+ return self.task.project_id
297
+
298
+ @property
299
+ def is_pending(self) -> bool:
300
+ """True when neither accepted nor dismissed — pending PM decision."""
301
+ return self.accepted_at is None and self.dismissed_at is None
302
+
303
+
304
+ class MonteCarloRun(models.Model):
305
+ """One persisted project-level Monte Carlo simulation run (ADR-0175, #961).
306
+
307
+ Written synchronously per ``POST /projects/<pk>/monte-carlo/`` run so the PM
308
+ can read finish-date forecast *drift* over time ("my P80 was Aug 14 two weeks
309
+ ago, now Aug 28"). Distinct from ``projects.ForecastSnapshot`` (ADR-0106 §5),
310
+ which is milestone-scoped, latest-per-milestone, and carries the velocity
311
+ -privacy band — this model is the explicit project-level CPM Monte Carlo run
312
+ history and stores P95 (which ForecastSnapshot does not).
313
+
314
+ A plain ``models.Model`` (not a ``VersionedModel``) — display/forecast
315
+ metadata, consistent with ``ForecastSnapshot`` / ``VelocitySuggestion``; not
316
+ on the mobile sync surface (Monte Carlo requires server compute, so history
317
+ is an online read).
318
+
319
+ Retention is the OSS cap applied to run *count*: a nightly purge keeps the
320
+ newest ``settings.MC_HISTORY_CAP`` rows per project (Enterprise overrides to
321
+ ``None`` = unlimited). Bounded history, never unlimited — the portfolio /
322
+ cross-program rollup is the Enterprise upsell (ADR-0175).
323
+ """
324
+
325
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
326
+ project = models.ForeignKey(
327
+ _PROJECT_MODEL,
328
+ on_delete=models.CASCADE,
329
+ related_name="monte_carlo_runs",
330
+ )
331
+ taken_at = models.DateTimeField(auto_now_add=True)
332
+ # SET_NULL + null: account deletion never cascades away forecast history, and
333
+ # the attribution is optional metadata. Serialized ONLY to Admin/Owner so
334
+ # forecast drift cannot become a named-individual performance signal at the
335
+ # team level (ADR-0175 / VoC Morgan). related_name="+": no reverse accessor
336
+ # needed (we never list a user's runs).
337
+ triggered_by = models.ForeignKey(
338
+ settings.AUTH_USER_MODEL,
339
+ on_delete=models.SET_NULL,
340
+ null=True,
341
+ blank=True,
342
+ related_name="+",
343
+ )
344
+ # The probabilistic finish-date percentiles as of this run. Nullable: a
345
+ # project with no committed tasks yields no distribution to anchor on.
346
+ p50 = models.DateField(null=True, blank=True)
347
+ p80 = models.DateField(null=True, blank=True)
348
+ p95 = models.DateField(null=True, blank=True)
349
+ # The deterministic CPM spine at run time (max early_finish of committed
350
+ # tasks), kept for context alongside the probabilistic band.
351
+ cpm_finish = models.DateField(null=True, blank=True)
352
+ # Inputs needed to interpret the run.
353
+ n_simulations = models.PositiveIntegerField()
354
+ task_count = models.PositiveIntegerField(null=True, blank=True)
355
+ # The full per-run distribution payload — the same
356
+ # ``{histogram_buckets, confidence_curve, sensitivity}`` shape written to the
357
+ # ``mc_latest`` cache (#1231, ADR-0144; key built by
358
+ # ``views.mc_latest_cache_key``). Persisted so the histogram +
359
+ # tornado survive cache expiry and a past run stays re-viewable.
360
+ #
361
+ # Nullable with NO backfill: pre-0143 runs have no stored distribution and the
362
+ # frontend renders the empty-state prose for them (legacy runs are a tail that
363
+ # ages out under the retention cap). Capped at MC_DISTRIBUTION_MAX_BYTES with
364
+ # bucket down-sampling at persist time (the cache copy stays full) so a
365
+ # pathological high-bucket run cannot bloat the row.
366
+ distribution = models.JSONField(null=True, blank=True)
367
+ # Why this run has — or lacks — an uncertainty band: the
368
+ # ``{deterministic, reason, tasks_total, tasks_with_variance, ...}`` payload
369
+ # from :func:`forecast_diagnostic` (#1340), persisted with the run (#2483).
370
+ #
371
+ # Load-bearing for the "added time" metric, not merely informational. A flat
372
+ # run yields a premium of exactly 0 days, and a project with no three-point
373
+ # estimates is always flat — so without the reason code a structural zero is
374
+ # indistinguishable from a measured zero, and Overview would tell an
375
+ # unestimated project it carries no schedule risk. Re-deriving the reason at
376
+ # read time would mean loading every committed task on a hot endpoint, so the
377
+ # run carries its own.
378
+ #
379
+ # Nullable with NO backfill: runs recorded before #2483 have no diagnostic and
380
+ # the frontend falls back to the measured presentation with the band collapsed
381
+ # (it never guesses "unmeasurable" from a missing reason).
382
+ diagnostic = models.JSONField(null=True, blank=True)
383
+ # The data date this run was actually computed against — ADR-0132 floors a null
384
+ # ``Project.status_date`` at "today" for Monte Carlo (never forecast remaining
385
+ # work in the past), but that substitution used to happen only in memory and was
386
+ # never recorded, so a past run could not be re-derived and two runs of an
387
+ # unchanged project on different days returned different percentiles with nothing
388
+ # in the row explaining why (#2638). ADR-0132's Implementation Notes already
389
+ # called this out as "additive on ADR-0175" when this model was designed; it
390
+ # simply never landed until now.
391
+ #
392
+ # Nullable with NO backfill, same pattern as ``distribution``/``diagnostic``:
393
+ # runs recorded before #2638 have no stored data date and read back as
394
+ # ``status_date: null`` rather than a guessed value.
395
+ status_date = models.DateField(null=True, blank=True)
396
+ # The plan version this run was computed against — the project's
397
+ # ``last_sync_version`` (ADR-0686) read *before* the task set was loaded (#3140).
398
+ #
399
+ # This is what makes "is the forecast still about the current plan?" a server fact
400
+ # instead of a client guess. Compared against the project's live value at response
401
+ # time by :mod:`.forecast_staleness`; a difference means the plan has been written to
402
+ # since the run. The web forecast bar previously answered the same question with a
403
+ # session-local mutation counter, which missed every write path but one and reset on
404
+ # reload — and once #3132 gated the Rerun *action* on it, a stale forecast could
405
+ # offer no recompute at all.
406
+ #
407
+ # Read before the tasks, not after, and the ordering is the correctness property: a
408
+ # write landing mid-simulation then leaves ``plan_version`` behind the project's
409
+ # value, so the run reads stale. Capturing it afterwards would claim the run covered
410
+ # a write it never saw — false-fresh, which is the direction that loses the action.
411
+ #
412
+ # Nullable with NO backfill, the same pattern as ``distribution``/``diagnostic``/
413
+ # ``status_date`` above: runs recorded before #3140 have no plan version and classify
414
+ # as ``unknown`` rather than a guessed ``current``. No index — this model is only ever
415
+ # read as "newest row for this project", which ``mcrun_project_recent_idx`` covers.
416
+ plan_version = models.BigIntegerField(null=True, blank=True)
417
+
418
+ class Meta:
419
+ db_table = "scheduling_montecarlorun"
420
+ ordering = ["-taken_at"]
421
+ indexes = [
422
+ # Newest-first history read + the nightly rank-based purge.
423
+ models.Index(fields=["project", "-taken_at"], name="mcrun_project_recent_idx"),
424
+ ]
425
+
426
+ def __str__(self) -> str:
427
+ return f"MonteCarloRun(project={self.project_id} @ {self.taken_at:%Y-%m-%d})"
428
+
429
+
430
+ class ForecastSnapshotTrigger(models.TextChoices):
431
+ """What caused a ``ProjectForecastSnapshot`` to be captured."""
432
+
433
+ RECOMPUTE = "recompute", "Recompute"
434
+ SCHEDULED = "scheduled", "Scheduled"
435
+ MANUAL = "manual", "Manual"
436
+
437
+
438
+ class ProjectForecastSnapshot(models.Model):
439
+ """One project-grain forecast point-in-time, captured on each recompute (ADR-0154, #388).
440
+
441
+ The continuous record of how a project's *whole-project* forecast drifts over
442
+ time — "we were saying end of June a month ago, now we're saying end of August".
443
+ Written best-effort after every CPM recompute (plus a daily floor) so ~30 days of
444
+ real history accrue before the forecast-trend chart (#368) and history-aware
445
+ sample loader (#376) consume it.
446
+
447
+ Distinct from the two adjacent forecast-history models, and deliberately not a
448
+ merge of either:
449
+
450
+ * ``projects.ForecastSnapshot`` (ADR-0106 §5) is *milestone*-grain,
451
+ latest-per-milestone, and carries a velocity-privacy band — a different read
452
+ contract. (Its FK already owns ``related_name="forecast_snapshots"`` on
453
+ Project, which is why this model uses ``project_forecast_snapshots``.)
454
+ * ``MonteCarloRun`` (ADR-0175) is written only when a user *explicitly* runs
455
+ Monte Carlo and is capped to the newest N runs — it never captures CPM-finish
456
+ drift on a project that has never been simulated, and its flat cap drops the
457
+ long tail the trend chart needs.
458
+
459
+ This model is CPM-primary: ``cpm_finish``/``total_float_days`` come from the
460
+ just-recomputed schedule, while the Monte Carlo percentiles are copied
461
+ best-effort from the project's most-recent ``MonteCarloRun`` (so the MC line
462
+ stays flat — truthfully — until someone reruns MC).
463
+
464
+ A plain ``models.Model`` (not a ``VersionedModel``) with no ``server_version``
465
+ and not on the mobile sync surface — consistent with ``MonteCarloRun`` /
466
+ ``ForecastSnapshot``; this is a high-churn, server-generated, online-read-only
467
+ history table with no mobile consumer (ADR-0154 §2).
468
+ """
469
+
470
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
471
+ project = models.ForeignKey(
472
+ _PROJECT_MODEL,
473
+ on_delete=models.CASCADE,
474
+ related_name="project_forecast_snapshots",
475
+ )
476
+ captured_at = models.DateTimeField(auto_now_add=True)
477
+ triggered_by = models.CharField(
478
+ max_length=16,
479
+ choices=ForecastSnapshotTrigger.choices,
480
+ default=ForecastSnapshotTrigger.RECOMPUTE,
481
+ )
482
+ # Every aggregate below is over ``Task.committed`` — the population CPM is
483
+ # actually run on — never over all non-deleted tasks (#3539). A BACKLOG/EPIC/
484
+ # recurring row is never scheduled, so any early_finish/total_float it carries
485
+ # is scheduling output left over from before it was groomed out, and admitting
486
+ # it here reports a forecast for a schedule that was never computed.
487
+ #
488
+ # Deterministic CPM spine at capture time: the project's latest committed task
489
+ # finish. Nullable — a project with no scheduled tasks has no finish to anchor on.
490
+ cpm_finish = models.DateField(null=True, blank=True)
491
+ # The tightest total float (minimum across the committed set): 0 on an
492
+ # unconstrained critical path, negative when a deadline/constraint is breached —
493
+ # so drift in schedule *pressure* is visible, not just the finish date.
494
+ total_float_days = models.IntegerField(null=True, blank=True)
495
+ # Probabilistic finish-date percentiles, copied best-effort from the project's
496
+ # most-recent MonteCarloRun at capture time. Null when MC has never run; may
497
+ # predate this capture (no newer probabilistic data exists to report).
498
+ mc_p50_finish = models.DateField(null=True, blank=True)
499
+ mc_p80_finish = models.DateField(null=True, blank=True)
500
+ mc_p95_finish = models.DateField(null=True, blank=True)
501
+ mc_iterations = models.PositiveIntegerField(null=True, blank=True)
502
+ # Schedule shape at capture time — context for interpreting the forecast, and
503
+ # therefore counted over the same committed population as cpm_finish above.
504
+ task_count = models.PositiveIntegerField(default=0)
505
+ completed_task_count = models.PositiveIntegerField(default=0)
506
+
507
+ class Meta:
508
+ db_table = "scheduling_projectforecastsnapshot"
509
+ ordering = ["-captured_at"]
510
+ indexes = [
511
+ # Newest-first history read + the per-project tiered prune scan.
512
+ models.Index(fields=["project", "-captured_at"], name="projfcast_proj_recent_idx"),
513
+ ]
514
+
515
+ def __str__(self) -> str:
516
+ return f"ProjectForecastSnapshot(project={self.project_id} @ {self.captured_at:%Y-%m-%d})"
@@ -0,0 +1,160 @@
1
+ """OSS signal receivers for the scheduling app.
2
+
3
+ The default dead-letter alerting receiver (ADR-0084). When a Celery task is
4
+ permanently dead-lettered, OSS emits a single structured WARNING line that an
5
+ operator (or a log-based metrics aggregator) can alert on. Enterprise registers
6
+ *additional* receivers on the same signal for PagerDuty/Slack in its own
7
+ AppConfig.ready() — this module is never imported by enterprise and imports
8
+ nothing from it.
9
+
10
+ Also holds the start/success/retry structured-log receivers (#1917) that
11
+ complement the dead-letter alert above — each Celery task's full lifecycle
12
+ (started → succeeded, or started → retried → ... → dead-lettered) is now a
13
+ structured, greppable/aggregatable log line rather than the ad-hoc
14
+ ``logger.info`` calls scattered across individual task bodies.
15
+
16
+ Wired by SchedulingConfig.ready() via ``from . import receivers``.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import logging
22
+ from typing import Any
23
+
24
+ from django.dispatch import receiver
25
+
26
+ from trueppm_api.apps.scheduling.signals import (
27
+ celery_task_permanently_failed,
28
+ celery_task_retried,
29
+ celery_task_started,
30
+ celery_task_succeeded,
31
+ )
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ @receiver(celery_task_permanently_failed)
37
+ def log_dead_letter_alert(
38
+ sender: Any,
39
+ task_id: str = "",
40
+ task_name: str = "",
41
+ exception: BaseException | None = None,
42
+ project_id: str | None = None,
43
+ **_kwargs: Any,
44
+ ) -> None:
45
+ """Emit a WARNING alert line for a newly dead-lettered task.
46
+
47
+ Distinct from the ERROR line in ``record_failed_task`` (which records the
48
+ raw failure): this is the *alert*, carrying structured ``extra`` fields so
49
+ log pipelines can build the ``trueppm_task_dead_letter_count`` series by
50
+ ``task_name`` without parsing the message. Broad ``except`` because an
51
+ alerting failure must never propagate back into the dead-letter path — the
52
+ signal is dispatched with ``send_robust`` for the same reason, so this is
53
+ belt-and-braces against a logging-config error masking a task failure.
54
+ """
55
+ try:
56
+ logger.warning(
57
+ "dead-letter alert: task %s (%s) permanently failed: %s",
58
+ task_name,
59
+ task_id,
60
+ type(exception).__qualname__ if exception is not None else "unknown",
61
+ extra={
62
+ "task_name": task_name,
63
+ "task_id": task_id,
64
+ "exception_type": (
65
+ type(exception).__qualname__ if exception is not None else "unknown"
66
+ ),
67
+ "project_id": project_id,
68
+ },
69
+ )
70
+ except Exception:
71
+ logger.exception("dead-letter alert receiver failed")
72
+
73
+
74
+ @receiver(celery_task_started)
75
+ def log_task_started(
76
+ sender: Any,
77
+ task_id: str = "",
78
+ task_name: str = "",
79
+ **_kwargs: Any,
80
+ ) -> None:
81
+ """Emit a structured INFO line when a Celery task begins execution (#1917).
82
+
83
+ Bridged from the ``task_prerun`` framework signal in
84
+ ``SchedulingConfig.ready()`` for every task in the process. Broad ``except``
85
+ (matching ``log_dead_letter_alert``): this is bridged via a plain (not
86
+ ``send_robust``) Django signal fired synchronously inside the worker's task
87
+ execution path, so a logging-config error here must never surface as (or
88
+ interrupt) a task failure.
89
+ """
90
+ try:
91
+ logger.info(
92
+ "task started: %s (%s)",
93
+ task_name,
94
+ task_id,
95
+ extra={"task_name": task_name, "task_id": task_id, "outcome": "started"},
96
+ )
97
+ except Exception:
98
+ logger.exception("task-started log receiver failed")
99
+
100
+
101
+ @receiver(celery_task_succeeded)
102
+ def log_task_succeeded(
103
+ sender: Any,
104
+ task_id: str = "",
105
+ task_name: str = "",
106
+ runtime_seconds: float = 0.0,
107
+ **_kwargs: Any,
108
+ ) -> None:
109
+ """Emit a structured INFO line when a Celery task completes successfully (#1917)."""
110
+ try:
111
+ logger.info(
112
+ "task succeeded: %s (%s) in %.3fs",
113
+ task_name,
114
+ task_id,
115
+ runtime_seconds,
116
+ extra={
117
+ "task_name": task_name,
118
+ "task_id": task_id,
119
+ "outcome": "succeeded",
120
+ "runtime_seconds": runtime_seconds,
121
+ },
122
+ )
123
+ except Exception:
124
+ logger.exception("task-succeeded log receiver failed")
125
+
126
+
127
+ @receiver(celery_task_retried)
128
+ def log_task_retried(
129
+ sender: Any,
130
+ task_id: str = "",
131
+ task_name: str = "",
132
+ attempt: int = 0,
133
+ exception: BaseException | None = None,
134
+ **_kwargs: Any,
135
+ ) -> None:
136
+ """Emit a structured WARNING line when a Celery task is about to be retried (#1917).
137
+
138
+ Distinct from ``log_dead_letter_alert``: this fires on *every* retry attempt
139
+ (the task will run again), the dead-letter alert fires once, only on the
140
+ terminal transition after retries are exhausted.
141
+ """
142
+ try:
143
+ logger.warning(
144
+ "task retry: %s (%s) attempt %s: %s",
145
+ task_name,
146
+ task_id,
147
+ attempt,
148
+ exception,
149
+ extra={
150
+ "task_name": task_name,
151
+ "task_id": task_id,
152
+ "outcome": "retried",
153
+ "attempt": attempt,
154
+ "exception_type": (
155
+ type(exception).__qualname__ if exception is not None else "unknown"
156
+ ),
157
+ },
158
+ )
159
+ except Exception:
160
+ logger.exception("task-retried log receiver failed")