trueppm-api 0.4.0__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.
- trueppm_api/__init__.py +27 -0
- trueppm_api/apps/access/__init__.py +0 -0
- trueppm_api/apps/access/apps.py +19 -0
- trueppm_api/apps/access/groups.py +518 -0
- trueppm_api/apps/access/management/__init__.py +0 -0
- trueppm_api/apps/access/management/commands/__init__.py +0 -0
- trueppm_api/apps/access/management/commands/create_admin.py +346 -0
- trueppm_api/apps/access/management/commands/migrate_locked.py +96 -0
- trueppm_api/apps/access/management/commands/revoke_api_tokens.py +483 -0
- trueppm_api/apps/access/migrations/0001_initial.py +61 -0
- trueppm_api/apps/access/migrations/0001_squashed_0012_programmembership_role_title.py +184 -0
- trueppm_api/apps/access/migrations/0002_alter_projectmembership_id.py +29 -0
- trueppm_api/apps/access/migrations/0003_projectmembership_soft_delete.py +24 -0
- trueppm_api/apps/access/migrations/0004_alter_projectmembership_role.py +34 -0
- trueppm_api/apps/access/migrations/0005_program_entity_and_membership.py +76 -0
- trueppm_api/apps/access/migrations/0006_role_ordinal_spacing.py +113 -0
- trueppm_api/apps/access/migrations/0007_projectmembership_joined_at_and_more.py +35 -0
- trueppm_api/apps/access/migrations/0008_projectmembership_source_group.py +25 -0
- trueppm_api/apps/access/migrations/0009_projectmembership_pm_proj_serverver_idx.py +20 -0
- trueppm_api/apps/access/migrations/0010_programmembership_joined_at_and_more.py +38 -0
- trueppm_api/apps/access/migrations/0011_alter_programmembership_unique_together_and_more.py +36 -0
- trueppm_api/apps/access/migrations/0012_programmembership_role_title.py +17 -0
- trueppm_api/apps/access/migrations/0013_squashed_0019_release_0_4.py +302 -0
- trueppm_api/apps/access/migrations/0013_userdefinedmentiongroup.py +82 -0
- trueppm_api/apps/access/migrations/0014_programmembership_progm_serverver_idx.py +19 -0
- trueppm_api/apps/access/migrations/0015_programuserdefinedmentiongroup.py +86 -0
- trueppm_api/apps/access/migrations/0016_externalstakeholder.py +67 -0
- trueppm_api/apps/access/migrations/0017_viewer_ordinal_one.py +143 -0
- trueppm_api/apps/access/migrations/0018_programmembership_sync_seq_and_more.py +52 -0
- trueppm_api/apps/access/migrations/0019_programmembership_reinstated_at_and_more.py +22 -0
- trueppm_api/apps/access/migrations/__init__.py +0 -0
- trueppm_api/apps/access/minter_role.py +38 -0
- trueppm_api/apps/access/models.py +588 -0
- trueppm_api/apps/access/permissions.py +3263 -0
- trueppm_api/apps/access/serializers.py +1007 -0
- trueppm_api/apps/access/services.py +878 -0
- trueppm_api/apps/access/signals.py +171 -0
- trueppm_api/apps/access/tasks.py +50 -0
- trueppm_api/apps/access/throttles.py +96 -0
- trueppm_api/apps/access/urls.py +191 -0
- trueppm_api/apps/access/views.py +1965 -0
- trueppm_api/apps/agents/__init__.py +6 -0
- trueppm_api/apps/agents/apps.py +11 -0
- trueppm_api/apps/agents/canonical.py +73 -0
- trueppm_api/apps/agents/deferred.py +108 -0
- trueppm_api/apps/agents/management/__init__.py +0 -0
- trueppm_api/apps/agents/management/commands/__init__.py +0 -0
- trueppm_api/apps/agents/management/commands/audit_prune.py +137 -0
- trueppm_api/apps/agents/management/commands/audit_verify.py +101 -0
- trueppm_api/apps/agents/middleware.py +44 -0
- trueppm_api/apps/agents/migrations/0001_initial.py +231 -0
- trueppm_api/apps/agents/migrations/0001_squashed_0003_release_0_4.py +344 -0
- trueppm_api/apps/agents/migrations/0002_agentactioncheckpoint.py +71 -0
- trueppm_api/apps/agents/migrations/0003_agentactionrefusaldetail.py +58 -0
- trueppm_api/apps/agents/migrations/__init__.py +0 -0
- trueppm_api/apps/agents/models.py +371 -0
- trueppm_api/apps/agents/refusal.py +103 -0
- trueppm_api/apps/agents/serializers.py +85 -0
- trueppm_api/apps/agents/services.py +397 -0
- trueppm_api/apps/agents/signals.py +30 -0
- trueppm_api/apps/agents/urls.py +15 -0
- trueppm_api/apps/agents/views.py +109 -0
- trueppm_api/apps/csvimport/__init__.py +12 -0
- trueppm_api/apps/csvimport/apps.py +11 -0
- trueppm_api/apps/csvimport/mapping.py +363 -0
- trueppm_api/apps/csvimport/migrations/0001_initial.py +74 -0
- trueppm_api/apps/csvimport/migrations/0001_squashed_0003_release_0_4.py +90 -0
- trueppm_api/apps/csvimport/migrations/0002_schedule_outline_batch_operations.py +37 -0
- trueppm_api/apps/csvimport/migrations/0003_csvimportrequest_date_order_and_more.py +26 -0
- trueppm_api/apps/csvimport/migrations/__init__.py +0 -0
- trueppm_api/apps/csvimport/models.py +111 -0
- trueppm_api/apps/csvimport/parser.py +1825 -0
- trueppm_api/apps/csvimport/services.py +48 -0
- trueppm_api/apps/csvimport/tasks.py +459 -0
- trueppm_api/apps/csvimport/template.py +37 -0
- trueppm_api/apps/csvimport/urls.py +50 -0
- trueppm_api/apps/csvimport/views.py +793 -0
- trueppm_api/apps/history/__init__.py +0 -0
- trueppm_api/apps/history/apps.py +12 -0
- trueppm_api/apps/history/changelog.py +359 -0
- trueppm_api/apps/history/diff_policy.py +178 -0
- trueppm_api/apps/history/serializers.py +104 -0
- trueppm_api/apps/history/signals.py +82 -0
- trueppm_api/apps/history/tasks.py +105 -0
- trueppm_api/apps/history/urls.py +38 -0
- trueppm_api/apps/history/views.py +443 -0
- trueppm_api/apps/idempotency/__init__.py +0 -0
- trueppm_api/apps/idempotency/apps.py +11 -0
- trueppm_api/apps/idempotency/migrations/0001_initial.py +71 -0
- trueppm_api/apps/idempotency/migrations/__init__.py +0 -0
- trueppm_api/apps/idempotency/mixins.py +226 -0
- trueppm_api/apps/idempotency/models.py +75 -0
- trueppm_api/apps/idempotency/tasks.py +61 -0
- trueppm_api/apps/integrations/__init__.py +13 -0
- trueppm_api/apps/integrations/apps.py +59 -0
- trueppm_api/apps/integrations/connections.py +806 -0
- trueppm_api/apps/integrations/encryption.py +92 -0
- trueppm_api/apps/integrations/external_sources.py +863 -0
- trueppm_api/apps/integrations/git_automation_services.py +231 -0
- trueppm_api/apps/integrations/git_webhook_auth.py +243 -0
- trueppm_api/apps/integrations/http.py +597 -0
- trueppm_api/apps/integrations/me_work.py +218 -0
- trueppm_api/apps/integrations/migrations/0001_initial.py +64 -0
- trueppm_api/apps/integrations/migrations/0001_squashed_0006_tasklink_description_tasklink_preview_type_and_more.py +187 -0
- trueppm_api/apps/integrations/migrations/0002_tasklink.py +67 -0
- trueppm_api/apps/integrations/migrations/0003_tasklink_tasklink_serverver_idx.py +17 -0
- trueppm_api/apps/integrations/migrations/0004_tasklink_custom_title_tasklink_labels.py +25 -0
- trueppm_api/apps/integrations/migrations/0005_boardautomation.py +56 -0
- trueppm_api/apps/integrations/migrations/0006_tasklink_description_tasklink_preview_type_and_more.py +40 -0
- trueppm_api/apps/integrations/migrations/0007_squashed_0014_release_0_4.py +225 -0
- trueppm_api/apps/integrations/migrations/0007_tasklink_created_at.py +23 -0
- trueppm_api/apps/integrations/migrations/0008_integrationcredential_config_externalworkitem.py +66 -0
- trueppm_api/apps/integrations/migrations/0009_externalsyncrequest_and_more.py +96 -0
- trueppm_api/apps/integrations/migrations/0010_externalworkitem_due_date.py +17 -0
- trueppm_api/apps/integrations/migrations/0011_tasklink_sync_seq_tasklink_tasklink_syncseq_idx.py +22 -0
- trueppm_api/apps/integrations/migrations/0012_boardautomation_last_delivery_at_and_more.py +42 -0
- trueppm_api/apps/integrations/migrations/0013_externalsyncrequest_attempt_count_and_more.py +26 -0
- trueppm_api/apps/integrations/migrations/0014_tasklink_created_by.py +27 -0
- trueppm_api/apps/integrations/migrations/__init__.py +0 -0
- trueppm_api/apps/integrations/models.py +635 -0
- trueppm_api/apps/integrations/notification_channels.py +57 -0
- trueppm_api/apps/integrations/opengraph.py +229 -0
- trueppm_api/apps/integrations/outgoing.py +201 -0
- trueppm_api/apps/integrations/providers.py +528 -0
- trueppm_api/apps/integrations/registry.py +345 -0
- trueppm_api/apps/integrations/serializers.py +453 -0
- trueppm_api/apps/integrations/services.py +171 -0
- trueppm_api/apps/integrations/tasks.py +734 -0
- trueppm_api/apps/integrations/throttles.py +165 -0
- trueppm_api/apps/integrations/urls.py +77 -0
- trueppm_api/apps/integrations/views.py +1158 -0
- trueppm_api/apps/jiraimport/__init__.py +8 -0
- trueppm_api/apps/jiraimport/apps.py +11 -0
- trueppm_api/apps/jiraimport/migrations/0001_initial.py +72 -0
- trueppm_api/apps/jiraimport/migrations/__init__.py +0 -0
- trueppm_api/apps/jiraimport/models.py +70 -0
- trueppm_api/apps/jiraimport/parser.py +350 -0
- trueppm_api/apps/jiraimport/services.py +46 -0
- trueppm_api/apps/jiraimport/tasks.py +280 -0
- trueppm_api/apps/jiraimport/urls.py +15 -0
- trueppm_api/apps/jiraimport/views.py +153 -0
- trueppm_api/apps/msproject/__init__.py +0 -0
- trueppm_api/apps/msproject/apps.py +11 -0
- trueppm_api/apps/msproject/dataclasses.py +153 -0
- trueppm_api/apps/msproject/exporter.py +551 -0
- trueppm_api/apps/msproject/extended_attributes.py +77 -0
- trueppm_api/apps/msproject/importer.py +1095 -0
- trueppm_api/apps/msproject/migrations/0001_import_request.py +77 -0
- trueppm_api/apps/msproject/migrations/0001_squashed_0002_importrequest_creates_project.py +80 -0
- trueppm_api/apps/msproject/migrations/0002_importrequest_creates_project.py +15 -0
- trueppm_api/apps/msproject/migrations/__init__.py +0 -0
- trueppm_api/apps/msproject/models.py +81 -0
- trueppm_api/apps/msproject/parser.py +1276 -0
- trueppm_api/apps/msproject/serializers.py +136 -0
- trueppm_api/apps/msproject/services.py +58 -0
- trueppm_api/apps/msproject/tasks.py +439 -0
- trueppm_api/apps/msproject/urls.py +39 -0
- trueppm_api/apps/msproject/views.py +531 -0
- trueppm_api/apps/notifications/__init__.py +7 -0
- trueppm_api/apps/notifications/apps.py +15 -0
- trueppm_api/apps/notifications/backfill.py +79 -0
- trueppm_api/apps/notifications/categories.py +112 -0
- trueppm_api/apps/notifications/delivery_limits.py +258 -0
- trueppm_api/apps/notifications/digests.py +462 -0
- trueppm_api/apps/notifications/email_backend.py +350 -0
- trueppm_api/apps/notifications/email_health.py +128 -0
- trueppm_api/apps/notifications/migrations/0001_initial.py +207 -0
- trueppm_api/apps/notifications/migrations/0001_squashed_0006_notification_task.py +299 -0
- trueppm_api/apps/notifications/migrations/0002_project_notification_preference.py +67 -0
- trueppm_api/apps/notifications/migrations/0003_projectnotificationpreference_paused.py +17 -0
- trueppm_api/apps/notifications/migrations/0004_clean_unknown_matrix_keys.py +30 -0
- trueppm_api/apps/notifications/migrations/0005_notification_body_notification_event_type_and_more.py +27 -0
- trueppm_api/apps/notifications/migrations/0006_notification_task.py +25 -0
- trueppm_api/apps/notifications/migrations/0007_squashed_0011_release_0_4.py +204 -0
- trueppm_api/apps/notifications/migrations/0007_workspaceemailsettings.py +80 -0
- trueppm_api/apps/notifications/migrations/0008_notification_snoozed_until.py +17 -0
- trueppm_api/apps/notifications/migrations/0009_usernotificationsettings.py +43 -0
- trueppm_api/apps/notifications/migrations/0010_projectnotificationpreference_schema_version.py +20 -0
- trueppm_api/apps/notifications/migrations/0011_usernotificationsettings_digest_hour_and_more.py +96 -0
- trueppm_api/apps/notifications/migrations/__init__.py +0 -0
- trueppm_api/apps/notifications/models.py +1148 -0
- trueppm_api/apps/notifications/receivers.py +155 -0
- trueppm_api/apps/notifications/schema_migrations.py +56 -0
- trueppm_api/apps/notifications/serializers.py +1094 -0
- trueppm_api/apps/notifications/services.py +1489 -0
- trueppm_api/apps/notifications/tasks.py +762 -0
- trueppm_api/apps/notifications/throttles.py +98 -0
- trueppm_api/apps/notifications/urls.py +97 -0
- trueppm_api/apps/notifications/views.py +919 -0
- trueppm_api/apps/observability/__init__.py +0 -0
- trueppm_api/apps/observability/apps.py +31 -0
- trueppm_api/apps/observability/logging.py +213 -0
- trueppm_api/apps/observability/migrations/0001_initial.py +35 -0
- trueppm_api/apps/observability/migrations/0001_squashed_0003_alter_purgerun_trigger.py +154 -0
- trueppm_api/apps/observability/migrations/0002_purgerun_retentionpolicy_retentionschedule.py +131 -0
- trueppm_api/apps/observability/migrations/0003_alter_purgerun_trigger.py +21 -0
- trueppm_api/apps/observability/migrations/0004_alter_retentionpolicy_key.py +28 -0
- trueppm_api/apps/observability/migrations/__init__.py +0 -0
- trueppm_api/apps/observability/models.py +141 -0
- trueppm_api/apps/observability/otel/__init__.py +45 -0
- trueppm_api/apps/observability/otel/attributes.py +247 -0
- trueppm_api/apps/observability/otel/export_health.py +533 -0
- trueppm_api/apps/observability/otel/instrumentation.py +351 -0
- trueppm_api/apps/observability/otel/metrics.py +566 -0
- trueppm_api/apps/observability/otel/provider.py +511 -0
- trueppm_api/apps/observability/otel/request_attributes.py +204 -0
- trueppm_api/apps/observability/purge_registry.py +124 -0
- trueppm_api/apps/observability/retention.py +139 -0
- trueppm_api/apps/observability/selectors.py +993 -0
- trueppm_api/apps/observability/serializers.py +142 -0
- trueppm_api/apps/observability/services.py +407 -0
- trueppm_api/apps/observability/tasks.py +266 -0
- trueppm_api/apps/observability/urls.py +27 -0
- trueppm_api/apps/observability/views.py +537 -0
- trueppm_api/apps/profiles/__init__.py +0 -0
- trueppm_api/apps/profiles/apps.py +15 -0
- trueppm_api/apps/profiles/constants.py +54 -0
- trueppm_api/apps/profiles/migrations/0001_initial.py +55 -0
- trueppm_api/apps/profiles/migrations/0001_squashed_0004_userprofile_role_context.py +125 -0
- trueppm_api/apps/profiles/migrations/0002_userprofile_hidden_views.py +17 -0
- trueppm_api/apps/profiles/migrations/0003_projectvisit.py +63 -0
- trueppm_api/apps/profiles/migrations/0004_userprofile_role_context.py +26 -0
- trueppm_api/apps/profiles/migrations/0005_squashed_0009_release_0_4.py +128 -0
- trueppm_api/apps/profiles/migrations/0005_userprofile_schedule_in_deliver.py +20 -0
- trueppm_api/apps/profiles/migrations/0006_userprofile_date_format_userprofile_timezone.py +36 -0
- trueppm_api/apps/profiles/migrations/0007_userpin.py +91 -0
- trueppm_api/apps/profiles/migrations/0008_remove_userprofile_schedule_in_deliver.py +71 -0
- trueppm_api/apps/profiles/migrations/0009_auth_user_email_upper_idx.py +81 -0
- trueppm_api/apps/profiles/migrations/__init__.py +0 -0
- trueppm_api/apps/profiles/models.py +276 -0
- trueppm_api/apps/profiles/serializers.py +199 -0
- trueppm_api/apps/profiles/services.py +541 -0
- trueppm_api/apps/profiles/views.py +124 -0
- trueppm_api/apps/projects/__init__.py +0 -0
- trueppm_api/apps/projects/actual_date_rules.py +163 -0
- trueppm_api/apps/projects/amend.py +133 -0
- trueppm_api/apps/projects/apps.py +38 -0
- trueppm_api/apps/projects/asset_feed.py +459 -0
- trueppm_api/apps/projects/asset_views.py +317 -0
- trueppm_api/apps/projects/attachment_policy.py +278 -0
- trueppm_api/apps/projects/authentication.py +458 -0
- trueppm_api/apps/projects/backfill.py +459 -0
- trueppm_api/apps/projects/backlog_services.py +324 -0
- trueppm_api/apps/projects/backlog_views.py +302 -0
- trueppm_api/apps/projects/batch_operation_views.py +264 -0
- trueppm_api/apps/projects/blocker_services.py +510 -0
- trueppm_api/apps/projects/board_activity.py +462 -0
- trueppm_api/apps/projects/board_activity_views.py +186 -0
- trueppm_api/apps/projects/board_lanes.py +134 -0
- trueppm_api/apps/projects/bulk_settings.py +194 -0
- trueppm_api/apps/projects/bundled_templates.py +215 -0
- trueppm_api/apps/projects/calendar_settings.py +180 -0
- trueppm_api/apps/projects/ceremony_views.py +244 -0
- trueppm_api/apps/projects/commit_moment.py +212 -0
- trueppm_api/apps/projects/config_notice.py +1330 -0
- trueppm_api/apps/projects/custom_field_values.py +266 -0
- trueppm_api/apps/projects/decisions_services.py +132 -0
- trueppm_api/apps/projects/decisions_views.py +97 -0
- trueppm_api/apps/projects/estimation_scale.py +126 -0
- trueppm_api/apps/projects/export_bundle.py +423 -0
- trueppm_api/apps/projects/fixtures/seeds/atlas-platform-launch.json +4278 -0
- trueppm_api/apps/projects/fixtures/seeds/aurora-mobile-app.json +2001 -0
- trueppm_api/apps/projects/fixtures/seeds/bayside-civic-center.json +1827 -0
- trueppm_api/apps/projects/fixtures/seeds/ga-launch.json +1909 -0
- trueppm_api/apps/projects/fixtures/seeds/helios-crm-replacement.json +1410 -0
- trueppm_api/apps/projects/guardrail_policy_source.py +269 -0
- trueppm_api/apps/projects/inbound_sync.py +555 -0
- trueppm_api/apps/projects/iteration_label.py +85 -0
- trueppm_api/apps/projects/key_views.py +468 -0
- trueppm_api/apps/projects/keys.py +205 -0
- trueppm_api/apps/projects/lifecycle.py +191 -0
- trueppm_api/apps/projects/management/__init__.py +0 -0
- trueppm_api/apps/projects/management/commands/__init__.py +0 -0
- trueppm_api/apps/projects/management/commands/backfill_in_progress_status.py +92 -0
- trueppm_api/apps/projects/management/commands/create_demo_share_link.py +368 -0
- trueppm_api/apps/projects/management/commands/export_program.py +50 -0
- trueppm_api/apps/projects/management/commands/import_seed.py +165 -0
- trueppm_api/apps/projects/management/commands/load_sample_project.py +514 -0
- trueppm_api/apps/projects/management/commands/seed_capacity.py +406 -0
- trueppm_api/apps/projects/management/commands/seed_integration_fixtures.py +192 -0
- trueppm_api/apps/projects/management/commands/shift_sample_dates.py +120 -0
- trueppm_api/apps/projects/mcp_settings.py +305 -0
- trueppm_api/apps/projects/methodology.py +178 -0
- trueppm_api/apps/projects/migration_helpers.py +75 -0
- trueppm_api/apps/projects/migrations/0001_initial.py +208 -0
- trueppm_api/apps/projects/migrations/0001_squashed_0094_project_decisions_policy.py +5659 -0
- trueppm_api/apps/projects/migrations/0002_alter_uuid_pk_serialize_false.py +57 -0
- trueppm_api/apps/projects/migrations/0003_rename_task_project_index.py +25 -0
- trueppm_api/apps/projects/migrations/0004_soft_delete_and_dependency_versioned.py +70 -0
- trueppm_api/apps/projects/migrations/0005_task_assignee.py +33 -0
- trueppm_api/apps/projects/migrations/0006_task_utilization_index.py +31 -0
- trueppm_api/apps/projects/migrations/0007_task_is_milestone.py +28 -0
- trueppm_api/apps/projects/migrations/0008_baseline.py +119 -0
- trueppm_api/apps/projects/migrations/0009_historicaldependency_historicalproject_and_more.py +210 -0
- trueppm_api/apps/projects/migrations/0010_risk.py +229 -0
- trueppm_api/apps/projects/migrations/0011_task_status.py +27 -0
- trueppm_api/apps/projects/migrations/0012_task_status.py +27 -0
- trueppm_api/apps/projects/migrations/0013_task_planned_start.py +24 -0
- trueppm_api/apps/projects/migrations/0014_short_hex_ids.py +74 -0
- trueppm_api/apps/projects/migrations/0015_backfill_short_ids.py +48 -0
- trueppm_api/apps/projects/migrations/0016_task_actual_dates.py +42 -0
- trueppm_api/apps/projects/migrations/0017_boardcolumnconfig.py +43 -0
- trueppm_api/apps/projects/migrations/0018_estimation_governance.py +62 -0
- trueppm_api/apps/projects/migrations/0019_backfill_wbs_paths.py +28 -0
- trueppm_api/apps/projects/migrations/0020_task_status_5col.py +65 -0
- trueppm_api/apps/projects/migrations/0021_boardsavedview.py +64 -0
- trueppm_api/apps/projects/migrations/0022_task_status_changed_at_priority_rank.py +35 -0
- trueppm_api/apps/projects/migrations/0023_risk_framework_fields.py +96 -0
- trueppm_api/apps/projects/migrations/0024_riskcomment.py +52 -0
- trueppm_api/apps/projects/migrations/0025_sprint.py +352 -0
- trueppm_api/apps/projects/migrations/0026_project_methodology.py +30 -0
- trueppm_api/apps/projects/migrations/0027_sprint_retro.py +89 -0
- trueppm_api/apps/projects/migrations/0028_normalize_notes_field.py +42 -0
- trueppm_api/apps/projects/migrations/0029_complete_implies_full_progress.py +38 -0
- trueppm_api/apps/projects/migrations/0030_review_implies_full_progress.py +37 -0
- trueppm_api/apps/projects/migrations/0031_task_remaining_points.py +22 -0
- trueppm_api/apps/projects/migrations/0032_task_is_subtask_and_sprint_scope_change.py +90 -0
- trueppm_api/apps/projects/migrations/0033_task_my_work_index.py +38 -0
- trueppm_api/apps/projects/migrations/0034_inbound_task_sync.py +313 -0
- trueppm_api/apps/projects/migrations/0035_retro_versioned_and_suggested_assignee.py +173 -0
- trueppm_api/apps/projects/migrations/0036_program_entity_and_membership.py +157 -0
- trueppm_api/apps/projects/migrations/0037_sprint_capacity_points.py +20 -0
- trueppm_api/apps/projects/migrations/0038_taskcomment_commentreaction_commentacknowledgement_and_more.py +233 -0
- trueppm_api/apps/projects/migrations/0039_apitoken_and_more.py +88 -0
- trueppm_api/apps/projects/migrations/0040_program_general_fields.py +119 -0
- trueppm_api/apps/projects/migrations/0041_ceremony_template_and_phase_gate_config.py +210 -0
- trueppm_api/apps/projects/migrations/0041_project_general_fields.py +106 -0
- trueppm_api/apps/projects/migrations/0042_merge_20260522_0410.py +12 -0
- trueppm_api/apps/projects/migrations/0042_program_rollup_config.py +95 -0
- trueppm_api/apps/projects/migrations/0042_workflow_color_and_custom_fields.py +94 -0
- trueppm_api/apps/projects/migrations/0043_merge_20260522_1118.py +10 -0
- trueppm_api/apps/projects/migrations/0044_merge_20260522_rollup.py +10 -0
- trueppm_api/apps/projects/migrations/0044_project_archive_program_close.py +119 -0
- trueppm_api/apps/projects/migrations/0045_program_risk_policy.py +78 -0
- trueppm_api/apps/projects/migrations/0046_merge_20260523_2248.py +12 -0
- trueppm_api/apps/projects/migrations/0047_apitokenauditentry_program_and_more.py +55 -0
- trueppm_api/apps/projects/migrations/0048_historicalprogram_color_program_color.py +32 -0
- trueppm_api/apps/projects/migrations/0049_backlog_item.py +112 -0
- trueppm_api/apps/projects/migrations/0050_backlog_item_trgm_search.py +26 -0
- trueppm_api/apps/projects/migrations/0051_alter_calendar_working_days_alter_dependency_lag_and_more.py +144 -0
- trueppm_api/apps/projects/migrations/0052_recurring_tasks.py +278 -0
- trueppm_api/apps/projects/migrations/0053_dependency_dep_pred_serverver_idx_and_more.py +56 -0
- trueppm_api/apps/projects/migrations/0054_sprintscopechange_goal_impact_and_more.py +117 -0
- trueppm_api/apps/projects/migrations/0055_historicaltask_sprint_pending_and_more.py +51 -0
- trueppm_api/apps/projects/migrations/0056_historicalproject_prioritization_model_and_more.py +276 -0
- trueppm_api/apps/projects/migrations/0057_historicalsprint_binding_committed_snapshot_and_more.py +58 -0
- trueppm_api/apps/projects/migrations/0058_historicaltask_delivery_mode_and_more.py +72 -0
- trueppm_api/apps/projects/migrations/0059_forecastsnapshot.py +80 -0
- trueppm_api/apps/projects/migrations/0060_historicalprojectsignalprivacypolicy_and_more.py +90 -0
- trueppm_api/apps/projects/migrations/0061_baselinetask_story_points.py +17 -0
- trueppm_api/apps/projects/migrations/0062_project_is_sample.py +22 -0
- trueppm_api/apps/projects/migrations/0063_historicalsprint_wip_limit_sprint_wip_limit.py +22 -0
- trueppm_api/apps/projects/migrations/0064_sprinttaskoutcome.py +97 -0
- trueppm_api/apps/projects/migrations/0065_historicalsprint_goal_outcome_sprint_goal_outcome.py +32 -0
- trueppm_api/apps/projects/migrations/0066_historicalproject_lead_project_lead.py +38 -0
- trueppm_api/apps/projects/migrations/0067_sprint_exclude_from_velocity.py +22 -0
- trueppm_api/apps/projects/migrations/0068_project_recalculated_at.py +23 -0
- trueppm_api/apps/projects/migrations/0069_iteration_label.py +22 -0
- trueppm_api/apps/projects/migrations/0070_historicalprogram_iteration_label_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0071_backfill_iteration_label_inherit.py +35 -0
- trueppm_api/apps/projects/migrations/0072_pulseresponse_retroboarditem.py +129 -0
- trueppm_api/apps/projects/migrations/0073_sprinttaskoutcome_demo_ready.py +17 -0
- trueppm_api/apps/projects/migrations/0074_historicaltask_blocked_reason_task_blocked_reason.py +30 -0
- trueppm_api/apps/projects/migrations/0075_risk_decimal_short_id.py +42 -0
- trueppm_api/apps/projects/migrations/0076_sprinttaskoutcome_review_polish.py +45 -0
- trueppm_api/apps/projects/migrations/0077_task_blocker_fields.py +111 -0
- trueppm_api/apps/projects/migrations/0078_alter_risktask_unique_together_and_more.py +22 -0
- trueppm_api/apps/projects/migrations/0079_historicalproject_status_date_project_status_date.py +22 -0
- trueppm_api/apps/projects/migrations/0080_alter_historicaltask_type_alter_task_type.py +46 -0
- trueppm_api/apps/projects/migrations/0081_historicalprogram_allow_guests_and_more.py +52 -0
- trueppm_api/apps/projects/migrations/0082_project_last_sync_version.py +90 -0
- trueppm_api/apps/projects/migrations/0083_historicalprogram_mc_history_attribution_audience_and_more.py +108 -0
- trueppm_api/apps/projects/migrations/0084_tasknote.py +71 -0
- trueppm_api/apps/projects/migrations/0085_sprint_ix_sprint_velocity.py +33 -0
- trueppm_api/apps/projects/migrations/0086_board_card_search_trgm.py +33 -0
- trueppm_api/apps/projects/migrations/0087_historicalprogram_task_duration_change_percent_policy_and_more.py +155 -0
- trueppm_api/apps/projects/migrations/0088_historicalprogram_allowed_attachment_types_and_more.py +61 -0
- trueppm_api/apps/projects/migrations/0089_signalceilingraiseproposal_signalceilingraisevote_and_more.py +157 -0
- trueppm_api/apps/projects/migrations/0090_historicaltask_proj_histdate_index.py +59 -0
- trueppm_api/apps/projects/migrations/0091_project_board_cadence.py +39 -0
- trueppm_api/apps/projects/migrations/0092_program_target_date.py +22 -0
- trueppm_api/apps/projects/migrations/0093_cross_project_dependency_consent.py +58 -0
- trueppm_api/apps/projects/migrations/0094_project_decisions_policy.py +90 -0
- trueppm_api/apps/projects/migrations/0095_poker_session_vote.py +127 -0
- trueppm_api/apps/projects/migrations/0095_squashed_0097_release_0_3.py +225 -0
- trueppm_api/apps/projects/migrations/0096_crossprojectslipconflict.py +91 -0
- trueppm_api/apps/projects/migrations/0097_backlogitem_backlogitem_tags_gin_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0098_historicalproject_show_baselines_and_more.py +52 -0
- trueppm_api/apps/projects/migrations/0099_apitoken_scopes.py +48 -0
- trueppm_api/apps/projects/migrations/0100_task_dep_serverver_idx_concurrent.py +75 -0
- trueppm_api/apps/projects/migrations/0101_dependency_deleted_at_task_deleted_at.py +22 -0
- trueppm_api/apps/projects/migrations/0102_project_deleted_at_project_proj_isdel_deletedat_idx.py +25 -0
- trueppm_api/apps/projects/migrations/0103_taskdurationchangeevent_task_dur_evt_sprint_idx.py +18 -0
- trueppm_api/apps/projects/migrations/0104_historicalproject_stale_task_threshold_days_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0104_trash_restore_1113.py +38 -0
- trueppm_api/apps/projects/migrations/0105_historical_changelog_indexes.py +76 -0
- trueppm_api/apps/projects/migrations/0106_boardsavedview_schema_version.py +20 -0
- trueppm_api/apps/projects/migrations/0106_squashed_0158_release_0_4.py +2357 -0
- trueppm_api/apps/projects/migrations/0107_task_activity_event.py +70 -0
- trueppm_api/apps/projects/migrations/0108_remove_apitoken_api_token_scope_xor_and_more.py +117 -0
- trueppm_api/apps/projects/migrations/0109_projectexportjob.py +82 -0
- trueppm_api/apps/projects/migrations/0110_sharelink.py +123 -0
- trueppm_api/apps/projects/migrations/0111_projectcalendarlayer.py +67 -0
- trueppm_api/apps/projects/migrations/0112_sharelink_expires_at_alter_sharelink_content_kind.py +31 -0
- trueppm_api/apps/projects/migrations/0113_alter_historicaltask_percent_complete_and_more.py +35 -0
- trueppm_api/apps/projects/migrations/0114_historicalproject_default_member_role_and_more.py +28 -0
- trueppm_api/apps/projects/migrations/0115_historicalproject_end_date_shift_threshold_days_and_more.py +22 -0
- trueppm_api/apps/projects/migrations/0116_alter_taskactivityevent_event_type.py +28 -0
- trueppm_api/apps/projects/migrations/0117_label_tasklabel_label_tasks_and_more.py +126 -0
- trueppm_api/apps/projects/migrations/0118_programexportjob.py +82 -0
- trueppm_api/apps/projects/migrations/0119_historicalprogram_calendar_program_calendar.py +36 -0
- trueppm_api/apps/projects/migrations/0120_alter_backlogitem_item_type.py +29 -0
- trueppm_api/apps/projects/migrations/0121_task_three_point_estimate_ordered.py +64 -0
- trueppm_api/apps/projects/migrations/0122_task_relation.py +173 -0
- trueppm_api/apps/projects/migrations/0123_remove_historicalproject_agile_features_and_more.py +20 -0
- trueppm_api/apps/projects/migrations/0124_dependency_is_driving.py +17 -0
- trueppm_api/apps/projects/migrations/0125_historicalprogram_estimation_scale_and_more.py +68 -0
- trueppm_api/apps/projects/migrations/0126_projectcustomfield_show_on_card_taskcustomfieldvalue.py +80 -0
- trueppm_api/apps/projects/migrations/0127_historicalprogram_mcp_enabled_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0128_acceptancecriterion_sync_seq_apitoken_sync_seq_and_more.py +192 -0
- trueppm_api/apps/projects/migrations/0129_sharelink_show_milestone_dates.py +20 -0
- trueppm_api/apps/projects/migrations/0130_programimportjob.py +85 -0
- trueppm_api/apps/projects/migrations/0131_historicalprogram_sprint_picker_ready_only_default_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0132_task_scheduled_start.py +17 -0
- trueppm_api/apps/projects/migrations/0133_project_status_date_floor_armed_at.py +17 -0
- trueppm_api/apps/projects/migrations/0134_task_edited_at_task_seeded_at_task_source_id_and_more.py +65 -0
- trueppm_api/apps/projects/migrations/0135_projecttemplate_templateapplication_and_more.py +175 -0
- trueppm_api/apps/projects/migrations/0136_schedule_outline_batch_operations.py +118 -0
- trueppm_api/apps/projects/migrations/0137_collapse_dual_scope_api_tokens.py +54 -0
- trueppm_api/apps/projects/migrations/0138_apitokenauditentry_api_token_audit_owner_idx.py +18 -0
- trueppm_api/apps/projects/migrations/0139_historicaltask_duration_unit_task_duration_unit.py +32 -0
- trueppm_api/apps/projects/migrations/0140_historicaltask_auto_container_and_more.py +113 -0
- trueppm_api/apps/projects/migrations/0141_historicalproject_draft_started_at_and_more.py +44 -0
- trueppm_api/apps/projects/migrations/0142_baseline_calendar_hours_per_day_and_more.py +31 -0
- trueppm_api/apps/projects/migrations/0143_sprintcloserequest_failure_reason_and_more.py +42 -0
- trueppm_api/apps/projects/migrations/0144_projecttemplate_source_project_and_more.py +35 -0
- trueppm_api/apps/projects/migrations/0145_seed_bundled_templates.py +65 -0
- trueppm_api/apps/projects/migrations/0146_historicaltask_board_lane_task_board_lane.py +32 -0
- trueppm_api/apps/projects/migrations/0147_structuraloperation.py +128 -0
- trueppm_api/apps/projects/migrations/0148_task_unique_task_wbs_path_per_project_live.py +76 -0
- trueppm_api/apps/projects/migrations/0149_drop_workshops_tables.py +42 -0
- trueppm_api/apps/projects/migrations/0150_clear_uncommitted_cpm_output.py +130 -0
- trueppm_api/apps/projects/migrations/0151_config_notice_request.py +70 -0
- trueppm_api/apps/projects/migrations/0152_aggregate_task_wbs_name_idx.py +20 -0
- trueppm_api/apps/projects/migrations/0153_program_sample_anchor_date.py +22 -0
- trueppm_api/apps/projects/migrations/0154_object_keys.py +184 -0
- trueppm_api/apps/projects/migrations/0155_task_milestone_at_day_end.py +20 -0
- trueppm_api/apps/projects/migrations/0156_program_import_job_replaced_project_ids.py +17 -0
- trueppm_api/apps/projects/migrations/0157_forecastsnapshot_cpm_finish_at_day_start.py +17 -0
- trueppm_api/apps/projects/migrations/0158_baselinetask_finish_at_day_start.py +17 -0
- trueppm_api/apps/projects/migrations/__init__.py +0 -0
- trueppm_api/apps/projects/models.py +9209 -0
- trueppm_api/apps/projects/poker_services.py +154 -0
- trueppm_api/apps/projects/poker_views.py +398 -0
- trueppm_api/apps/projects/product_backlog_services.py +450 -0
- trueppm_api/apps/projects/program_label_services.py +94 -0
- trueppm_api/apps/projects/program_label_views.py +189 -0
- trueppm_api/apps/projects/program_rollup.py +903 -0
- trueppm_api/apps/projects/program_schedule.py +767 -0
- trueppm_api/apps/projects/program_views.py +3445 -0
- trueppm_api/apps/projects/project_templates.py +422 -0
- trueppm_api/apps/projects/receivers.py +234 -0
- trueppm_api/apps/projects/refusal_codes.py +140 -0
- trueppm_api/apps/projects/reorder_services.py +145 -0
- trueppm_api/apps/projects/restructure_hooks.py +54 -0
- trueppm_api/apps/projects/retro_board_services.py +368 -0
- trueppm_api/apps/projects/retro_services.py +285 -0
- trueppm_api/apps/projects/risk_import.py +396 -0
- trueppm_api/apps/projects/row_identity.py +113 -0
- trueppm_api/apps/projects/schema_migrations.py +228 -0
- trueppm_api/apps/projects/schemas/seed_v1.json +492 -0
- trueppm_api/apps/projects/schemas/seed_v2.json +891 -0
- trueppm_api/apps/projects/seed/__init__.py +61 -0
- trueppm_api/apps/projects/seed/demo_landing_overlay.py +532 -0
- trueppm_api/apps/projects/seed/exporter.py +1717 -0
- trueppm_api/apps/projects/seed/forecast_backfill.py +247 -0
- trueppm_api/apps/projects/seed/importer.py +2764 -0
- trueppm_api/apps/projects/seed/reanchor.py +551 -0
- trueppm_api/apps/projects/seed/reldates.py +126 -0
- trueppm_api/apps/projects/seed/replace.py +128 -0
- trueppm_api/apps/projects/seed/replay.py +1695 -0
- trueppm_api/apps/projects/seed/replay_ctx.py +41 -0
- trueppm_api/apps/projects/seed/samples.py +427 -0
- trueppm_api/apps/projects/seed/validation.py +1169 -0
- trueppm_api/apps/projects/serializers.py +12904 -0
- trueppm_api/apps/projects/services.py +7525 -0
- trueppm_api/apps/projects/share_serializers.py +142 -0
- trueppm_api/apps/projects/share_services.py +373 -0
- trueppm_api/apps/projects/share_views.py +395 -0
- trueppm_api/apps/projects/sharing_settings.py +187 -0
- trueppm_api/apps/projects/signal_privacy_services.py +910 -0
- trueppm_api/apps/projects/signal_privacy_views.py +485 -0
- trueppm_api/apps/projects/signals.py +132 -0
- trueppm_api/apps/projects/slip_conflict.py +288 -0
- trueppm_api/apps/projects/sprint_cadence.py +453 -0
- trueppm_api/apps/projects/sprint_picker_settings.py +132 -0
- trueppm_api/apps/projects/standup.py +304 -0
- trueppm_api/apps/projects/standup_views.py +99 -0
- trueppm_api/apps/projects/structural_operation_services.py +727 -0
- trueppm_api/apps/projects/structural_operation_views.py +311 -0
- trueppm_api/apps/projects/surface_visibility.py +126 -0
- trueppm_api/apps/projects/task_batch_services.py +379 -0
- trueppm_api/apps/projects/task_bulk.py +1244 -0
- trueppm_api/apps/projects/task_classification.py +561 -0
- trueppm_api/apps/projects/task_classification_defaults.py +95 -0
- trueppm_api/apps/projects/task_duration_settings.py +142 -0
- trueppm_api/apps/projects/task_grouping.py +754 -0
- trueppm_api/apps/projects/tasks.py +1979 -0
- trueppm_api/apps/projects/template_divergence.py +168 -0
- trueppm_api/apps/projects/template_services.py +160 -0
- trueppm_api/apps/projects/template_tasks.py +261 -0
- trueppm_api/apps/projects/template_views.py +829 -0
- trueppm_api/apps/projects/throttles.py +311 -0
- trueppm_api/apps/projects/urls.py +1016 -0
- trueppm_api/apps/projects/utilization.py +909 -0
- trueppm_api/apps/projects/views.py +21225 -0
- trueppm_api/apps/projects/wbs_paths.py +119 -0
- trueppm_api/apps/resources/__init__.py +0 -0
- trueppm_api/apps/resources/apps.py +8 -0
- trueppm_api/apps/resources/capacity.py +121 -0
- trueppm_api/apps/resources/migrations/0001_initial.py +68 -0
- trueppm_api/apps/resources/migrations/0001_squashed_0013_alter_projectresource_unique_together_and_more.py +281 -0
- trueppm_api/apps/resources/migrations/0002_alter_uuid_pk_serialize_false.py +36 -0
- trueppm_api/apps/resources/migrations/0003_resource_soft_delete.py +30 -0
- trueppm_api/apps/resources/migrations/0004_add_taskresource_resource_index.py +25 -0
- trueppm_api/apps/resources/migrations/0005_resource_job_role.py +20 -0
- trueppm_api/apps/resources/migrations/0006_skill.py +34 -0
- trueppm_api/apps/resources/migrations/0007_resource_skill.py +63 -0
- trueppm_api/apps/resources/migrations/0008_project_resource.py +63 -0
- trueppm_api/apps/resources/migrations/0009_task_skill_requirement.py +60 -0
- trueppm_api/apps/resources/migrations/0010_alter_resourceskill_options_and_more.py +20 -0
- trueppm_api/apps/resources/migrations/0011_alter_projectresource_notes.py +17 -0
- trueppm_api/apps/resources/migrations/0012_add_resource_user_fk.py +26 -0
- trueppm_api/apps/resources/migrations/0013_alter_projectresource_unique_together_and_more.py +53 -0
- trueppm_api/apps/resources/migrations/0014_projectresource_sync_seq_resource_sync_seq_and_more.py +37 -0
- trueppm_api/apps/resources/migrations/0014_squashed_0015_release_0_4.py +47 -0
- trueppm_api/apps/resources/migrations/0015_projectresource_deactivated_with_resource.py +17 -0
- trueppm_api/apps/resources/migrations/__init__.py +0 -0
- trueppm_api/apps/resources/models.py +298 -0
- trueppm_api/apps/resources/serializers.py +426 -0
- trueppm_api/apps/resources/services.py +465 -0
- trueppm_api/apps/resources/urls.py +28 -0
- trueppm_api/apps/resources/views.py +1752 -0
- trueppm_api/apps/scheduling/__init__.py +0 -0
- trueppm_api/apps/scheduling/apps.py +153 -0
- trueppm_api/apps/scheduling/calendars.py +144 -0
- trueppm_api/apps/scheduling/deadletter.py +91 -0
- trueppm_api/apps/scheduling/finish_reading.py +198 -0
- trueppm_api/apps/scheduling/forecast_history_settings.py +215 -0
- trueppm_api/apps/scheduling/forecast_staleness.py +313 -0
- trueppm_api/apps/scheduling/graph_guard.py +263 -0
- trueppm_api/apps/scheduling/management/__init__.py +0 -0
- trueppm_api/apps/scheduling/management/commands/__init__.py +0 -0
- trueppm_api/apps/scheduling/management/commands/prune_forecast_snapshots.py +53 -0
- trueppm_api/apps/scheduling/mc_admission.py +181 -0
- trueppm_api/apps/scheduling/migrations/0001_failed_task.py +62 -0
- trueppm_api/apps/scheduling/migrations/0001_squashed_0007_projectforecastsnapshot.py +309 -0
- trueppm_api/apps/scheduling/migrations/0002_schedulerequest.py +78 -0
- trueppm_api/apps/scheduling/migrations/0003_add_schedule_request_reason.py +27 -0
- trueppm_api/apps/scheduling/migrations/0004_velocity_suggestion.py +94 -0
- trueppm_api/apps/scheduling/migrations/0005_montecarlorun.py +61 -0
- trueppm_api/apps/scheduling/migrations/0006_montecarlorun_distribution.py +17 -0
- trueppm_api/apps/scheduling/migrations/0007_projectforecastsnapshot.py +65 -0
- trueppm_api/apps/scheduling/migrations/0008_alter_schedulerequest_reason.py +28 -0
- trueppm_api/apps/scheduling/migrations/0008_folded_schedulerequest_reason.py +34 -0
- trueppm_api/apps/scheduling/migrations/0009_alter_schedulerequest_reason.py +29 -0
- trueppm_api/apps/scheduling/migrations/0010_failedtask_resolution_note_failedtask_resolved_at_and_more.py +43 -0
- trueppm_api/apps/scheduling/migrations/0010_squashed_0016_release_0_4.py +106 -0
- trueppm_api/apps/scheduling/migrations/0011_failedtask_project.py +26 -0
- trueppm_api/apps/scheduling/migrations/0012_montecarlorun_diagnostic.py +17 -0
- trueppm_api/apps/scheduling/migrations/0013_montecarlorun_status_date.py +17 -0
- trueppm_api/apps/scheduling/migrations/0014_montecarlorun_plan_version.py +17 -0
- trueppm_api/apps/scheduling/migrations/0015_projectforecastsnapshot_cpm_finish_at_day_start.py +17 -0
- trueppm_api/apps/scheduling/migrations/0016_montecarlorun_finish_readings.py +32 -0
- trueppm_api/apps/scheduling/migrations/__init__.py +0 -0
- trueppm_api/apps/scheduling/models.py +542 -0
- trueppm_api/apps/scheduling/receivers.py +160 -0
- trueppm_api/apps/scheduling/risk_premium.py +334 -0
- trueppm_api/apps/scheduling/serializers.py +723 -0
- trueppm_api/apps/scheduling/services.py +1251 -0
- trueppm_api/apps/scheduling/signals.py +56 -0
- trueppm_api/apps/scheduling/tasks.py +2248 -0
- trueppm_api/apps/scheduling/telemetry.py +80 -0
- trueppm_api/apps/scheduling/units.py +35 -0
- trueppm_api/apps/scheduling/urls.py +57 -0
- trueppm_api/apps/scheduling/views.py +2908 -0
- trueppm_api/apps/sso/__init__.py +0 -0
- trueppm_api/apps/sso/apps.py +19 -0
- trueppm_api/apps/sso/extensions.py +130 -0
- trueppm_api/apps/sso/management/__init__.py +0 -0
- trueppm_api/apps/sso/management/commands/__init__.py +0 -0
- trueppm_api/apps/sso/management/commands/seed_sso_keycloak.py +172 -0
- trueppm_api/apps/sso/migrations/0001_initial.py +119 -0
- trueppm_api/apps/sso/migrations/0002_remove_oidcprovider_workspace_ssoproviderpolicy_and_more.py +169 -0
- trueppm_api/apps/sso/migrations/__init__.py +0 -0
- trueppm_api/apps/sso/models.py +148 -0
- trueppm_api/apps/sso/serializers.py +446 -0
- trueppm_api/apps/sso/services.py +1473 -0
- trueppm_api/apps/sso/urls.py +47 -0
- trueppm_api/apps/sso/views.py +935 -0
- trueppm_api/apps/sync/__init__.py +0 -0
- trueppm_api/apps/sync/apps.py +15 -0
- trueppm_api/apps/sync/backfill.py +208 -0
- trueppm_api/apps/sync/broadcast.py +369 -0
- trueppm_api/apps/sync/conflict.py +262 -0
- trueppm_api/apps/sync/consumers.py +548 -0
- trueppm_api/apps/sync/migrations/0001_initial.py +59 -0
- trueppm_api/apps/sync/migrations/0001_squashed_0002_remove_syncbatch_syncbatch_project_client_batch_uniq_and_more.py +77 -0
- trueppm_api/apps/sync/migrations/0002_remove_syncbatch_syncbatch_project_client_batch_uniq_and_more.py +41 -0
- trueppm_api/apps/sync/migrations/0003_boardevent.py +46 -0
- trueppm_api/apps/sync/migrations/0003_squashed_0005_release_0_4.py +77 -0
- trueppm_api/apps/sync/migrations/0004_seed_sync_seq.py +24 -0
- trueppm_api/apps/sync/migrations/0005_program_sync_sequence.py +35 -0
- trueppm_api/apps/sync/migrations/0006_boardevent_per_project_seq.py +77 -0
- trueppm_api/apps/sync/migrations/__init__.py +0 -0
- trueppm_api/apps/sync/models.py +272 -0
- trueppm_api/apps/sync/pagination.py +231 -0
- trueppm_api/apps/sync/sequence.py +488 -0
- trueppm_api/apps/sync/serializers.py +688 -0
- trueppm_api/apps/sync/tasks.py +260 -0
- trueppm_api/apps/sync/throttles.py +175 -0
- trueppm_api/apps/sync/upload.py +556 -0
- trueppm_api/apps/sync/urls.py +17 -0
- trueppm_api/apps/sync/views.py +957 -0
- trueppm_api/apps/sync/ws_auth.py +193 -0
- trueppm_api/apps/taskruns/__init__.py +0 -0
- trueppm_api/apps/taskruns/apps.py +11 -0
- trueppm_api/apps/taskruns/migrations/0001_initial.py +92 -0
- trueppm_api/apps/taskruns/migrations/__init__.py +0 -0
- trueppm_api/apps/taskruns/models.py +68 -0
- trueppm_api/apps/taskruns/serializers.py +92 -0
- trueppm_api/apps/taskruns/tasks.py +60 -0
- trueppm_api/apps/taskruns/tracker.py +286 -0
- trueppm_api/apps/taskruns/urls.py +46 -0
- trueppm_api/apps/taskruns/views.py +195 -0
- trueppm_api/apps/teams/__init__.py +8 -0
- trueppm_api/apps/teams/apps.py +16 -0
- trueppm_api/apps/teams/migrations/0001_initial.py +139 -0
- trueppm_api/apps/teams/migrations/0001_squashed_0002_default_teams.py +159 -0
- trueppm_api/apps/teams/migrations/0002_default_teams.py +62 -0
- trueppm_api/apps/teams/migrations/0003_team_sync_seq_teammembership_sync_seq.py +22 -0
- trueppm_api/apps/teams/migrations/0004_backfill_default_teams_on_upgrade.py +49 -0
- trueppm_api/apps/teams/migrations/__init__.py +0 -0
- trueppm_api/apps/teams/models.py +145 -0
- trueppm_api/apps/teams/permissions.py +149 -0
- trueppm_api/apps/teams/serializers.py +95 -0
- trueppm_api/apps/teams/services.py +440 -0
- trueppm_api/apps/teams/signals.py +61 -0
- trueppm_api/apps/teams/urls.py +34 -0
- trueppm_api/apps/teams/views.py +201 -0
- trueppm_api/apps/timetracking/__init__.py +0 -0
- trueppm_api/apps/timetracking/apps.py +9 -0
- trueppm_api/apps/timetracking/migrations/0001_initial.py +117 -0
- trueppm_api/apps/timetracking/migrations/0001_squashed_0004_release_0_4.py +167 -0
- trueppm_api/apps/timetracking/migrations/0002_timesheetsubmission.py +46 -0
- trueppm_api/apps/timetracking/migrations/0003_timeentry_deleted_at_timeentry_deleted_by.py +31 -0
- trueppm_api/apps/timetracking/migrations/0004_timeentry_sync_seq_and_more.py +24 -0
- trueppm_api/apps/timetracking/migrations/__init__.py +0 -0
- trueppm_api/apps/timetracking/models.py +178 -0
- trueppm_api/apps/timetracking/serializers.py +175 -0
- trueppm_api/apps/timetracking/services.py +211 -0
- trueppm_api/apps/timetracking/urls.py +47 -0
- trueppm_api/apps/timetracking/views.py +597 -0
- trueppm_api/apps/webhooks/__init__.py +0 -0
- trueppm_api/apps/webhooks/apps.py +8 -0
- trueppm_api/apps/webhooks/backfill.py +90 -0
- trueppm_api/apps/webhooks/dispatch.py +279 -0
- trueppm_api/apps/webhooks/migrations/0001_initial.py +146 -0
- trueppm_api/apps/webhooks/migrations/0001_squashed_0007_sprint_lifecycle_events.py +249 -0
- trueppm_api/apps/webhooks/migrations/0002_alter_webhook_events.py +32 -0
- trueppm_api/apps/webhooks/migrations/0003_delivery_status_created_idx.py +17 -0
- trueppm_api/apps/webhooks/migrations/0004_webhook_program_alter_webhook_project_and_more.py +64 -0
- trueppm_api/apps/webhooks/migrations/0005_webhook_delivery_sequence_numbers.py +30 -0
- trueppm_api/apps/webhooks/migrations/0006_webhook_format_alter_webhook_events_and_more.py +61 -0
- trueppm_api/apps/webhooks/migrations/0007_sprint_lifecycle_events.py +63 -0
- trueppm_api/apps/webhooks/migrations/0008_risk_baseline_comment_events.py +73 -0
- trueppm_api/apps/webhooks/migrations/0009_encrypt_webhook_secret_and_failure_counters.py +100 -0
- trueppm_api/apps/webhooks/migrations/0010_alter_webhook_disabled_at.py +21 -0
- trueppm_api/apps/webhooks/migrations/0011_webhookeditor.py +48 -0
- trueppm_api/apps/webhooks/migrations/0012_alter_webhook_disabled_at.py +21 -0
- trueppm_api/apps/webhooks/migrations/__init__.py +0 -0
- trueppm_api/apps/webhooks/models.py +437 -0
- trueppm_api/apps/webhooks/serializers.py +326 -0
- trueppm_api/apps/webhooks/tasks.py +680 -0
- trueppm_api/apps/webhooks/urls.py +22 -0
- trueppm_api/apps/webhooks/views.py +533 -0
- trueppm_api/apps/workflow_engine/__init__.py +0 -0
- trueppm_api/apps/workflow_engine/apps.py +23 -0
- trueppm_api/apps/workflow_engine/migrations/0001_initial.py +230 -0
- trueppm_api/apps/workflow_engine/migrations/0001_squashed_0002_remove_workflowhistoryevent_workflow_history_lookup_idx.py +234 -0
- trueppm_api/apps/workflow_engine/migrations/0002_remove_workflowhistoryevent_workflow_history_lookup_idx.py +16 -0
- trueppm_api/apps/workflow_engine/migrations/0003_workflowoutboxrow_workflow_outbox_recovery_idx.py +21 -0
- trueppm_api/apps/workflow_engine/migrations/__init__.py +0 -0
- trueppm_api/apps/workflow_engine/models.py +265 -0
- trueppm_api/apps/workflow_engine/tasks.py +371 -0
- trueppm_api/apps/workspace/__init__.py +0 -0
- trueppm_api/apps/workspace/apps.py +10 -0
- trueppm_api/apps/workspace/backfill.py +111 -0
- trueppm_api/apps/workspace/export.py +254 -0
- trueppm_api/apps/workspace/migrations/0001_initial.py +326 -0
- trueppm_api/apps/workspace/migrations/0001_squashed_0014_workspacemembership_availability_effective_from_and_more.py +829 -0
- trueppm_api/apps/workspace/migrations/0002_remove_workspace_fiscal_year_start_and_more.py +85 -0
- trueppm_api/apps/workspace/migrations/0003_workspaceexportjob.py +73 -0
- trueppm_api/apps/workspace/migrations/0004_alter_workspaceinvite_status.py +27 -0
- trueppm_api/apps/workspace/migrations/0005_workspace_iteration_label_and_more.py +26 -0
- trueppm_api/apps/workspace/migrations/0006_alter_groupmembership_unique_together_and_more.py +45 -0
- trueppm_api/apps/workspace/migrations/0007_workspace_public_sharing_override_policy.py +21 -0
- trueppm_api/apps/workspace/migrations/0008_workspace_mc_history_attribution_audience_and_more.py +44 -0
- trueppm_api/apps/workspace/migrations/0009_workspace_methodology_and_more.py +186 -0
- trueppm_api/apps/workspace/migrations/0010_workspace_logo.py +38 -0
- trueppm_api/apps/workspace/migrations/0011_historicalworkspace_task_duration_change_percent_override_policy_and_more.py +56 -0
- trueppm_api/apps/workspace/migrations/0012_historicalworkspace_allowed_attachment_types_and_more.py +64 -0
- trueppm_api/apps/workspace/migrations/0013_auditevent.py +70 -0
- trueppm_api/apps/workspace/migrations/0014_workspacemembership_availability_effective_from_and_more.py +39 -0
- trueppm_api/apps/workspace/migrations/0015_squashed_0027_release_0_4.py +199 -0
- trueppm_api/apps/workspace/migrations/0015_trash_restore_1113.py +34 -0
- trueppm_api/apps/workspace/migrations/0016_historicalworkspace_calendar_and_more.py +55 -0
- trueppm_api/apps/workspace/migrations/0017_historicalworkspace_estimation_scale_and_more.py +38 -0
- trueppm_api/apps/workspace/migrations/0018_historicalworkspace_feedback_enabled_and_more.py +32 -0
- trueppm_api/apps/workspace/migrations/0019_historicalworkspace_mcp_enabled_and_more.py +22 -0
- trueppm_api/apps/workspace/migrations/0020_viewer_ordinal_one.py +34 -0
- trueppm_api/apps/workspace/migrations/0021_group_sync_seq_groupmembership_sync_seq_and_more.py +27 -0
- trueppm_api/apps/workspace/migrations/0022_historicalworkspace_sprint_picker_ready_only_default_and_more.py +22 -0
- trueppm_api/apps/workspace/migrations/0023_alter_auditevent_event_type.py +32 -0
- trueppm_api/apps/workspace/migrations/0024_alter_auditevent_event_type.py +33 -0
- trueppm_api/apps/workspace/migrations/0025_alter_auditevent_event_type.py +36 -0
- trueppm_api/apps/workspace/migrations/0026_alter_auditevent_event_type.py +37 -0
- trueppm_api/apps/workspace/migrations/0027_alter_auditevent_event_type.py +42 -0
- trueppm_api/apps/workspace/migrations/__init__.py +0 -0
- trueppm_api/apps/workspace/models.py +857 -0
- trueppm_api/apps/workspace/permissions.py +187 -0
- trueppm_api/apps/workspace/serializers.py +590 -0
- trueppm_api/apps/workspace/services.py +967 -0
- trueppm_api/apps/workspace/signals.py +37 -0
- trueppm_api/apps/workspace/tasks.py +616 -0
- trueppm_api/apps/workspace/urls.py +113 -0
- trueppm_api/apps/workspace/views.py +1581 -0
- trueppm_api/asgi.py +49 -0
- trueppm_api/celery.py +40 -0
- trueppm_api/core/__init__.py +0 -0
- trueppm_api/core/admin_site.py +206 -0
- trueppm_api/core/auth_views.py +934 -0
- trueppm_api/core/constant_time.py +51 -0
- trueppm_api/core/csp.py +54 -0
- trueppm_api/core/db.py +87 -0
- trueppm_api/core/db_session.py +37 -0
- trueppm_api/core/demo_read_only.py +314 -0
- trueppm_api/core/exception_handlers.py +157 -0
- trueppm_api/core/export_downloads.py +56 -0
- trueppm_api/core/extension_providers.py +56 -0
- trueppm_api/core/extension_signals.py +147 -0
- trueppm_api/core/idempotent.py +260 -0
- trueppm_api/core/metadata.py +42 -0
- trueppm_api/core/middleware.py +51 -0
- trueppm_api/core/openapi.py +1221 -0
- trueppm_api/core/password_reset.py +513 -0
- trueppm_api/core/protect_conflict.py +100 -0
- trueppm_api/core/ratelimit.py +148 -0
- trueppm_api/core/redis_throttle.py +82 -0
- trueppm_api/core/refresh_cookie_policy.py +156 -0
- trueppm_api/core/request_body.py +86 -0
- trueppm_api/core/security_checks.py +1034 -0
- trueppm_api/core/storage_config.py +105 -0
- trueppm_api/core/text_decode.py +168 -0
- trueppm_api/core/throttling.py +514 -0
- trueppm_api/core/valkey.py +214 -0
- trueppm_api/core/valkey_cache.py +66 -0
- trueppm_api/core/valkey_checks.py +104 -0
- trueppm_api/core/valkey_config.py +39 -0
- trueppm_api/core/worker_broker_wait.py +149 -0
- trueppm_api/core/worker_heartbeat.py +134 -0
- trueppm_api/core/worker_selfheal.py +205 -0
- trueppm_api/fields.py +36 -0
- trueppm_api/permissions.py +30 -0
- trueppm_api/py.typed +0 -0
- trueppm_api/routing.py +11 -0
- trueppm_api/settings/__init__.py +0 -0
- trueppm_api/settings/base.py +2605 -0
- trueppm_api/settings/dev.py +296 -0
- trueppm_api/settings/prod.py +265 -0
- trueppm_api/urls.py +217 -0
- trueppm_api/workflows/__init__.py +38 -0
- trueppm_api/workflows/backends/__init__.py +6 -0
- trueppm_api/workflows/backends/default.py +297 -0
- trueppm_api/workflows/consumers/__init__.py +11 -0
- trueppm_api/workflows/consumers/requeue_failed_task.py +65 -0
- trueppm_api/workflows/interface.py +148 -0
- trueppm_api/workflows/registry.py +106 -0
- trueppm_api/workflows/services.py +90 -0
- trueppm_api/wsgi.py +11 -0
- trueppm_api-0.4.0.dist-info/METADATA +273 -0
- trueppm_api-0.4.0.dist-info/RECORD +799 -0
- trueppm_api-0.4.0.dist-info/WHEEL +4 -0
- trueppm_api-0.4.0.dist-info/licenses/LICENSE +201 -0
- trueppm_api-0.4.0.dist-info/licenses/NOTICE +7 -0
- trueppm_api-0.4.0.dist-info/licenses/NOTICES +104 -0
- trueppm_api-0.4.0.dist-info/licenses/licenses/GPL-3.0.txt +674 -0
- trueppm_api-0.4.0.dist-info/licenses/licenses/LGPL-3.0.txt +165 -0
- trueppm_api-0.4.0.dist-info/licenses/licenses/MPL-2.0.txt +373 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Board lane assignment, server-side (#2953, ADR-0843).
|
|
2
|
+
|
|
3
|
+
The case 16 rendering rule renders in the browser
|
|
4
|
+
(``packages/web/src/features/board/laneAssignment.ts``). This is the same rule
|
|
5
|
+
as a server derivation, used as the **oracle for ADR-0843 invariant 1**: the
|
|
6
|
+
structure-declaration suites assert that a row promoted to a container by
|
|
7
|
+
indent, or created as one by import, groups here as a lane and never as a card.
|
|
8
|
+
The three invariants are identical to the browser's, and deliberately so — two
|
|
9
|
+
answers to one question is worse than one answer stated twice:
|
|
10
|
+
|
|
11
|
+
1. **A container is never a card.** A row with structural children is a lane,
|
|
12
|
+
never a work item in a column, at any depth.
|
|
13
|
+
2. **Every task appears exactly once**, in the lane of its top-level container
|
|
14
|
+
ancestor. Containers nested below that lane travel on the card as a crumb.
|
|
15
|
+
3. **Root-level work belongs to the project node**, whose lane carries the
|
|
16
|
+
project's name and is absent when it holds nothing.
|
|
17
|
+
|
|
18
|
+
``group_depth`` defaults to 1 and is a parameter so a caller can cut lanes
|
|
19
|
+
deeper; the depth distribution measured on 2026-08-18 put 94.9% of leaf rows at
|
|
20
|
+
depth <= 2 with no crumb at all, so nothing asks for anything else today.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
from dataclasses import dataclass, field
|
|
26
|
+
|
|
27
|
+
from .models import Task
|
|
28
|
+
|
|
29
|
+
#: Sentinel lane id for work hanging directly off the project node.
|
|
30
|
+
ROOT_LANE_ID = "root"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class Lane:
|
|
35
|
+
"""One board swimlane: a real container, or the project node."""
|
|
36
|
+
|
|
37
|
+
id: str
|
|
38
|
+
name: str
|
|
39
|
+
#: True for the project-node lane — says *which* object it is, not that it lacks one.
|
|
40
|
+
is_root: bool = False
|
|
41
|
+
task_ids: list[str] = field(default_factory=list)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _wbs_parts(task: Task) -> list[str]:
|
|
45
|
+
return str(task.wbs_path).split(".") if task.wbs_path else []
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _container_paths(by_path: dict[str, Task]) -> set[str]:
|
|
49
|
+
"""Every path with something beneath it.
|
|
50
|
+
|
|
51
|
+
A row is a container iff something else sits beneath it. Derived, exactly as
|
|
52
|
+
``task_is_phase`` derives it — this must not diverge from the rollup's notion of a
|
|
53
|
+
phase (ADR-0844: the derived fact wins for the math).
|
|
54
|
+
"""
|
|
55
|
+
container_paths: set[str] = set()
|
|
56
|
+
for path in by_path:
|
|
57
|
+
parts = path.split(".")
|
|
58
|
+
for i in range(1, len(parts)):
|
|
59
|
+
container_paths.add(".".join(parts[:i]))
|
|
60
|
+
return container_paths
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _crumb_for(parts: list[str], lane_path: str, by_path: dict[str, Task]) -> str | None:
|
|
64
|
+
"""The row's own parent name when the lane cannot show it, else ``None``."""
|
|
65
|
+
parent_path = ".".join(parts[:-1])
|
|
66
|
+
if parent_path != lane_path:
|
|
67
|
+
parent = by_path.get(parent_path)
|
|
68
|
+
if parent is not None:
|
|
69
|
+
return parent.name
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def build_lanes(
|
|
74
|
+
tasks: list[Task],
|
|
75
|
+
*,
|
|
76
|
+
project_name: str,
|
|
77
|
+
group_depth: int = 1,
|
|
78
|
+
) -> tuple[list[Lane], dict[str, str]]:
|
|
79
|
+
"""Group ``tasks`` into lanes, and say which crumb each card carries.
|
|
80
|
+
|
|
81
|
+
Returns ``(lanes, crumb_by_task_id)``. A task absent from the crumb map sits
|
|
82
|
+
directly in its lane, which is the overwhelming majority.
|
|
83
|
+
|
|
84
|
+
Parenthood is the ltree ``wbs_path`` — there is no ``parent_id`` column — so
|
|
85
|
+
a lane at ``group_depth=1`` is the first path segment, and the crumb names
|
|
86
|
+
the row's immediate parent when that parent is not the lane itself.
|
|
87
|
+
"""
|
|
88
|
+
by_path: dict[str, Task] = {
|
|
89
|
+
str(t.wbs_path): t for t in tasks if t.wbs_path and not t.is_subtask
|
|
90
|
+
}
|
|
91
|
+
container_paths = _container_paths(by_path)
|
|
92
|
+
|
|
93
|
+
lanes: dict[str, Lane] = {}
|
|
94
|
+
order: list[str] = []
|
|
95
|
+
crumbs: dict[str, str] = {}
|
|
96
|
+
root_lane = Lane(id=ROOT_LANE_ID, name=project_name, is_root=True)
|
|
97
|
+
|
|
98
|
+
for path, task in sorted(by_path.items(), key=lambda kv: _sort_key(kv[0])):
|
|
99
|
+
if path in container_paths:
|
|
100
|
+
continue # invariant 1 — a container is never a card
|
|
101
|
+
|
|
102
|
+
parts = path.split(".")
|
|
103
|
+
if len(parts) <= group_depth:
|
|
104
|
+
root_lane.task_ids.append(str(task.id))
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
lane_path = ".".join(parts[:group_depth])
|
|
108
|
+
head = by_path.get(lane_path)
|
|
109
|
+
if head is None:
|
|
110
|
+
# A gap in the tree (a deleted ancestor) must not drop the card.
|
|
111
|
+
root_lane.task_ids.append(str(task.id))
|
|
112
|
+
continue
|
|
113
|
+
if lane_path not in lanes:
|
|
114
|
+
lanes[lane_path] = Lane(id=str(head.id), name=head.name)
|
|
115
|
+
order.append(lane_path)
|
|
116
|
+
lanes[lane_path].task_ids.append(str(task.id))
|
|
117
|
+
|
|
118
|
+
crumb = _crumb_for(parts, lane_path, by_path)
|
|
119
|
+
if crumb is not None:
|
|
120
|
+
crumbs[str(task.id)] = crumb
|
|
121
|
+
|
|
122
|
+
out = [lanes[p] for p in order]
|
|
123
|
+
# Invariant 3: the project-node lane is absent when it holds nothing.
|
|
124
|
+
if root_lane.task_ids:
|
|
125
|
+
out.append(root_lane)
|
|
126
|
+
return out, crumbs
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _sort_key(path: str) -> tuple[int, ...]:
|
|
130
|
+
"""Numeric WBS ordering — ``1.10`` sorts after ``1.9``, not between 1 and 2."""
|
|
131
|
+
try:
|
|
132
|
+
return tuple(int(p) for p in path.split("."))
|
|
133
|
+
except ValueError:
|
|
134
|
+
return (0,)
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""Bulk-PATCH of inherited settings across many Program or Project rows (ADR-0161, #1233).
|
|
2
|
+
|
|
3
|
+
The settings matrix (Workspace → Programs and Program → Projects) lets an admin set an
|
|
4
|
+
inherited field — methodology, iteration label, risk policy — on a *selection* of entities
|
|
5
|
+
in one call instead of N per-entity PATCHes. This module holds the request envelope, the
|
|
6
|
+
per-scope field-whitelist serializers (which reuse the same field-level validation as the
|
|
7
|
+
per-entity serializers), and the atomic apply routine. The thin ``ProgramViewSet`` actions
|
|
8
|
+
in :mod:`program_views` wire these to two routes.
|
|
9
|
+
|
|
10
|
+
Scope of the 0.3 slice (the rest of #1233's field list is deferred — see ADR-0161):
|
|
11
|
+
* Programs (workspace scope): ``methodology``, ``iteration_label``,
|
|
12
|
+
``risk_slip_propagation``, ``risk_escalation_days``.
|
|
13
|
+
* Projects (program scope): ``methodology``, ``iteration_label``.
|
|
14
|
+
|
|
15
|
+
``calendar`` (Project-only, schedule-affecting with no bulk recalc path yet) and the
|
|
16
|
+
notification defaults (not Program/Project fields — they live in
|
|
17
|
+
``ProjectNotificationPreference``) are deferred to follow-ups.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
from django.db.models import QuerySet
|
|
25
|
+
from rest_framework import serializers
|
|
26
|
+
from rest_framework.exceptions import PermissionDenied
|
|
27
|
+
|
|
28
|
+
from trueppm_api.apps.projects.methodology import methodology_override_locked
|
|
29
|
+
from trueppm_api.apps.projects.models import Program, Project
|
|
30
|
+
from trueppm_api.apps.workspace.models import Workspace
|
|
31
|
+
|
|
32
|
+
# Cap on the rows a single bulk call may touch. Generous for a real workspace (programs) or
|
|
33
|
+
# program (projects) selection, but bounds the per-row ``select_for_update`` + ``save`` loop
|
|
34
|
+
# so the endpoint can't be used to lock a large slice of the table in one request.
|
|
35
|
+
MAX_BULK_TARGETS = 200
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _validate_iteration_label(value: str | None) -> str | None:
|
|
39
|
+
"""Mirror ``Program/ProjectSerializer.validate_iteration_label`` (ADR-0116).
|
|
40
|
+
|
|
41
|
+
``None`` clears the override so the row inherits its parent's label; a non-null
|
|
42
|
+
empty/whitespace string is rejected because "inherit" already has an explicit
|
|
43
|
+
representation (``null``). ``max_length`` is enforced by the model field.
|
|
44
|
+
"""
|
|
45
|
+
if value is None:
|
|
46
|
+
return None
|
|
47
|
+
stripped = value.strip()
|
|
48
|
+
if not stripped:
|
|
49
|
+
raise serializers.ValidationError(
|
|
50
|
+
"Enter a label for the iteration container, or clear it to inherit the parent default."
|
|
51
|
+
)
|
|
52
|
+
return stripped
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class _InheritedMethodologyMixin:
|
|
56
|
+
"""Shared ``methodology`` lock backstop (ADR-0107 §4).
|
|
57
|
+
|
|
58
|
+
A per-entity methodology override is forbidden only while a workspace enforcement lock
|
|
59
|
+
is active — which never happens in OSS (no enforcement provider is registered), so this
|
|
60
|
+
is the server-side backstop for a direct API write. Re-sending the current value is a
|
|
61
|
+
harmless no-op and is allowed even under a lock. ``PermissionDenied`` (403) is the
|
|
62
|
+
correct response for a policy refusal, matching the per-entity serializers.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
instance: Any # set by DRF when the serializer wraps a model row
|
|
66
|
+
context: dict[str, Any] # provided by the DRF serializer this mixes into
|
|
67
|
+
|
|
68
|
+
def validate_methodology(self, value: str) -> str:
|
|
69
|
+
instance = getattr(self, "instance", None)
|
|
70
|
+
if instance is not None and value == instance.methodology:
|
|
71
|
+
return value
|
|
72
|
+
# Read the singleton from context (hoisted once per bulk call by
|
|
73
|
+
# apply_bulk_fields) so a 200-row batch doesn't reload it per row; fall back to a
|
|
74
|
+
# direct load when the serializer is used standalone.
|
|
75
|
+
workspace = self.context.get("workspace") or Workspace.load()
|
|
76
|
+
if methodology_override_locked(workspace):
|
|
77
|
+
raise PermissionDenied(
|
|
78
|
+
"This workspace's methodology policy locks the delivery model to the "
|
|
79
|
+
"workspace default — it can't be set per entity."
|
|
80
|
+
)
|
|
81
|
+
return value
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ProgramBulkFieldsSerializer(_InheritedMethodologyMixin, serializers.ModelSerializer[Program]):
|
|
85
|
+
"""Whitelist + field validation for a workspace-scope program bulk-PATCH."""
|
|
86
|
+
|
|
87
|
+
class Meta:
|
|
88
|
+
model = Program
|
|
89
|
+
fields = [ # noqa: RUF012 — DRF Meta field list (matches the serializers.py per-file ignore)
|
|
90
|
+
"methodology",
|
|
91
|
+
"iteration_label",
|
|
92
|
+
"risk_slip_propagation",
|
|
93
|
+
"risk_escalation_days",
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
def validate_iteration_label(self, value: str | None) -> str | None:
|
|
97
|
+
return _validate_iteration_label(value)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class ProjectBulkFieldsSerializer(_InheritedMethodologyMixin, serializers.ModelSerializer[Project]):
|
|
101
|
+
"""Whitelist + field validation for a program-scope project bulk-PATCH.
|
|
102
|
+
|
|
103
|
+
Deliberately narrower than :class:`ProgramBulkFieldsSerializer`: ``calendar`` is
|
|
104
|
+
omitted (schedule-affecting, no bulk recalc path yet) and the program-only risk fields
|
|
105
|
+
do not exist on Project. Only the two benign, non-schedule inherited fields ship here.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
class Meta:
|
|
109
|
+
model = Project
|
|
110
|
+
fields = ["methodology", "iteration_label"] # noqa: RUF012 — DRF Meta field list
|
|
111
|
+
|
|
112
|
+
def validate_iteration_label(self, value: str | None) -> str | None:
|
|
113
|
+
return _validate_iteration_label(value)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class BulkFieldsRequestSerializer(serializers.Serializer[Any]):
|
|
117
|
+
"""Request envelope: which rows to change, and which fields to set on them.
|
|
118
|
+
|
|
119
|
+
``ids`` are the entities the user checked; ``fields`` is the partial field map to apply.
|
|
120
|
+
Only the named fields on the named rows change — every other row and every other field
|
|
121
|
+
keeps inheriting (#1233). The *values* in ``fields`` are validated per-scope by the
|
|
122
|
+
per-entity serializer the caller passes to :func:`apply_bulk_fields`; this envelope only
|
|
123
|
+
enforces the request shape (non-empty, well-typed ids, bounded count).
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
ids = serializers.ListField(
|
|
127
|
+
child=serializers.UUIDField(),
|
|
128
|
+
allow_empty=False,
|
|
129
|
+
max_length=MAX_BULK_TARGETS,
|
|
130
|
+
)
|
|
131
|
+
# The wire key is "fields" (the partial field map). Declaring a field named ``fields``
|
|
132
|
+
# shadows DRF's base ``Serializer.fields`` property for the type checker only — at
|
|
133
|
+
# runtime declared fields live in ``_declared_fields`` and the ``.fields`` property
|
|
134
|
+
# still returns the BindingDict (verified by the endpoint tests).
|
|
135
|
+
fields = serializers.DictField(allow_empty=False) # type: ignore[assignment]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def apply_bulk_fields(
|
|
139
|
+
*,
|
|
140
|
+
field_serializer_cls: type[serializers.ModelSerializer[Any]],
|
|
141
|
+
queryset: QuerySet[Any],
|
|
142
|
+
ids: list[Any],
|
|
143
|
+
fields: dict[str, Any],
|
|
144
|
+
) -> list[Any]:
|
|
145
|
+
"""Validate ``fields`` against the scope whitelist and apply them to the rows in
|
|
146
|
+
``queryset`` whose pk is in ``ids``. **Must run inside ``transaction.atomic()``**
|
|
147
|
+
(it locks the targets with ``select_for_update``).
|
|
148
|
+
|
|
149
|
+
Raises ``serializers.ValidationError`` (→ 400) for a field not bulk-editable in this
|
|
150
|
+
scope, an id outside the allowed scope, or a bad value. All-or-nothing: any failure
|
|
151
|
+
raises inside the caller's atomic block and rolls the whole batch back. Returns the
|
|
152
|
+
updated rows with their freshly bumped ``server_version``.
|
|
153
|
+
"""
|
|
154
|
+
allowed = set(field_serializer_cls.Meta.fields)
|
|
155
|
+
unknown = sorted(set(fields) - allowed)
|
|
156
|
+
if unknown:
|
|
157
|
+
raise serializers.ValidationError(
|
|
158
|
+
{"fields": f"Not bulk-editable in this scope: {unknown}. Allowed: {sorted(allowed)}."}
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Dedupe while preserving the caller's order; compare as str so UUID objects and the
|
|
162
|
+
# DB's UUID pks match regardless of representation.
|
|
163
|
+
unique_ids = list(dict.fromkeys(str(i) for i in ids))
|
|
164
|
+
rows = list(queryset.filter(pk__in=unique_ids).select_for_update())
|
|
165
|
+
found = {str(r.pk) for r in rows}
|
|
166
|
+
missing = [i for i in unique_ids if i not in found]
|
|
167
|
+
if missing:
|
|
168
|
+
# 400, not silent skip: an id outside scope is a client error (wrong program,
|
|
169
|
+
# archived/closed/deleted row, or another tenant's entity) the caller should see.
|
|
170
|
+
raise serializers.ValidationError(
|
|
171
|
+
{"ids": f"Not found or outside the allowed scope: {missing}."}
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Hoist the workspace singleton out of the loop — the methodology validator needs it,
|
|
175
|
+
# and reloading it per row would be a needless N+1 on a 200-row batch (perf-check #1233).
|
|
176
|
+
workspace = Workspace.load()
|
|
177
|
+
for row in rows:
|
|
178
|
+
ser = field_serializer_cls(row, data=fields, partial=True, context={"workspace": workspace})
|
|
179
|
+
ser.is_valid(raise_exception=True)
|
|
180
|
+
ser.save() # per-row save() so VersionedModel bumps server_version + history audits
|
|
181
|
+
return rows
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def build_bulk_response(rows: list[Any], fields: dict[str, Any]) -> dict[str, Any]:
|
|
185
|
+
"""Lightweight, context-free response for a bulk apply.
|
|
186
|
+
|
|
187
|
+
Returns each touched row's id and its new ``server_version`` (so an offline client can
|
|
188
|
+
advance its sync watermark) plus the field names applied — not a full re-serialization,
|
|
189
|
+
which would need the viewset's queryset annotations and request context.
|
|
190
|
+
"""
|
|
191
|
+
return {
|
|
192
|
+
"updated": [{"id": str(r.pk), "server_version": r.server_version} for r in rows],
|
|
193
|
+
"fields": sorted(fields),
|
|
194
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""The starter templates that ship with the install (#2909, ADR-0789).
|
|
2
|
+
|
|
3
|
+
Why these exist at all: **Template** is one of three peer ways in on the Start
|
|
4
|
+
sheet, and on every fresh install it was empty — the only row-creation site was
|
|
5
|
+
the publish action, and no publish UI existed. A way-in that is empty on first
|
|
6
|
+
contact is worse than no way-in, because the user has already chosen it.
|
|
7
|
+
|
|
8
|
+
They also carry the product's own argument. `createdProjectDestination` sends an
|
|
9
|
+
**AGILE + template** project straight to a seeding Product Backlog rather than to
|
|
10
|
+
an empty Schedule, which is the "this is a sprint tool, not a Gantt with a board
|
|
11
|
+
bolted on" signal a delivery lead is looking for — and until now that path could
|
|
12
|
+
not be walked, because it needed a template that did not exist.
|
|
13
|
+
|
|
14
|
+
Deliberately small. A starter is a **shape to argue with**, not a plan: enough
|
|
15
|
+
structure that the phases and the dependency spine are visible, few enough rows
|
|
16
|
+
that deleting the half that does not apply is a minute's work. A 140-row starter
|
|
17
|
+
reads as somebody else's project.
|
|
18
|
+
|
|
19
|
+
They are `COMMUNITY` provenance, which is what the gallery labels "Bundled" and
|
|
20
|
+
sorts last — on a workspace that has published its own shapes, the local ones are
|
|
21
|
+
the ones worth reading first.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from typing import Any
|
|
27
|
+
|
|
28
|
+
#: Names are the identity: the seeding migration is idempotent on them, so
|
|
29
|
+
#: renaming one here creates a second row rather than editing the first.
|
|
30
|
+
SCRUM_TEAM = "Scrum product team"
|
|
31
|
+
STAGE_GATE = "Stage-gate delivery"
|
|
32
|
+
HYBRID_RELEASE = "Regulated release"
|
|
33
|
+
|
|
34
|
+
BUNDLED_TEMPLATE_NAMES = (SCRUM_TEAM, STAGE_GATE, HYBRID_RELEASE)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _node(
|
|
38
|
+
ref: str,
|
|
39
|
+
name: str,
|
|
40
|
+
path: str,
|
|
41
|
+
*,
|
|
42
|
+
duration: int | None = 5,
|
|
43
|
+
milestone: bool = False,
|
|
44
|
+
mode: str = "waterfall",
|
|
45
|
+
governance: str = "flow",
|
|
46
|
+
task_type: str = "task",
|
|
47
|
+
notes: str = "",
|
|
48
|
+
) -> dict[str, Any]:
|
|
49
|
+
return {
|
|
50
|
+
"ref": ref,
|
|
51
|
+
"name": name,
|
|
52
|
+
"wbs_path": path,
|
|
53
|
+
"duration": 0 if milestone else duration,
|
|
54
|
+
"is_milestone": milestone,
|
|
55
|
+
"delivery_mode": "milestone" if milestone else mode,
|
|
56
|
+
"governance_class": governance,
|
|
57
|
+
"type": task_type,
|
|
58
|
+
"is_subtask": False,
|
|
59
|
+
"notes": notes,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _document(
|
|
64
|
+
methodology: str,
|
|
65
|
+
tasks: list[dict[str, Any]],
|
|
66
|
+
dependencies: list[dict[str, Any]],
|
|
67
|
+
*,
|
|
68
|
+
sprint_length: int | None = None,
|
|
69
|
+
) -> dict[str, Any]:
|
|
70
|
+
"""Wrap nodes in the structure envelope `validate_structure` accepts.
|
|
71
|
+
|
|
72
|
+
``extracted_at`` is deliberately absent: these were not extracted from any
|
|
73
|
+
project, and stamping a time would imply a provenance they do not have. The
|
|
74
|
+
field is optional in the envelope for exactly this case.
|
|
75
|
+
"""
|
|
76
|
+
carries = ["structure"]
|
|
77
|
+
if dependencies:
|
|
78
|
+
carries.append("dependencies")
|
|
79
|
+
if any(t["duration"] for t in tasks):
|
|
80
|
+
carries.append("durations")
|
|
81
|
+
if any(t["is_milestone"] for t in tasks):
|
|
82
|
+
carries.append("milestones")
|
|
83
|
+
carries.append("delivery_modes")
|
|
84
|
+
if sprint_length:
|
|
85
|
+
carries.append("sprint_length")
|
|
86
|
+
return {
|
|
87
|
+
"version": 1,
|
|
88
|
+
"methodology": methodology,
|
|
89
|
+
"sprint_length_days": sprint_length,
|
|
90
|
+
"tasks": tasks,
|
|
91
|
+
"dependencies": dependencies,
|
|
92
|
+
"carries": carries,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _fs(pred: str, succ: str, lag: int = 0) -> dict[str, Any]:
|
|
97
|
+
return {"predecessor": pred, "successor": succ, "dep_type": "FS", "lag": lag}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def scrum_product_team() -> dict[str, Any]:
|
|
101
|
+
"""A squad's first two sprints, plus the discovery that precedes them."""
|
|
102
|
+
tasks = [
|
|
103
|
+
_node("dsc", "Discovery", "1", duration=10, mode="scrum"),
|
|
104
|
+
_node("dsc-1", "Frame the problem and the users", "1.1", duration=3, mode="scrum"),
|
|
105
|
+
_node("dsc-2", "Shape the first slice", "1.2", duration=4, mode="scrum"),
|
|
106
|
+
_node("dsc-3", "Size and order the backlog", "1.3", duration=3, mode="scrum"),
|
|
107
|
+
_node("rdy", "Backlog ready", "1.4", milestone=True),
|
|
108
|
+
_node("s1", "Sprint 1 — walking skeleton", "2", duration=10, mode="scrum"),
|
|
109
|
+
_node("s1-1", "Thinnest end-to-end path", "2.1", duration=5, mode="scrum"),
|
|
110
|
+
_node("s1-2", "Make it demonstrable", "2.2", duration=3, mode="scrum"),
|
|
111
|
+
_node("s1-3", "Sprint review and retro", "2.3", duration=1, mode="scrum"),
|
|
112
|
+
_node("s2", "Sprint 2 — the first real slice", "3", duration=10, mode="scrum"),
|
|
113
|
+
_node("s2-1", "Build the slice", "3.1", duration=6, mode="scrum"),
|
|
114
|
+
_node("s2-2", "Harden and instrument", "3.2", duration=3, mode="scrum"),
|
|
115
|
+
_node("s2-3", "Sprint review and retro", "3.3", duration=1, mode="scrum"),
|
|
116
|
+
]
|
|
117
|
+
deps = [_fs("dsc", "s1"), _fs("s1", "s2"), _fs("dsc-3", "rdy")]
|
|
118
|
+
return _document("AGILE", tasks, deps, sprint_length=10)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def stage_gate_delivery() -> dict[str, Any]:
|
|
122
|
+
"""Five gated phases with a hold point at each — the classic waterfall spine."""
|
|
123
|
+
tasks = [
|
|
124
|
+
_node("ini", "Initiate", "1", duration=10, governance="gated"),
|
|
125
|
+
_node("ini-1", "Charter and scope", "1.1", duration=5, governance="gated"),
|
|
126
|
+
_node("ini-2", "Stakeholders and constraints", "1.2", duration=5, governance="gated"),
|
|
127
|
+
_node("g1", "Gate 1 — approved to plan", "1.3", milestone=True, governance="gated"),
|
|
128
|
+
_node("pln", "Plan", "2", duration=15, governance="gated"),
|
|
129
|
+
_node("pln-1", "Work breakdown", "2.1", duration=7, governance="gated"),
|
|
130
|
+
_node("pln-2", "Schedule and resource plan", "2.2", duration=8, governance="gated"),
|
|
131
|
+
_node("g2", "Gate 2 — approved to execute", "2.3", milestone=True, governance="gated"),
|
|
132
|
+
_node("exe", "Execute", "3", duration=40, governance="gated"),
|
|
133
|
+
_node("exe-1", "Build", "3.1", duration=25, governance="gated"),
|
|
134
|
+
_node("exe-2", "Integrate", "3.2", duration=15, governance="gated"),
|
|
135
|
+
_node("ver", "Verify", "4", duration=15, governance="gated"),
|
|
136
|
+
_node("ver-1", "Test and defect burn-down", "4.1", duration=10, governance="gated"),
|
|
137
|
+
_node("ver-2", "Acceptance", "4.2", duration=5, governance="gated"),
|
|
138
|
+
_node("g3", "Gate 3 — approved to release", "4.3", milestone=True, governance="gated"),
|
|
139
|
+
_node("clo", "Close", "5", duration=10, governance="gated"),
|
|
140
|
+
_node("clo-1", "Handover and documentation", "5.1", duration=6, governance="gated"),
|
|
141
|
+
_node("clo-2", "Lessons learned", "5.2", duration=4, governance="gated"),
|
|
142
|
+
_node("g4", "Gate 4 — closed", "5.3", milestone=True, governance="gated"),
|
|
143
|
+
]
|
|
144
|
+
deps = [
|
|
145
|
+
_fs("ini", "pln"),
|
|
146
|
+
_fs("pln", "exe"),
|
|
147
|
+
_fs("exe", "ver"),
|
|
148
|
+
_fs("ver", "clo"),
|
|
149
|
+
_fs("ini-2", "g1"),
|
|
150
|
+
_fs("pln-2", "g2"),
|
|
151
|
+
_fs("ver-2", "g3"),
|
|
152
|
+
_fs("clo-2", "g4"),
|
|
153
|
+
_fs("exe-1", "exe-2"),
|
|
154
|
+
]
|
|
155
|
+
return _document("WATERFALL", tasks, deps)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def regulated_release() -> dict[str, Any]:
|
|
159
|
+
"""A gated validation branch beside a sprint-driven build branch.
|
|
160
|
+
|
|
161
|
+
The shape hybrid exists for: the build runs in sprints and the evidence trail
|
|
162
|
+
runs on gates, and they converge once rather than interleaving.
|
|
163
|
+
"""
|
|
164
|
+
tasks = [
|
|
165
|
+
_node("pre", "Preparation", "1", duration=10, governance="hybrid"),
|
|
166
|
+
_node("pre-1", "Scope and regulatory basis", "1.1", duration=5, governance="gated"),
|
|
167
|
+
_node("pre-2", "Backlog and release goal", "1.2", duration=5, mode="scrum"),
|
|
168
|
+
_node("bld", "Build", "2", duration=30, mode="scrum"),
|
|
169
|
+
_node("bld-1", "Sprint 1", "2.1", duration=10, mode="scrum"),
|
|
170
|
+
_node("bld-2", "Sprint 2", "2.2", duration=10, mode="scrum"),
|
|
171
|
+
_node("bld-3", "Sprint 3", "2.3", duration=10, mode="scrum"),
|
|
172
|
+
_node("val", "Validation", "3", duration=20, governance="gated"),
|
|
173
|
+
_node("val-1", "Protocol and traceability", "3.1", duration=8, governance="gated"),
|
|
174
|
+
_node("val-2", "Execute and record evidence", "3.2", duration=12, governance="gated"),
|
|
175
|
+
_node("gv", "Validation gate", "3.3", milestone=True, governance="gated"),
|
|
176
|
+
_node("rel", "Release", "4", duration=8, governance="gated"),
|
|
177
|
+
_node("rel-1", "Release notes and sign-off", "4.1", duration=5, governance="gated"),
|
|
178
|
+
_node("rel-2", "Deploy", "4.2", duration=3, governance="gated"),
|
|
179
|
+
_node("gr", "Released", "4.3", milestone=True, governance="gated"),
|
|
180
|
+
]
|
|
181
|
+
deps = [
|
|
182
|
+
_fs("pre", "bld"),
|
|
183
|
+
_fs("pre-1", "val-1"),
|
|
184
|
+
_fs("bld-1", "bld-2"),
|
|
185
|
+
_fs("bld-2", "bld-3"),
|
|
186
|
+
_fs("bld", "val-2"),
|
|
187
|
+
_fs("val-2", "gv"),
|
|
188
|
+
_fs("gv", "rel"),
|
|
189
|
+
_fs("rel-2", "gr"),
|
|
190
|
+
]
|
|
191
|
+
return _document("HYBRID", tasks, deps, sprint_length=10)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
#: ``(name, description, structure_builder)`` — one starter per methodology, so
|
|
195
|
+
#: whichever way in a new team picks, the gallery has something for it.
|
|
196
|
+
BUNDLED_TEMPLATES: tuple[tuple[str, str, Any], ...] = (
|
|
197
|
+
(
|
|
198
|
+
SCRUM_TEAM,
|
|
199
|
+
"Discovery, then two sprints that build a walking skeleton before a real "
|
|
200
|
+
"slice. For a squad with no history yet.",
|
|
201
|
+
scrum_product_team,
|
|
202
|
+
),
|
|
203
|
+
(
|
|
204
|
+
STAGE_GATE,
|
|
205
|
+
"Five gated phases with a hold point at each. Heavy on milestones, light "
|
|
206
|
+
"on tasks — the spine, not the plan.",
|
|
207
|
+
stage_gate_delivery,
|
|
208
|
+
),
|
|
209
|
+
(
|
|
210
|
+
HYBRID_RELEASE,
|
|
211
|
+
"A gated validation branch beside a sprint-driven build branch, converging "
|
|
212
|
+
"once at release. For work that ships iteratively and must evidence itself.",
|
|
213
|
+
regulated_release,
|
|
214
|
+
),
|
|
215
|
+
)
|