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,273 @@
1
+ """Development settings — DEBUG on, relaxed auth, local service URLs.
2
+
3
+ This module is fenced by ``_assert_dev_environment_safe`` because it sets
4
+ ``AllowAny`` and ``ALLOWED_HOSTS=['*']`` — loading it in staging or production
5
+ would silently disable authentication on every endpoint. The guard fails loudly
6
+ at import time unless the process is a test runner or the operator has
7
+ explicitly opted in via ``TRUEPPM_ALLOW_DEV_SETTINGS=1``.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import os
13
+ import sys
14
+ from collections.abc import Mapping
15
+ from pathlib import Path
16
+ from typing import Any
17
+
18
+ import environ
19
+
20
+
21
+ def _assert_dev_environment_safe(
22
+ env: Mapping[str, str] | None = None,
23
+ modules: Mapping[str, Any] | None = None,
24
+ ) -> None:
25
+ """Refuse to load dev settings outside a test runner or developer workstation.
26
+
27
+ Four signals permit the load, in order of precedence:
28
+ 1. ``PYTEST_CURRENT_TEST`` is set in the environment (pytest is active)
29
+ 2. ``pytest`` is already imported in the running process (test collection)
30
+ 3. ``mypy`` is already imported (django-stubs imports settings under mypy)
31
+ 4. ``TRUEPPM_ALLOW_DEV_SETTINGS=1`` is set (explicit developer opt-in)
32
+
33
+ Any other environment — staging, production, an unconfigured Docker image —
34
+ raises ``RuntimeError`` to prevent the module from completing its import and
35
+ overriding ``DEFAULT_PERMISSION_CLASSES`` with ``AllowAny``.
36
+
37
+ Args are injectable so the assertion can be unit-tested without mutating the
38
+ real environment or the global module table.
39
+ """
40
+ env = env if env is not None else os.environ
41
+ modules = modules if modules is not None else sys.modules
42
+
43
+ if env.get("PYTEST_CURRENT_TEST"):
44
+ return
45
+ if "pytest" in modules or "mypy" in modules:
46
+ return
47
+ if env.get("TRUEPPM_ALLOW_DEV_SETTINGS") == "1":
48
+ return
49
+
50
+ raise RuntimeError(
51
+ "trueppm_api.settings.dev was loaded outside local dev or a test runner. "
52
+ "This module sets AllowAny and ALLOWED_HOSTS=['*'] — refusing to import. "
53
+ "Set TRUEPPM_ALLOW_DEV_SETTINGS=1 to override on a developer workstation."
54
+ )
55
+
56
+
57
+ _assert_dev_environment_safe()
58
+
59
+
60
+ from .base import * # noqa: F403, E402
61
+ from .base import BASE_DIR, DATABASES, REST_FRAMEWORK # noqa: E402
62
+
63
+ env = environ.Env()
64
+
65
+ # Read .env file if present (optional in dev)
66
+ environ.Env.read_env(env_file=".env", overwrite=False)
67
+
68
+ DEBUG = True
69
+
70
+ ALLOWED_HOSTS = ["*"]
71
+
72
+ # Deterministic Fernet key for dev / pytest only — never use this value in
73
+ # staging or production. The dev settings module is fenced by
74
+ # _assert_dev_environment_safe above; production reads its key from a
75
+ # Kubernetes Secret via the Helm chart and never falls through to this default.
76
+ INTEGRATION_ENCRYPTION_KEY = "cNHot7PnbAHGIuY4zUht8FwB5wYGv06O7ppzGyhzR84="
77
+
78
+ # In dev, allow unauthenticated access to the API for ease of local testing.
79
+ # Throttle classes/rates are inherited from base settings via the spread below;
80
+ # this dev-only module merely relaxes the permission classes. Fenced by
81
+ # _assert_dev_environment_safe — never loaded in staging or production.
82
+ REST_FRAMEWORK = { # nosemgrep: missing-throttle-config
83
+ **REST_FRAMEWORK, # nosemgrep: missing-throttle-config
84
+ "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.AllowAny"],
85
+ # Re-add SessionAuthentication on top of base's posture (#2248) so the test
86
+ # suite's `client.force_login()` populates request.user without minting a JWT.
87
+ # Never loaded in staging/prod (fenced by _assert_dev_environment_safe). Keeps
88
+ # base's OwnerScopedApiTokenAuthentication entry (#2547) so PAT-authenticated
89
+ # requests in the test suite exercise the real production auth wiring.
90
+ "DEFAULT_AUTHENTICATION_CLASSES": [
91
+ "trueppm_api.apps.projects.authentication.OwnerScopedApiTokenAuthentication",
92
+ "rest_framework_simplejwt.authentication.JWTAuthentication",
93
+ "rest_framework.authentication.SessionAuthentication",
94
+ ],
95
+ }
96
+
97
+ # The refresh cookie must work over plain HTTP on localhost — a Secure cookie is
98
+ # dropped by the browser on http://. Production keeps the base default (True).
99
+ AUTH_REFRESH_COOKIE_SECURE = False
100
+
101
+ # Django admin is ON in dev and OFF everywhere else (#3557). base.py defaults it
102
+ # to False so that a production deploy that sets nothing does not expose a second
103
+ # password door; a developer workstation is the one place where reaching /admin/
104
+ # with no ceremony is the point. Still env-overridable, so `pytest` can assert the
105
+ # disabled behavior through the same variable an operator would set. This module
106
+ # is fenced by _assert_dev_environment_safe above, so the relaxation cannot load
107
+ # in staging or production.
108
+ DJANGO_ADMIN_ENABLED = env.bool("TRUEPPM_DJANGO_ADMIN_ENABLED", default=True)
109
+
110
+ # base.py defaults MEDIA_ROOT to /var/lib/trueppm/media — the path the chart and
111
+ # compose mount a writable volume at (#3184). Nothing creates that path on a
112
+ # developer workstation, and pytest runs under this module, so keep uploads
113
+ # inside the checkout. BASE_DIR is packages/api/src, so `.parent` lands on
114
+ # packages/api/media/, which .gitignore has already carried since #817.
115
+ MEDIA_ROOT = Path(env("TRUEPPM_MEDIA_ROOT", default=str(BASE_DIR.parent / "media")))
116
+
117
+ # WhiteNoise (base.py MIDDLEWARE) serves static from STATIC_ROOT, which requires a
118
+ # `collectstatic` run. In dev and under pytest we want /static/ to work without
119
+ # that step, so serve straight from the staticfiles *finders* (each app's static/
120
+ # dir, including drf-spectacular-sidecar's bundles) and re-scan on every request so
121
+ # newly added files appear without a restart. Production keeps the base behavior:
122
+ # collectstatic into STATIC_ROOT, which WhiteNoise serves with far-future caching.
123
+ WHITENOISE_USE_FINDERS = True
124
+ WHITENOISE_AUTOREFRESH = True
125
+
126
+ # Local dev / pytest run in a single process, so per-process memory is a
127
+ # sufficient (and dependency-free) cache for the OIDC login state and the DRF
128
+ # throttles. Production uses the Redis-backed cache from base.py. Overriding here
129
+ # keeps `pytest` from requiring a separate Valkey cache db (the testcontainers
130
+ # fixture provisions PostgreSQL only).
131
+ CACHES = {
132
+ "default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"},
133
+ }
134
+
135
+
136
+ # Detailed SQL logging in dev.
137
+ #
138
+ # This override replaces base.py's build_logging_config() output entirely, so the
139
+ # UTC-timestamp fix in that function (#1952) does not reach dev. That is fine and
140
+ # intentional: these handlers declare no "formatter", so they use logging's
141
+ # default (message-only) formatter, which emits no %(asctime)s at all — there is
142
+ # no log timestamp here to render in the wrong timezone. If a formatter with
143
+ # %(asctime)s is ever added to this dev config, mirror the base fix
144
+ # (logging.Formatter.converter = time.gmtime) so dev timestamps stay UTC too.
145
+ LOGGING = {
146
+ "version": 1,
147
+ "disable_existing_loggers": False,
148
+ "handlers": {
149
+ "console": {"class": "logging.StreamHandler"},
150
+ },
151
+ "root": {
152
+ "handlers": ["console"],
153
+ "level": "WARNING",
154
+ },
155
+ "loggers": {
156
+ "django.db.backends": {
157
+ "handlers": ["console"],
158
+ "level": env("SQL_LOG_LEVEL", default="WARNING"),
159
+ "propagate": False,
160
+ },
161
+ },
162
+ }
163
+
164
+ # ---------------------------------------------------------------------------
165
+ # CI test-DB prewarm (#688)
166
+ # ---------------------------------------------------------------------------
167
+ # When the api:test CI shards have loaded a `migrated` template database from
168
+ # the schema dump produced by api:testdb-dump, clone each pytest-xdist worker
169
+ # DB from it (CREATE DATABASE ... TEMPLATE, a fast file copy) and skip the
170
+ # per-worker migration replay. The template already carries the ltree
171
+ # extension, the wbs_path GiST index, and the data backfills, so this is
172
+ # equivalent to a full migrate — unlike --no-migrations, which skips the
173
+ # RunSQL that creates the ltree extension and breaks test-DB creation.
174
+ #
175
+ # Gated on the CI-set env var: a local `pytest` run (no `migrated` template
176
+ # present) leaves DATABASES untouched and builds its test DB by replaying
177
+ # migrations exactly as before. This is test-only — the TEST sub-dict is read
178
+ # solely by Django's test-database creation, never by a running server.
179
+ _test_db_template = os.environ.get("TRUEPPM_TEST_DB_TEMPLATE")
180
+ if _test_db_template:
181
+ DATABASES["default"].setdefault("TEST", {})
182
+ DATABASES["default"]["TEST"]["TEMPLATE"] = _test_db_template
183
+ DATABASES["default"]["TEST"]["MIGRATE"] = False
184
+
185
+ # ---------------------------------------------------------------------------
186
+ # Per-worktree test DB (scripts/wt)
187
+ # ---------------------------------------------------------------------------
188
+ # `scripts/wt new` writes TRUEPPM_TEST_DB=test_trueppm_wt_<slug> into each
189
+ # worktree's .envrc so N parallel worktrees each create and drop their OWN test
190
+ # database instead of racing on one shared `test_trueppm`. This removes the need
191
+ # for the out-of-band flock mutex that serialized parallel pytest runs (and that
192
+ # flock(1) can't provide on macOS). Test-only: like TEST["TEMPLATE"] above, the
193
+ # TEST["NAME"] key is read solely by Django's test-database creation, never by a
194
+ # running server.
195
+
196
+
197
+ def _apply_test_db_name(databases: dict[str, Any], env: Mapping[str, str]) -> None:
198
+ """Point Django's test-DB creation at a per-worktree database, if requested.
199
+
200
+ Reads ``TRUEPPM_TEST_DB`` from ``env`` and, when set, writes it to
201
+ ``databases["default"]["TEST"]["NAME"]`` so a worktree's ``pytest`` run builds
202
+ an isolated test database instead of racing on the shared one. A no-op when the
203
+ variable is unset or empty. ``databases``/``env`` are injectable so the logic
204
+ is unit-testable without reloading the settings module or mutating the process
205
+ environment (mirrors ``_assert_dev_environment_safe``).
206
+ """
207
+ name = env.get("TRUEPPM_TEST_DB")
208
+ if not name:
209
+ return
210
+ databases["default"].setdefault("TEST", {})
211
+ databases["default"]["TEST"]["NAME"] = name
212
+
213
+
214
+ _apply_test_db_name(DATABASES, os.environ)
215
+
216
+
217
+ # ---------------------------------------------------------------------------
218
+ # Fast password hashing under pytest (#3391)
219
+ # ---------------------------------------------------------------------------
220
+ # Django 5.2 defaults to PBKDF2-SHA256 at 1,000,000 iterations. That cost is the
221
+ # whole point in production and pure waste in the test suite, which makes 1,054
222
+ # `create_user(..., password=...)` calls and asserts nothing about hash strength.
223
+ # Measured: 76.3ms per PBKDF2 hash vs 0.026ms for MD5 — 2,899x, several minutes
224
+ # of every api:test run spent proving nothing.
225
+ #
226
+ # Gated on pytest actually being loaded rather than applied to all of dev: a
227
+ # local `runserver` keeps the production hasher, so a developer never logs in
228
+ # against a weaker algorithm than the one they ship. `"pytest" in sys.modules`
229
+ # is ONE of the four signals `_assert_dev_environment_safe` trusts above, not
230
+ # the same test — that guard also accepts PYTEST_CURRENT_TEST from the env,
231
+ # which this deliberately does not, because it is set per test rather than at
232
+ # settings-import time. The gap is worth naming: a subprocess spawned from a
233
+ # test inherits PYTEST_CURRENT_TEST but not the parent's module table, so it
234
+ # would load PBKDF2 while its parent used MD5, and a cross-process
235
+ # check_password against an md5 hash would raise "Unknown password hashing
236
+ # algorithm". Latent, not live — the suite's only subprocess use is a mocked
237
+ # Popen — but a future test that really shells out has to know this.
238
+ #
239
+ # Where settings.dev actually loads, so the next reader does not have to guess:
240
+ # the local compose stack (docker-compose.yml, three services, which set
241
+ # TRUEPPM_ALLOW_DEV_SETTINGS=1), every api:* CI job, the Makefile, and
242
+ # scripts/export-openapi.sh — plus pytest. It is routine infrastructure, not a
243
+ # rare manual opt-in. The branch is unreachable in all of those but pytest for
244
+ # one reason: packages/api/Dockerfile installs `api[c]`/`api[binary]` and never
245
+ # `api[dev]`, and uninstalls pip, so the runtime image has no pytest to import.
246
+ # Every deployed path (helm values, docker-compose.prod, docker-compose.demo)
247
+ # loads settings.prod and never reaches this file at all.
248
+ #
249
+ # The list is deliberately a SINGLE entry. Adding PBKDF2 back as a fallback
250
+ # looks safer and is not: `hasher_changed` would then be True on every login, so
251
+ # check_password's setter fires and ModelBackend REWRITES stored PBKDF2 hashes
252
+ # as MD5. One entry fails those rows closed instead of silently downgrading them.
253
+ #
254
+ # DX note: with --reuse-db, a test database created before this change still
255
+ # holds PBKDF2 hashes, which no longer verify (Django catches the unknown-hasher
256
+ # ValueError and returns False rather than raising). That reads as an auth
257
+ # regression; it is a stale test DB. Use --create-db once.
258
+ #
259
+ # Asserted by tests/test_password_hashers.py, including the invariant this
260
+ # gate rests on: nothing under src/ may import pytest.
261
+
262
+
263
+ def _use_fast_password_hashers(modules: Mapping[str, Any]) -> bool:
264
+ """Report whether the test-only fast password hasher should be installed.
265
+
266
+ Injectable so the predicate is unit-testable without mutating the global
267
+ module table (mirrors ``_assert_dev_environment_safe``).
268
+ """
269
+ return "pytest" in modules
270
+
271
+
272
+ if _use_fast_password_hashers(sys.modules):
273
+ PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
@@ -0,0 +1,228 @@
1
+ """Production settings — security hardened, secrets from environment."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import urllib.parse
7
+
8
+ import environ
9
+
10
+ from trueppm_api.apps.observability.logging import build_logging_config
11
+ from trueppm_api.core.security_checks import (
12
+ validate_allowed_hosts,
13
+ validate_attachment_storage,
14
+ validate_integration_encryption_key,
15
+ validate_project_soft_delete_retention,
16
+ validate_secret_key,
17
+ validate_service_credentials,
18
+ validate_signing_key,
19
+ )
20
+
21
+ from .base import * # noqa: F403
22
+ from .base import (
23
+ ALLOW_LOCAL_ATTACHMENT_STORAGE,
24
+ ALLOW_UNENCRYPTED_DB,
25
+ ALLOW_WILDCARD_ALLOWED_HOSTS,
26
+ DATABASES,
27
+ DJANGO_LOG_LEVEL,
28
+ INTEGRATION_ENCRYPTION_KEY,
29
+ MEDIA_ROOT,
30
+ REDIS_URL,
31
+ SIMPLE_JWT,
32
+ STORAGES,
33
+ TRUEPPM_PROJECT_SOFT_DELETE_RETENTION_DAYS,
34
+ )
35
+
36
+ env = environ.Env()
37
+
38
+ DEBUG = False
39
+
40
+ # Prefix for every import-time boot-guard failure below.
41
+ _REFUSING_TO_START = "Refusing to start: "
42
+
43
+ # Force single-line JSON logs in production so a collector (Loki/ELK/CloudWatch)
44
+ # can index each record's fields — including the OTel trace_id/span_id/request_id
45
+ # the filter injects (ADR-0223, #1899) — for log-to-trace correlation. The base
46
+ # config defaults to human-readable console output for dev; here we always emit
47
+ # JSON regardless of TRUEPPM_LOG_JSON, while still honouring DJANGO_LOG_LEVEL.
48
+ LOGGING = build_logging_config(level=DJANGO_LOG_LEVEL, json_output=True)
49
+
50
+ ALLOWED_HOSTS = env.list("ALLOWED_HOSTS")
51
+
52
+ # Refuse to boot on a bare-wildcard ALLOWED_HOSTS (#3515). Host validation is the
53
+ # only bound on the host the API reports, and therefore on every absolute URL it
54
+ # builds; "*" removes it. Same import-time enforcement as the guards below, since
55
+ # gunicorn/asgi workers never run `manage.py check`. Operators whose host set is
56
+ # genuinely unknowable opt in via TRUEPPM_ALLOW_WILDCARD_HOSTS=true and keep the
57
+ # warning instead — the TRUEPPM_ALLOW_UNENCRYPTED_DB shape, chosen so an existing
58
+ # install running "*" has a one-variable remedy rather than a crash-loop.
59
+ _wildcard_host_errors = validate_allowed_hosts(
60
+ ALLOWED_HOSTS, debug=DEBUG, allow_wildcard=ALLOW_WILDCARD_ALLOWED_HOSTS
61
+ )
62
+ if _wildcard_host_errors:
63
+ raise RuntimeError(_REFUSING_TO_START + "; ".join(str(e.msg) for e in _wildcard_host_errors))
64
+ if ALLOW_WILDCARD_ALLOWED_HOSTS and "*" in ALLOWED_HOSTS:
65
+ logging.getLogger("trueppm.settings").warning(
66
+ "ALLOWED_HOSTS contains the wildcard '*', so Django performs no host "
67
+ "validation. Absolute URLs the API builds (the OIDC redirect_uri and the "
68
+ "inbound Git-webhook URL) will follow whatever host the caller sends. "
69
+ "Proceeding because TRUEPPM_ALLOW_WILDCARD_HOSTS=true is set."
70
+ )
71
+
72
+ SECRET_KEY = env("SECRET_KEY") # required; no default in prod
73
+
74
+ # Refuse to boot with a weak SECRET_KEY (#566, PYSEC-2025-183).
75
+ # Django's system-check registry only fires under `manage.py check`; gunicorn
76
+ # and asgi workers do not run checks at startup, so the failure must be
77
+ # raised at settings import time to actually stop a broken deploy.
78
+ _secret_key_errors = validate_secret_key(SECRET_KEY, debug=DEBUG)
79
+ if _secret_key_errors:
80
+ raise RuntimeError(_REFUSING_TO_START + "; ".join(str(e.msg) for e in _secret_key_errors))
81
+
82
+ # Dedicated JWT signing key (#2247). base.py already derived JWT_SIGNING_KEY from
83
+ # the SECRET_KEY env var; re-derive it here against the prod-required SECRET_KEY so
84
+ # the binding is explicit and cannot drift, and mirror the value into SIMPLE_JWT.
85
+ # Then refuse to boot on a weak *explicit* key — an unset key inherits the
86
+ # already-validated SECRET_KEY, so validate_signing_key returns clean for it.
87
+ JWT_SIGNING_KEY = env("JWT_SIGNING_KEY", default=SECRET_KEY)
88
+ SIMPLE_JWT["SIGNING_KEY"] = JWT_SIGNING_KEY
89
+ _signing_key_errors = validate_signing_key(JWT_SIGNING_KEY, SECRET_KEY, debug=DEBUG)
90
+ if _signing_key_errors:
91
+ raise RuntimeError(_REFUSING_TO_START + "; ".join(str(e.msg) for e in _signing_key_errors))
92
+
93
+ # Persistent connections for production load.
94
+ DATABASES["default"]["CONN_MAX_AGE"] = 600
95
+
96
+ # Security headers.
97
+ SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
98
+
99
+ # The host is NOT taken from the proxy, and that asymmetry with the line above is
100
+ # deliberate (#3515). Django defaults both of these to False; stating them keeps
101
+ # the file from inheriting a position it never took.
102
+ #
103
+ # Why the scheme is trusted and the host is not:
104
+ #
105
+ # * X-Forwarded-Proto carries information the app cannot obtain any other way —
106
+ # the container always speaks plain HTTP on :8000, so without the header
107
+ # every request looks insecure. Its failure mode here is contained: the
108
+ # Secure flags on the session, CSRF and refresh cookies are hardcoded True
109
+ # above and in base.py rather than derived from is_secure(), so a spoofed
110
+ # value does not downgrade a cookie.
111
+ #
112
+ # * X-Forwarded-Host carries nothing new. Every proxy this project ships
113
+ # preserves the original Host (`proxy_set_header Host $host` in
114
+ # nginx/app.conf.template, app-http.conf.template, demo.conf.template,
115
+ # packages/web/nginx.conf and the chart's web ConfigMap), and none of them
116
+ # sets or strips X-Forwarded-Host. Turning this on would therefore trust a
117
+ # header whose only author in every supported topology is the client: Host is
118
+ # the edge's routing key, so a value that does not route never arrives, while
119
+ # X-Forwarded-Host routes fine and would be believed anyway. That is a strict
120
+ # widening of who can steer request.build_absolute_uri(), and it buys nothing.
121
+ #
122
+ # The premise True would need — "the proxy is the sole ingress path" — is also not
123
+ # something the chart enforces: templates/networkpolicy.yaml restricts the bundled
124
+ # datastore pods only, and the admin docs hand API-pod ingress restriction to the
125
+ # operator. Do not flip this without also closing that gap and stripping the
126
+ # header at every edge.
127
+ #
128
+ # An operator whose proxy genuinely rewrites Host does not need this switch:
129
+ # TRUEPPM_PUBLIC_API_BASE_URL pins the origin for both request-derived absolute
130
+ # URLs (the OIDC redirect_uri and the inbound Git-webhook URL), which is a value
131
+ # they control rather than a belief about a header they cannot verify.
132
+ USE_X_FORWARDED_HOST = False
133
+ USE_X_FORWARDED_PORT = False
134
+ SECURE_HSTS_SECONDS = 31536000
135
+ SECURE_HSTS_INCLUDE_SUBDOMAINS = True
136
+ SESSION_COOKIE_SECURE = True
137
+ CSRF_COOKIE_SECURE = True
138
+ SECURE_CONTENT_TYPE_NOSNIFF = True
139
+ SECURE_REFERRER_POLICY = "same-origin"
140
+ # HTTP→HTTPS redirect is opt-in: many deploys terminate TLS at the ingress and
141
+ # speak plain HTTP to the app (incl. the k8s liveness/readiness probes that hit
142
+ # /health/ and /edition/), where an unconditional redirect would break them.
143
+ # Operators that expose the app directly over TLS opt in via env; the probe
144
+ # paths stay exempt so they keep working over plain HTTP either way.
145
+ SECURE_SSL_REDIRECT = env.bool("TRUEPPM_SECURE_SSL_REDIRECT", default=False)
146
+ SECURE_REDIRECT_EXEMPT = [r"^api/v1/health/$", r"^api/v1/readyz$", r"^api/v1/edition/$"]
147
+
148
+ # Refuse to boot when task attachments would land on ephemeral local disk in a
149
+ # containerized deploy (#775) — same import-time enforcement as the SECRET_KEY
150
+ # guard, since gunicorn/asgi workers never run `manage.py check`. Passing
151
+ # MEDIA_ROOT extends the guard to the opted-in case (#3184): before this the
152
+ # opt-in was an unverified claim, and the deployment it described — no MEDIA_ROOT
153
+ # at all, on a read-only root filesystem — booted clean and then EROFS'd on the
154
+ # first upload.
155
+ _storage_errors = validate_attachment_storage(
156
+ STORAGES["default"]["BACKEND"],
157
+ debug=DEBUG,
158
+ allow_local=ALLOW_LOCAL_ATTACHMENT_STORAGE,
159
+ media_root=MEDIA_ROOT,
160
+ )
161
+ if _storage_errors:
162
+ raise RuntimeError(_REFUSING_TO_START + "; ".join(str(e.msg) for e in _storage_errors))
163
+
164
+ # Refuse to boot without a valid integration encryption key (#1002). The key
165
+ # encrypts integration PATs at rest; without this guard a missing/malformed key
166
+ # only surfaces as a 500 on the first PAT connect, long after deploy. Same
167
+ # import-time enforcement as the SECRET_KEY and storage guards above.
168
+ _integration_key_errors = validate_integration_encryption_key(
169
+ INTEGRATION_ENCRYPTION_KEY, debug=DEBUG
170
+ )
171
+ if _integration_key_errors:
172
+ raise RuntimeError(_REFUSING_TO_START + "; ".join(str(e.msg) for e in _integration_key_errors))
173
+
174
+ # Refuse to boot when the soft-delete retention window is 0 (#3186). 0 sets the
175
+ # purge cutoff to the present moment, so the next tick HARD-deletes every
176
+ # trashed project and all of its children via CASCADE — irreversibly, with no
177
+ # tombstone. The API has always refused this value
178
+ # (RetentionPolicyWriteSerializer.value is min_value=1); the env var had no
179
+ # floor, and the chart's own comment told operators to set exactly this "to keep
180
+ # the default". Same import-time posture as the guards above, since asgi workers
181
+ # never run `manage.py check`.
182
+ _retention_errors = validate_project_soft_delete_retention(
183
+ TRUEPPM_PROJECT_SOFT_DELETE_RETENTION_DAYS
184
+ )
185
+ if _retention_errors:
186
+ raise RuntimeError(_REFUSING_TO_START + "; ".join(str(e.msg) for e in _retention_errors))
187
+
188
+ # Refuse to boot when DATABASE_URL has no sslmode parameter in a non-DEBUG
189
+ # deployment (#1550). Without sslmode=require the connection falls back to
190
+ # whatever the server negotiates, which may be plaintext — the same fail-closed
191
+ # posture as the SECRET_KEY (#566), attachment-storage (#775), and integration-
192
+ # key (#1002) guards above, since gunicorn/asgi workers never run
193
+ # `manage.py check`. Operators terminating TLS at the proxy/sidecar layer (where
194
+ # the app-to-DB link is already encrypted) opt in via
195
+ # TRUEPPM_ALLOW_UNENCRYPTED_DB=true and keep the warning instead.
196
+ _db_url_raw: str = env("DATABASE_URL", default="")
197
+ if _db_url_raw:
198
+ _db_url_qs = urllib.parse.parse_qs(urllib.parse.urlparse(_db_url_raw).query)
199
+ if "sslmode" not in _db_url_qs:
200
+ if ALLOW_UNENCRYPTED_DB:
201
+ logging.getLogger("trueppm.settings").warning(
202
+ "DATABASE_URL does not include sslmode=require. "
203
+ "Database connections may use unencrypted transport. "
204
+ "Proceeding because TRUEPPM_ALLOW_UNENCRYPTED_DB=true is set; "
205
+ "ensure TLS is enforced at the network layer."
206
+ )
207
+ else:
208
+ raise RuntimeError(
209
+ "Refusing to start: DATABASE_URL does not include sslmode=require "
210
+ "in a non-DEBUG environment; database connections may use "
211
+ "unencrypted transport. Set sslmode=require in DATABASE_URL, or set "
212
+ "TRUEPPM_ALLOW_UNENCRYPTED_DB=true if TLS is enforced at the network "
213
+ "layer."
214
+ )
215
+
216
+ # Refuse to boot on a placeholder datastore credential (#3176). Compose's
217
+ # ``${DB_PASSWORD:?...}`` only asserts the variable is non-empty, and .env.example
218
+ # shipped ``change-me`` — so the documented copy-paste path produced a deploy in which
219
+ # SECRET_KEY, the attachment backend, the integration key and sslmode were all validated
220
+ # and the database/cache passwords were not. Same import-time enforcement as the guards
221
+ # above, for the same reason: gunicorn/asgi workers never run ``manage.py check``.
222
+ _service_cred_errors = validate_service_credentials(
223
+ DATABASES["default"].get("PASSWORD"),
224
+ urllib.parse.urlparse(REDIS_URL or "").password,
225
+ debug=DEBUG,
226
+ )
227
+ if _service_cred_errors:
228
+ raise RuntimeError(_REFUSING_TO_START + "; ".join(str(e.msg) for e in _service_cred_errors))
trueppm_api/urls.py ADDED
@@ -0,0 +1,153 @@
1
+ """Root URL configuration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from django.conf import settings
6
+ from django.contrib import admin
7
+ from django.urls import include, path
8
+ from drf_spectacular.utils import extend_schema, inline_serializer
9
+ from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerSplitView
10
+ from rest_framework import serializers
11
+ from rest_framework.decorators import api_view, permission_classes
12
+ from rest_framework.permissions import AllowAny
13
+ from rest_framework.request import Request
14
+ from rest_framework.response import Response
15
+
16
+ from trueppm_api.apps.observability.views import readyz
17
+ from trueppm_api.core.auth_views import (
18
+ CookieTokenLogoutView,
19
+ CookieTokenObtainPairView,
20
+ CookieTokenRefreshView,
21
+ )
22
+ from trueppm_api.core.password_reset import (
23
+ PasswordResetConfirmView,
24
+ PasswordResetRequestView,
25
+ )
26
+
27
+
28
+ @extend_schema(
29
+ summary="Liveness probe",
30
+ description=(
31
+ 'Returns HTTP 200 with `{"status": "ok"}` when the API process is running. '
32
+ "No authentication required. Use for Kubernetes liveness/readiness probes."
33
+ ),
34
+ responses={200: inline_serializer("HealthResponse", {"status": serializers.CharField()})},
35
+ auth=[],
36
+ tags=["meta"],
37
+ )
38
+ @api_view(["GET"])
39
+ @permission_classes([AllowAny])
40
+ def health(_request: Request) -> Response:
41
+ return Response({"status": "ok"})
42
+
43
+
44
+ @extend_schema(
45
+ summary="Running edition",
46
+ description=(
47
+ 'Returns `{"edition": "community" | "enterprise"}` from the TRUEPPM_EDITION '
48
+ "Django setting. No authentication required. The React shell calls this once "
49
+ "at startup to decide the post-login redirect target (ADR-0029, ADR-0030)."
50
+ ),
51
+ responses={
52
+ 200: inline_serializer(
53
+ "EditionResponse",
54
+ {
55
+ "edition": serializers.CharField(),
56
+ "version": serializers.CharField(),
57
+ "build_sha": serializers.CharField(allow_blank=True),
58
+ },
59
+ )
60
+ },
61
+ auth=[],
62
+ tags=["meta"],
63
+ )
64
+ @api_view(["GET"])
65
+ @permission_classes([AllowAny])
66
+ def edition(request: Request) -> Response:
67
+ """Return the running edition — community or enterprise.
68
+
69
+ Public endpoint (no auth required). The React shell calls this once at
70
+ startup to decide the post-login redirect target (ADR-0029, ADR-0030).
71
+ The value is controlled by the TRUEPPM_EDITION Django setting, which the
72
+ enterprise Helm chart sets to "enterprise".
73
+ """
74
+ return Response(
75
+ {
76
+ "edition": settings.TRUEPPM_EDITION,
77
+ # Build identity (#2392): a bug report has to name the exact build it
78
+ # came from, and this is the one endpoint the shell already calls at
79
+ # startup without auth. `build_sha` is empty on a source checkout.
80
+ "version": settings.TRUEPPM_VERSION,
81
+ "build_sha": settings.TRUEPPM_BUILD_SHA,
82
+ }
83
+ )
84
+
85
+
86
+ # Versioned prefix every app router mounts under.
87
+ _API_V1_PREFIX = "api/v1/"
88
+
89
+ urlpatterns = [
90
+ path("api/v1/health/", health, name="health"),
91
+ # Dependency-aware readiness probe (#1894). Unauthenticated like /health/ so
92
+ # kubelet can call it, but returns 503 when the DB or cache is unreachable —
93
+ # unlike /health/, which is a shallow process-liveness check.
94
+ path("api/v1/readyz", readyz, name="readyz"),
95
+ path("api/v1/edition/", edition, name="edition"),
96
+ path("admin/", admin.site.urls),
97
+ # OpenAPI schema and interactive docs. The *split* Swagger view (not the
98
+ # default inline one) is required by our strict CSP: it delivers the UI
99
+ # bootstrap as a separate same-origin JS request instead of an inline
100
+ # <script>, which script-src 'self' would otherwise block (the page rendered
101
+ # blank — #1603). Asset bundles are served from drf-spectacular-sidecar
102
+ # ('self') via SWAGGER_UI_DIST=SIDECAR in settings.
103
+ path("api/schema/", SpectacularAPIView.as_view(), name="schema"),
104
+ path("api/docs/", SpectacularSwaggerSplitView.as_view(url_name="schema"), name="swagger-ui"),
105
+ path(
106
+ "api/schema/swagger-ui/",
107
+ SpectacularSwaggerSplitView.as_view(url_name="schema"),
108
+ name="swagger-ui-compat",
109
+ ),
110
+ # JWT auth endpoints (#897). Login returns the access token in the body and
111
+ # sets the refresh token in an httpOnly cookie; refresh reads that cookie;
112
+ # logout clears it (and blacklists the token if the blacklist app is present).
113
+ path("api/v1/auth/token/", CookieTokenObtainPairView.as_view(), name="token_obtain_pair"),
114
+ path("api/v1/auth/token/refresh/", CookieTokenRefreshView.as_view(), name="token_refresh"),
115
+ path("api/v1/auth/logout/", CookieTokenLogoutView.as_view(), name="token_logout"),
116
+ # Self-service password reset (#765, ADR-0209). Both AllowAny + throttled with a
117
+ # dedicated "password_reset" scope. Request always returns 200 (no user
118
+ # enumeration); confirm validates a stateless token, sets the password, and
119
+ # revokes all of the account's other sessions.
120
+ path(
121
+ "api/v1/auth/password/reset/",
122
+ PasswordResetRequestView.as_view(),
123
+ name="password_reset",
124
+ ),
125
+ path(
126
+ "api/v1/auth/password/reset/confirm/",
127
+ PasswordResetConfirmView.as_view(),
128
+ name="password_reset_confirm",
129
+ ),
130
+ # Versioned API
131
+ path(_API_V1_PREFIX, include("trueppm_api.apps.access.urls")),
132
+ path(_API_V1_PREFIX, include("trueppm_api.apps.projects.urls")),
133
+ path(_API_V1_PREFIX, include("trueppm_api.apps.resources.urls")),
134
+ path(_API_V1_PREFIX, include("trueppm_api.apps.scheduling.urls")),
135
+ path(_API_V1_PREFIX, include("trueppm_api.apps.sync.urls")),
136
+ path(_API_V1_PREFIX, include("trueppm_api.apps.history.urls")),
137
+ path(_API_V1_PREFIX, include("trueppm_api.apps.msproject.urls")),
138
+ path(_API_V1_PREFIX, include("trueppm_api.apps.jiraimport.urls")),
139
+ path(_API_V1_PREFIX, include("trueppm_api.apps.csvimport.urls")),
140
+ path(_API_V1_PREFIX, include("trueppm_api.apps.webhooks.urls")),
141
+ path(_API_V1_PREFIX, include("trueppm_api.apps.taskruns.urls")),
142
+ path(_API_V1_PREFIX, include("trueppm_api.apps.notifications.urls")),
143
+ path(_API_V1_PREFIX, include("trueppm_api.apps.integrations.urls")),
144
+ path(_API_V1_PREFIX, include("trueppm_api.apps.observability.urls")),
145
+ path(_API_V1_PREFIX, include("trueppm_api.apps.workspace.urls")),
146
+ path(_API_V1_PREFIX, include("trueppm_api.apps.teams.urls")),
147
+ path(_API_V1_PREFIX, include("trueppm_api.apps.timetracking.urls")),
148
+ # Basic SSO — OIDC relying party (ADR-0187). Flow endpoints under
149
+ # auth/oidc/*, admin config under workspace/sso/*.
150
+ path(_API_V1_PREFIX, include("trueppm_api.apps.sso.urls")),
151
+ # Team-readable agent-action audit log (ADR-0112 RC1, #1805).
152
+ path(_API_V1_PREFIX, include("trueppm_api.apps.agents.urls")),
153
+ ]