core-framework 2.1.0__tar.gz → 2.2.0__tar.gz

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 (634) hide show
  1. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/api-layer.mdc +1 -1
  2. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/application-layer.mdc +1 -1
  3. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/constitution.mdc +7 -1
  4. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/domain-caller-context.mdc +1 -1
  5. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/domain-imports.mdc +2 -2
  6. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/domain-repository-exceptions.mdc +5 -2
  7. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/error-boundary.mdc +4 -3
  8. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/layer-boundaries.mdc +1 -1
  9. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/strong-reads.mdc +4 -4
  10. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/skills/code-review/SKILL.md +1 -1
  11. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/skills/implement-feature/SKILL.md +1 -1
  12. {core_framework-2.1.0 → core_framework-2.2.0}/.github/workflows/_deploy.yml +2 -0
  13. {core_framework-2.1.0 → core_framework-2.2.0}/.github/workflows/test.yaml +5 -10
  14. {core_framework-2.1.0 → core_framework-2.2.0}/CHANGELOG.md +33 -1
  15. {core_framework-2.1.0 → core_framework-2.2.0}/PKG-INFO +1 -1
  16. core_framework-2.2.0/alembic/moderation/alembic/versions/moderation_add_event_outbox.py +52 -0
  17. core_framework-2.2.0/alembic/moderation/alembic/versions/moderation_add_event_outbox_dead_indexes.py +34 -0
  18. core_framework-2.2.0/alembic/moderation/alembic/versions/moderation_add_event_outbox_pending_created_at_index.py +28 -0
  19. core_framework-2.2.0/alembic/post/alembic/versions/post_post_views_retention_high_water_mark.py +64 -0
  20. core_framework-2.2.0/alembic/user/alembic/versions/user_add_event_outbox.py +52 -0
  21. core_framework-2.2.0/alembic/user/alembic/versions/user_add_event_outbox_dead_indexes.py +34 -0
  22. core_framework-2.2.0/alembic/user/alembic/versions/user_add_event_outbox_pending_created_at_index.py +28 -0
  23. {core_framework-2.1.0 → core_framework-2.2.0}/config.toml +12 -1
  24. {core_framework-2.1.0 → core_framework-2.2.0}/config.toml.template +13 -2
  25. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/cache/router.py +2 -8
  26. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/comments/router.py +3 -13
  27. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/moderation/router.py +2 -10
  28. core_framework-2.2.0/core_framework/api/admin/outbox/router.py +71 -0
  29. core_framework-2.2.0/core_framework/api/admin/outbox/schemas.py +56 -0
  30. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/posts/router.py +3 -12
  31. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/router.py +2 -0
  32. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/users/router.py +2 -10
  33. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/users/schemas.py +1 -1
  34. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/comments/authenticated/router.py +5 -25
  35. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/comments/authenticated/schemas.py +1 -4
  36. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/events/router.py +12 -11
  37. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/events/schemas.py +4 -3
  38. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/notifications/authenticated/router.py +2 -8
  39. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/posts/authenticated/router.py +1 -5
  40. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/posts/authenticated/schemas.py +1 -4
  41. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/authenticated/router.py +10 -41
  42. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/bootstrap.py +14 -0
  43. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/comments/admin_service.py +2 -10
  44. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/comments/authenticated_service.py +5 -15
  45. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/comments/public_service.py +2 -11
  46. core_framework-2.2.0/core_framework/application/events/README.md +35 -0
  47. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/events/event_service.py +29 -21
  48. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/events/event_token.py +7 -12
  49. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/events/models.py +1 -3
  50. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/media/README.md +3 -1
  51. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/media/attachment_service.py +12 -23
  52. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/media/avatar_service.py +8 -13
  53. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/media/banner_service.py +8 -13
  54. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/media/ingest_guards.py +1 -5
  55. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/moderation/appeal_service.py +43 -39
  56. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/moderation/moderator_service.py +1 -6
  57. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/moderation/user_service.py +42 -64
  58. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/notifications/inbox_service.py +2 -11
  59. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/notifications/mute_service.py +1 -5
  60. core_framework-2.2.0/core_framework/application/outbox/block_mirrors.py +54 -0
  61. core_framework-2.2.0/core_framework/application/outbox/events.py +109 -0
  62. core_framework-2.2.0/core_framework/application/outbox/exceptions.py +2 -0
  63. core_framework-2.2.0/core_framework/application/outbox/follow_mirrors.py +20 -0
  64. core_framework-2.2.0/core_framework/application/outbox/handlers.py +115 -0
  65. core_framework-2.2.0/core_framework/application/outbox/ops_service.py +77 -0
  66. core_framework-2.2.0/core_framework/application/outbox/polling_service.py +64 -0
  67. core_framework-2.2.0/core_framework/application/outbox/processing_service.py +69 -0
  68. core_framework-2.2.0/core_framework/application/outbox/restriction_mirrors.py +46 -0
  69. core_framework-2.2.0/core_framework/application/posts/aggregation_service.py +54 -0
  70. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/posts/authenticated_service.py +2 -13
  71. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/posts/public_service.py +1 -6
  72. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/shared/enums.py +1 -0
  73. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/shared/exceptions.py +6 -0
  74. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/users/admin_service.py +7 -32
  75. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/users/authenticated_service.py +53 -52
  76. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/users/public_service.py +2 -2
  77. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/users/user_deletion_service.py +6 -2
  78. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/database.py +1 -6
  79. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/exception_handlers/application.py +17 -28
  80. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/exception_handlers/common.py +2 -8
  81. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/exception_handlers/setup.py +8 -8
  82. core_framework-2.2.0/core_framework/core/exceptions.py +2 -0
  83. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/logging.py +1 -5
  84. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/middleware.py +1 -6
  85. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/pagination.py +4 -2
  86. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/runtime.py +6 -0
  87. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/settings.py +46 -2
  88. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/comment/README.md +3 -2
  89. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/comment/repository.py +6 -83
  90. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/comment/service.py +7 -72
  91. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/attachment/components/finals_publisher.py +1 -7
  92. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/attachment/ports/finals_publisher.py +1 -7
  93. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/attachment/service.py +3 -13
  94. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/service.py +4 -20
  95. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/banner/service.py +3 -13
  96. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/shared/repository.py +4 -24
  97. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/moderation/dependencies.py +28 -2
  98. core_framework-2.2.0/core_framework/domains/moderation/outbox_repository.py +179 -0
  99. core_framework-2.2.0/core_framework/domains/moderation/outbox_service.py +52 -0
  100. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/moderation/repository.py +93 -26
  101. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/moderation/service.py +86 -24
  102. core_framework-2.2.0/core_framework/domains/outbox/__init__.py +17 -0
  103. core_framework-2.2.0/core_framework/domains/outbox/dependencies.py +61 -0
  104. core_framework-2.2.0/core_framework/domains/outbox/models.py +79 -0
  105. core_framework-2.2.0/core_framework/domains/outbox/ports/admin.py +35 -0
  106. core_framework-2.2.0/core_framework/domains/outbox/ports/consumer.py +78 -0
  107. core_framework-2.2.0/core_framework/domains/outbox/ports/producer.py +42 -0
  108. core_framework-2.2.0/core_framework/domains/outbox/service.py +66 -0
  109. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/post/README.md +4 -3
  110. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/post/models.py +12 -0
  111. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/post/repository.py +90 -65
  112. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/post/service.py +51 -44
  113. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/dependencies.py +28 -2
  114. core_framework-2.2.0/core_framework/domains/user/outbox_repository.py +178 -0
  115. core_framework-2.2.0/core_framework/domains/user/outbox_service.py +52 -0
  116. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/outcomes.py +1 -0
  117. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/repository.py +165 -59
  118. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/service.py +93 -52
  119. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/ssh_attachment_finals_publisher_adapter.py +3 -21
  120. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/ssh_banner_finals_publisher_adapter.py +2 -14
  121. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/ssh_finals_publisher_adapter.py +2 -14
  122. core_framework-2.2.0/core_framework/infrastructure/outbox/outbox_consumer_adapter.py +150 -0
  123. core_framework-2.2.0/core_framework/infrastructure/outbox/outbox_producer_adapter.py +71 -0
  124. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/arq.py +22 -20
  125. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/auth.py +62 -48
  126. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/containers.py +1 -5
  127. core_framework-2.2.0/core_framework/testing/firebase_identity_toolkit.py +20 -0
  128. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/media.py +2 -14
  129. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/main.py +19 -4
  130. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/schedules/__init__.py +22 -0
  131. core_framework-2.2.0/core_framework/worker/schedules/schedule_poll_outbox.py +42 -0
  132. core_framework-2.2.0/core_framework/worker/schedules/schedule_prune_post_views.py +17 -0
  133. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/schedules/schedule_sweep_stale_avatar_staging.py +2 -2
  134. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/schedules/schedule_sweep_stale_banner_staging.py +2 -2
  135. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/__init__.py +14 -0
  136. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_attachment_asset_variants.py +1 -6
  137. core_framework-2.2.0/core_framework/worker/tasks/process_outbox_row.py +7 -0
  138. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/deploy-playbook.md +1 -0
  139. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/e2e-smoke-tests-design.md +1 -1
  140. core_framework-2.2.0/docs/domains/README.md +18 -0
  141. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/auth/access_control.md +1 -0
  142. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/cache/admin_cache_invalidation.md +9 -9
  143. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/events/events.md +21 -7
  144. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/media/avatar-upload-design.md +1 -1
  145. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/media/banner-upload-design.md +1 -1
  146. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/media/post-comment-attachments-design.md +26 -27
  147. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/media/upload-pipeline-design.md +28 -30
  148. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/moderation/appeals.md +35 -17
  149. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/moderation/restrictions.md +28 -22
  150. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/notifications/notification_inbox.md +1 -1
  151. core_framework-2.2.0/docs/domains/outbox/admin_outbox_ops.md +182 -0
  152. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/posts/post_stats_aggregation.md +4 -3
  153. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/account_deletion.md +1 -0
  154. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/blocks.md +11 -2
  155. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/check_username_exists.md +1 -0
  156. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/follow-system-design.md +69 -61
  157. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/follow.md +8 -4
  158. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/user_removal.md +5 -5
  159. {core_framework-2.1.0 → core_framework-2.2.0}/docs/library/api.md +8 -0
  160. {core_framework-2.1.0 → core_framework-2.2.0}/docs/library/overview.md +5 -3
  161. {core_framework-2.1.0 → core_framework-2.2.0}/docs/library/package-api.md +15 -3
  162. {core_framework-2.1.0 → core_framework-2.2.0}/docs/platform/README.md +3 -1
  163. {core_framework-2.1.0 → core_framework-2.2.0}/docs/platform/architecture-decisions.md +75 -12
  164. {core_framework-2.1.0 → core_framework-2.2.0}/docs/platform/client-error-visibility.md +1 -1
  165. {core_framework-2.1.0 → core_framework-2.2.0}/docs/platform/conventions.md +6 -8
  166. core_framework-2.2.0/docs/platform/event-outbox-design.md +722 -0
  167. core_framework-2.2.0/docs/platform/events-ingest-design.md +109 -0
  168. core_framework-2.2.0/docs/platform/outbox-admin-ops-design.md +334 -0
  169. core_framework-2.2.0/docs/todo.md +11 -0
  170. {core_framework-2.1.0 → core_framework-2.2.0}/makefile +2 -2
  171. {core_framework-2.1.0 → core_framework-2.2.0}/pyproject.toml +1 -1
  172. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/_auth.py +8 -5
  173. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/conftest.py +1 -5
  174. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/smoke/tls_host_test.py +24 -6
  175. core_framework-2.2.0/tests/integration/api/_auth_helpers.py +6 -0
  176. core_framework-2.2.0/tests/integration/api/_outbox_helpers.py +138 -0
  177. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/_auth_cases.py +6 -0
  178. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/cache/router_test.py +5 -25
  179. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/moderation/router_test.py +96 -10
  180. core_framework-2.2.0/tests/integration/api/admin/outbox/router_test.py +333 -0
  181. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/users/router_test.py +5 -25
  182. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/attachments/_helpers.py +3 -17
  183. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/attachments/attachment_upload_test.py +1 -5
  184. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/comments/authenticated/comment_writes_integration_test.py +3 -16
  185. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/comments/public/router_test.py +4 -0
  186. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/create_idempotency_integration_test.py +1 -6
  187. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/events/router_test.py +4 -16
  188. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/notifications/router_test.py +5 -13
  189. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/posts/authenticated/post_writes_integration_test.py +1 -6
  190. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/posts/followers_visibility_test.py +34 -7
  191. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/posts/public/router_test.py +6 -16
  192. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/users/authenticated/router_test.py +19 -95
  193. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/users/public/router_test.py +6 -25
  194. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/account_deletion_test.py +3 -15
  195. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/aggregate_comment_stats_test.py +1 -4
  196. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/aggregate_post_stats_test.py +1 -4
  197. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/aggregate_user_stats_test.py +6 -29
  198. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/create_idempotency_retention_test.py +2 -12
  199. core_framework-2.2.0/tests/integration/worker/moderation_outbox_test.py +306 -0
  200. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/mute_lift_test.py +19 -17
  201. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/stale_staging_sweep_test.py +6 -6
  202. core_framework-2.2.0/tests/integration/worker/user_outbox_test.py +374 -0
  203. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/utils_test.py +1 -6
  204. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/application/events/event_service_test.py +4 -4
  205. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/core/pagination_test.py +7 -16
  206. core_framework-2.2.0/tests/unit/infrastructure/media/__init__.py +0 -0
  207. {core_framework-2.1.0 → core_framework-2.2.0}/uv.lock +1 -1
  208. core_framework-2.1.0/core_framework/application/events/README.md +0 -26
  209. core_framework-2.1.0/core_framework/application/posts/aggregation_service.py +0 -38
  210. core_framework-2.1.0/docs/domains/README.md +0 -17
  211. core_framework-2.1.0/docs/platform/event-outbox-design.md +0 -529
  212. core_framework-2.1.0/docs/todo.md +0 -10
  213. core_framework-2.1.0/tests/integration/api/_auth_helpers.py +0 -12
  214. {core_framework-2.1.0 → core_framework-2.2.0}/.agents/skills/fastapi +0 -0
  215. {core_framework-2.1.0 → core_framework-2.2.0}/.agents/skills/library-skills/.library-skills.json +0 -0
  216. {core_framework-2.1.0 → core_framework-2.2.0}/.agents/skills/library-skills/SKILL.md +0 -0
  217. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/alembic-revision-ids.mdc +0 -0
  218. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/api-reference-docs.mdc +0 -0
  219. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/api-validation.mdc +0 -0
  220. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/constants-final.mdc +0 -0
  221. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/database-triggers.mdc +0 -0
  222. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/docstrings.mdc +0 -0
  223. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/domain-input-guards.mdc +0 -0
  224. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/domain-services-and-adapters.mdc +0 -0
  225. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/flow-documentation.mdc +0 -0
  226. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/inline-raise-messages.mdc +0 -0
  227. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/integration-test-strategy.mdc +0 -0
  228. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/no-code-in-docs.mdc +0 -0
  229. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/postgres-config-conventions.mdc +0 -0
  230. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/repository-schema-isolation.mdc +0 -0
  231. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/rules/structured-logging.mdc +0 -0
  232. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/skills/add-config/SKILL.md +0 -0
  233. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/skills/add-domain/SKILL.md +0 -0
  234. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/skills/fastapi +0 -0
  235. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/skills/recommend-features/SKILL.md +0 -0
  236. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/skills/sync-host-rules/SKILL.md +0 -0
  237. {core_framework-2.1.0 → core_framework-2.2.0}/.cursor/skills/write-flow-doc/SKILL.md +0 -0
  238. {core_framework-2.1.0 → core_framework-2.2.0}/.dockerignore +0 -0
  239. {core_framework-2.1.0 → core_framework-2.2.0}/.github/workflows/dev-ci-cd.yaml +0 -0
  240. {core_framework-2.1.0 → core_framework-2.2.0}/.github/workflows/manual-deployment.yaml +0 -0
  241. {core_framework-2.1.0 → core_framework-2.2.0}/.github/workflows/publish-pypi.yml +0 -0
  242. {core_framework-2.1.0 → core_framework-2.2.0}/.gitignore +0 -0
  243. {core_framework-2.1.0 → core_framework-2.2.0}/.pre-commit-config.yaml +0 -0
  244. {core_framework-2.1.0 → core_framework-2.2.0}/.python-version +0 -0
  245. {core_framework-2.1.0 → core_framework-2.2.0}/LICENSE +0 -0
  246. {core_framework-2.1.0 → core_framework-2.2.0}/README.md +0 -0
  247. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/comment/alembic/README +0 -0
  248. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/comment/alembic/env.py +0 -0
  249. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/comment/alembic/script.py.mako +0 -0
  250. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/comment/alembic/versions/comment_add_comment_attachments.py +0 -0
  251. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/comment/alembic/versions/comment_add_comment_create_idempotency.py +0 -0
  252. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/comment/alembic/versions/comment_add_comment_create_idempotency_created_at_index.py +0 -0
  253. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/comment/alembic/versions/comment_add_comment_mentions.py +0 -0
  254. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/comment/alembic/versions/comment_tombstone_status_model.py +0 -0
  255. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/comment/alembic/versions/v1_comment_init_baseline.py +0 -0
  256. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/comment/alembic.ini +0 -0
  257. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/extension/alembic/README +0 -0
  258. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/extension/alembic/env.py +0 -0
  259. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/extension/alembic/script.py.mako +0 -0
  260. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/extension/alembic/versions/v1_ext_init_baseline.py +0 -0
  261. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/extension/alembic.ini +0 -0
  262. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/media/alembic/README +0 -0
  263. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/media/alembic/env.py +0 -0
  264. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/media/alembic/script.py.mako +0 -0
  265. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/media/alembic/versions/media_add_attachment_staging_registry.py +0 -0
  266. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/media/alembic/versions/media_add_banner_staging_and_lease.py +0 -0
  267. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/media/alembic/versions/media_attachment_staging_registry_published_at.py +0 -0
  268. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/media/alembic/versions/v1_media_init_baseline.py +0 -0
  269. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/media/alembic.ini +0 -0
  270. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/moderation/alembic/README +0 -0
  271. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/moderation/alembic/env.py +0 -0
  272. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/moderation/alembic/script.py.mako +0 -0
  273. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/moderation/alembic/versions/v1_mod_init_baseline.py +0 -0
  274. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/moderation/alembic.ini +0 -0
  275. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/notification/alembic/README +0 -0
  276. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/notification/alembic/env.py +0 -0
  277. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/notification/alembic/script.py.mako +0 -0
  278. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/notification/alembic/versions/v1_notif_init_baseline.py +0 -0
  279. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/notification/alembic.ini +0 -0
  280. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/post/alembic/README +0 -0
  281. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/post/alembic/env.py +0 -0
  282. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/post/alembic/script.py.mako +0 -0
  283. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/post/alembic/versions/post_add_post_attachments.py +0 -0
  284. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/post/alembic/versions/post_add_post_create_idempotency.py +0 -0
  285. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/post/alembic/versions/post_add_post_create_idempotency_created_at_index.py +0 -0
  286. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/post/alembic/versions/post_add_post_mentions.py +0 -0
  287. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/post/alembic/versions/post_tombstone_status_model.py +0 -0
  288. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/post/alembic/versions/v1_post_init_baseline.py +0 -0
  289. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/post/alembic.ini +0 -0
  290. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/user/alembic/README +0 -0
  291. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/user/alembic/env.py +0 -0
  292. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/user/alembic/script.py.mako +0 -0
  293. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/user/alembic/versions/user_add_avatar_ingest_sequences.py +0 -0
  294. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/user/alembic/versions/user_add_banner_ingest_sequences.py +0 -0
  295. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/user/alembic/versions/user_add_date_of_birth_to_profiles.py +0 -0
  296. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/user/alembic/versions/user_reserve_sentinel_user_ids.py +0 -0
  297. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/user/alembic/versions/v1_user_init_baseline.py +0 -0
  298. {core_framework-2.1.0 → core_framework-2.2.0}/alembic/user/alembic.ini +0 -0
  299. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/__init__.py +0 -0
  300. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/__init__.py +0 -0
  301. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/__init__.py +0 -0
  302. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/cache/schemas.py +0 -0
  303. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/comments/schemas.py +0 -0
  304. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/moderation/__init__.py +0 -0
  305. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/moderation/schemas.py +0 -0
  306. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/posts/schemas.py +0 -0
  307. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/admin/users/__init__.py +0 -0
  308. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/attachments/router.py +0 -0
  309. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/attachments/schemas.py +0 -0
  310. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/auth/__init__.py +0 -0
  311. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/auth/router.py +0 -0
  312. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/auth/schemas.py +0 -0
  313. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/comments/authenticated/mappers.py +0 -0
  314. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/comments/public/router.py +0 -0
  315. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/comments/public/schemas.py +0 -0
  316. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/comments/router.py +0 -0
  317. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/comments/schemas.py +0 -0
  318. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/constants.py +0 -0
  319. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/dependencies.py +0 -0
  320. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/idempotency/__init__.py +0 -0
  321. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/idempotency/dependencies.py +0 -0
  322. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/notifications/authenticated/schemas.py +0 -0
  323. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/notifications/router.py +0 -0
  324. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/posts/authenticated/mappers.py +0 -0
  325. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/posts/public/router.py +0 -0
  326. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/posts/public/schemas.py +0 -0
  327. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/posts/router.py +0 -0
  328. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/posts/schemas.py +0 -0
  329. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/router.py +0 -0
  330. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/schemas.py +0 -0
  331. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/system/__init__.py +0 -0
  332. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/system/router.py +0 -0
  333. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/__init__.py +0 -0
  334. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/authenticated/__init__.py +0 -0
  335. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/authenticated/mappers.py +0 -0
  336. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/authenticated/schemas.py +0 -0
  337. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/mappers.py +0 -0
  338. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/public/__init__.py +0 -0
  339. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/public/router.py +0 -0
  340. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/public/schemas.py +0 -0
  341. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/router.py +0 -0
  342. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/api/users/shared/schemas.py +0 -0
  343. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/__init__.py +0 -0
  344. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/auth/__init__.py +0 -0
  345. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/auth/access_service.py +0 -0
  346. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/auth/auth_service.py +0 -0
  347. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/auth/models.py +0 -0
  348. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/cache/invalidate_service.py +0 -0
  349. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/cache/models.py +0 -0
  350. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/comments/aggregation_service.py +0 -0
  351. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/comments/cleanup_service.py +0 -0
  352. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/media/attachment_read.py +0 -0
  353. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/media/read_url_config.py +0 -0
  354. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/moderation/__init__.py +0 -0
  355. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/moderation/report_service.py +0 -0
  356. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/moderation/scheduled_service.py +0 -0
  357. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/notifications/README.md +0 -0
  358. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/notifications/enums.py +0 -0
  359. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/notifications/notification_service.py +0 -0
  360. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/posts/admin_service.py +0 -0
  361. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/posts/cleanup_service.py +0 -0
  362. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/shared/__init__.py +0 -0
  363. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/shared/user_agent.py +0 -0
  364. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/shared/worker_jobs.py +0 -0
  365. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/users/__init__.py +0 -0
  366. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/users/aggregation_service.py +0 -0
  367. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/users/deletion_audit.py +0 -0
  368. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/users/enums.py +0 -0
  369. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/application/users/scheduled_service.py +0 -0
  370. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/asgi.py +0 -0
  371. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/bundled_alembic.py +0 -0
  372. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/constants.py +0 -0
  373. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/__init__.py +0 -0
  374. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/cache.py +0 -0
  375. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/context.py +0 -0
  376. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/exception_handlers/__init__.py +0 -0
  377. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/firebase.py +0 -0
  378. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/http_client.py +0 -0
  379. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/observability.py +0 -0
  380. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/core/redis.py +0 -0
  381. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/__init__.py +0 -0
  382. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/auth/__init__.py +0 -0
  383. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/auth/dependencies.py +0 -0
  384. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/auth/exceptions.py +0 -0
  385. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/auth/models.py +0 -0
  386. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/auth/ports/__init__.py +0 -0
  387. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/auth/ports/auth.py +0 -0
  388. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/auth/service.py +0 -0
  389. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/comment/__init__.py +0 -0
  390. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/comment/constants.py +0 -0
  391. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/comment/dependencies.py +0 -0
  392. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/comment/enums.py +0 -0
  393. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/comment/exceptions.py +0 -0
  394. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/comment/models.py +0 -0
  395. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/comment/outcomes.py +0 -0
  396. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/exceptions.py +0 -0
  397. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/README.md +0 -0
  398. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/__init__.py +0 -0
  399. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/attachment/components/staging.py +0 -0
  400. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/attachment/components/variant_encoder.py +0 -0
  401. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/attachment/constants.py +0 -0
  402. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/attachment/exceptions.py +0 -0
  403. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/attachment/models.py +0 -0
  404. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/attachment/ports/staging.py +0 -0
  405. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/attachment/ports/variant_encoder.py +0 -0
  406. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/__init__.py +0 -0
  407. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/components/__init__.py +0 -0
  408. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/components/finals_publisher.py +0 -0
  409. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/components/staging.py +0 -0
  410. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/components/variant_encoder.py +0 -0
  411. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/constants.py +0 -0
  412. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/exceptions.py +0 -0
  413. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/models.py +0 -0
  414. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/ports/__init__.py +0 -0
  415. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/ports/finals_publisher.py +0 -0
  416. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/ports/staging.py +0 -0
  417. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/avatar/ports/variant_encoder.py +0 -0
  418. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/banner/components/finals_publisher.py +0 -0
  419. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/banner/components/staging.py +0 -0
  420. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/banner/components/variant_encoder.py +0 -0
  421. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/banner/constants.py +0 -0
  422. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/banner/exceptions.py +0 -0
  423. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/banner/models.py +0 -0
  424. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/banner/ports/finals_publisher.py +0 -0
  425. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/banner/ports/staging.py +0 -0
  426. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/banner/ports/variant_encoder.py +0 -0
  427. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/dependencies.py +0 -0
  428. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/shared/__init__.py +0 -0
  429. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/shared/constants.py +0 -0
  430. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/shared/exceptions.py +0 -0
  431. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/shared/outcomes.py +0 -0
  432. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/shared/service.py +0 -0
  433. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/media/shared/utils.py +0 -0
  434. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/moderation/README.md +0 -0
  435. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/moderation/__init__.py +0 -0
  436. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/moderation/enums.py +0 -0
  437. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/moderation/exceptions.py +0 -0
  438. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/moderation/models.py +0 -0
  439. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/moderation/outcomes.py +0 -0
  440. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/notification/README.md +0 -0
  441. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/notification/__init__.py +0 -0
  442. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/notification/dependencies.py +0 -0
  443. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/notification/enums.py +0 -0
  444. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/notification/exceptions.py +0 -0
  445. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/notification/models.py +0 -0
  446. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/notification/repository.py +0 -0
  447. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/notification/service.py +0 -0
  448. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/post/__init__.py +0 -0
  449. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/post/constants.py +0 -0
  450. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/post/dependencies.py +0 -0
  451. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/post/enums.py +0 -0
  452. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/post/exceptions.py +0 -0
  453. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/post/outcomes.py +0 -0
  454. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/README.md +0 -0
  455. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/__init__.py +0 -0
  456. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/constants.py +0 -0
  457. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/enums.py +0 -0
  458. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/exceptions.py +0 -0
  459. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/models.py +0 -0
  460. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/user/utils.py +0 -0
  461. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/domains/utils.py +0 -0
  462. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/__init__.py +0 -0
  463. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/firebase/__init__.py +0 -0
  464. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/firebase/firebase_auth_adapter.py +0 -0
  465. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/__init__.py +0 -0
  466. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/attachment_staging_display_geometry.py +0 -0
  467. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/local_attachment_staging_adapter.py +0 -0
  468. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/local_banner_staging_adapter.py +0 -0
  469. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/local_staging_adapter.py +0 -0
  470. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/pillow_attachment_variant_encoder_adapter.py +0 -0
  471. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/pillow_avatar_variant_encoder_adapter.py +0 -0
  472. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/pillow_banner_variant_encoder_adapter.py +0 -0
  473. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/infrastructure/media/pillow_staging_image.py +0 -0
  474. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/main.py +0 -0
  475. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/migrate_cli.py +0 -0
  476. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/__init__.py +0 -0
  477. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/config.py +0 -0
  478. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/firebase.py +0 -0
  479. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/hookspecs.py +0 -0
  480. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/httpx_test_client.py +0 -0
  481. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/migrations.py +0 -0
  482. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/testing/plugin.py +0 -0
  483. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/__init__.py +0 -0
  484. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/schedules/schedule_aggregate_comment_stats.py +0 -0
  485. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/schedules/schedule_aggregate_post_stats.py +0 -0
  486. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/schedules/schedule_aggregate_user_stats.py +0 -0
  487. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/schedules/schedule_expired_account_deletions.py +0 -0
  488. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/schedules/schedule_expired_mute_lifts.py +0 -0
  489. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/schedules/schedule_purge_expired_create_idempotency_keys.py +0 -0
  490. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/schedules/schedule_sweep_stale_attachment_staging.py +0 -0
  491. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/delete_attachment_finals.py +0 -0
  492. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/delete_superseded_avatar_finals.py +0 -0
  493. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/delete_superseded_banner_finals.py +0 -0
  494. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_account_deletion.py +0 -0
  495. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_admin_user_deletion.py +0 -0
  496. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_aggregate_comment_stats.py +0 -0
  497. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_aggregate_post_stats.py +0 -0
  498. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_aggregate_user_stats.py +0 -0
  499. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_banner_asset_variants.py +0 -0
  500. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_cache_pattern_invalidation.py +0 -0
  501. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_destructive_comment_delete.py +0 -0
  502. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_destructive_post_delete.py +0 -0
  503. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_media_asset_variants.py +0 -0
  504. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_mute_lift.py +0 -0
  505. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/tasks/process_user_content_deletion.py +0 -0
  506. {core_framework-2.1.0 → core_framework-2.2.0}/core_framework/worker/worker_context.py +0 -0
  507. {core_framework-2.1.0 → core_framework-2.2.0}/docker-compose.dev.yaml +0 -0
  508. {core_framework-2.1.0 → core_framework-2.2.0}/docker-compose.yml +0 -0
  509. {core_framework-2.1.0 → core_framework-2.2.0}/dockerfile +0 -0
  510. {core_framework-2.1.0 → core_framework-2.2.0}/docs/README.md +0 -0
  511. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/README.md +0 -0
  512. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/edge-upload-limits.md +0 -0
  513. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/examples/Caddyfile.example +0 -0
  514. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/examples/image-server-known-hosts.example +0 -0
  515. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/guides/app-server-deploy-ssh.md +0 -0
  516. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/guides/image-server-ssh.md +0 -0
  517. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/guides/postgres-setup.md +0 -0
  518. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/guides/redis-setup.md +0 -0
  519. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/guides/ubuntu-server-setup.md +0 -0
  520. {core_framework-2.1.0 → core_framework-2.2.0}/docs/deployments/release-playbook.md +0 -0
  521. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/auth/registration.md +0 -0
  522. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/comments/admin_comments.md +0 -0
  523. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/comments/comment_report.md +0 -0
  524. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/comments/comment_stats_aggregation.md +0 -0
  525. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/comments/create_comment.md +0 -0
  526. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/comments/delete_comment.md +0 -0
  527. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/comments/edit_comment.md +0 -0
  528. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/comments/retrieve_comments.md +0 -0
  529. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/deletion/comments.md +0 -0
  530. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/deletion/overview.md +0 -0
  531. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/deletion/posts.md +0 -0
  532. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/deletion/users.md +0 -0
  533. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/media/upload_pipeline.md +0 -0
  534. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/mentions/mentions_in_content.md +0 -0
  535. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/moderation/internal_notes.md +0 -0
  536. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/moderation/moderator_actions.md +0 -0
  537. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/moderation/reports.md +0 -0
  538. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/posts/admin_posts.md +0 -0
  539. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/posts/author_context.md +0 -0
  540. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/posts/hashtag_discovery.md +0 -0
  541. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/posts/post_like.md +0 -0
  542. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/posts/post_visibility.md +0 -0
  543. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/account.md +0 -0
  544. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/avatar.md +0 -0
  545. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/banner.md +0 -0
  546. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/change_history.md +0 -0
  547. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/my_posts_and_comments.md +0 -0
  548. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/preferences.md +0 -0
  549. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/profile.md +0 -0
  550. {core_framework-2.1.0 → core_framework-2.2.0}/docs/domains/users/public_profile.md +0 -0
  551. {core_framework-2.1.0 → core_framework-2.2.0}/docs/library/README.md +0 -0
  552. {core_framework-2.1.0 → core_framework-2.2.0}/docs/library/core-framework-migration.md +0 -0
  553. {core_framework-2.1.0 → core_framework-2.2.0}/docs/library/testing-plugin-design.md +0 -0
  554. {core_framework-2.1.0 → core_framework-2.2.0}/docs/platform/create-idempotency-design.md +0 -0
  555. {core_framework-2.1.0 → core_framework-2.2.0}/docs/platform/database-triggers.md +0 -0
  556. {core_framework-2.1.0 → core_framework-2.2.0}/docs/platform/domain-services-and-adapters.md +0 -0
  557. {core_framework-2.1.0 → core_framework-2.2.0}/docs/platform/layers-and-boundaries.md +0 -0
  558. {core_framework-2.1.0 → core_framework-2.2.0}/docs/platform/media-storage-topology.md +0 -0
  559. {core_framework-2.1.0 → core_framework-2.2.0}/docs/platform/patch-update-typed-payload.md +0 -0
  560. {core_framework-2.1.0 → core_framework-2.2.0}/firebase_config.example.json +0 -0
  561. {core_framework-2.1.0 → core_framework-2.2.0}/tests/__init__.py +0 -0
  562. {core_framework-2.1.0 → core_framework-2.2.0}/tests/conftest.py +0 -0
  563. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/_canaries.py +0 -0
  564. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/_media.py +0 -0
  565. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/_settings.py +0 -0
  566. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/_upload_payloads.py +0 -0
  567. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/media/pipeline_test.py +0 -0
  568. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/smoke/canary_test.py +0 -0
  569. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/smoke/media_test.py +0 -0
  570. {core_framework-2.1.0 → core_framework-2.2.0}/tests/e2e/smoke/system_test.py +0 -0
  571. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/__init__.py +0 -0
  572. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/_http_error_details.py +0 -0
  573. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/__init__.py +0 -0
  574. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/_destructive_delete_helpers.py +0 -0
  575. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/_http_helpers.py +0 -0
  576. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/_user_deletion_helpers.py +0 -0
  577. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/_user_helpers.py +0 -0
  578. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/__init__.py +0 -0
  579. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/cache/__init__.py +0 -0
  580. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/comments/__init__.py +0 -0
  581. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/comments/router_test.py +0 -0
  582. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/moderation/__init__.py +0 -0
  583. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/moderation/_auth_cases.py +0 -0
  584. {core_framework-2.1.0/tests/integration/api/admin/posts → core_framework-2.2.0/tests/integration/api/admin/outbox}/__init__.py +0 -0
  585. {core_framework-2.1.0/tests/integration/api/admin/users → core_framework-2.2.0/tests/integration/api/admin/posts}/__init__.py +0 -0
  586. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/admin/posts/router_test.py +0 -0
  587. {core_framework-2.1.0/tests/integration/api/auth → core_framework-2.2.0/tests/integration/api/admin/users}/__init__.py +0 -0
  588. {core_framework-2.1.0/tests/integration/api/comments → core_framework-2.2.0/tests/integration/api/auth}/__init__.py +0 -0
  589. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/auth/router_test.py +0 -0
  590. {core_framework-2.1.0/tests/integration/api/comments/authenticated → core_framework-2.2.0/tests/integration/api/comments}/__init__.py +0 -0
  591. {core_framework-2.1.0/tests/integration/api/comments/public → core_framework-2.2.0/tests/integration/api/comments/authenticated}/__init__.py +0 -0
  592. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/comments/comment_attachments_integration_test.py +0 -0
  593. {core_framework-2.1.0/tests/integration/api/notifications → core_framework-2.2.0/tests/integration/api/comments/public}/__init__.py +0 -0
  594. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/media/ingest_contract_test.py +0 -0
  595. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/mentions/mentions_integration_test.py +0 -0
  596. {core_framework-2.1.0/tests/integration/api/posts → core_framework-2.2.0/tests/integration/api/notifications}/__init__.py +0 -0
  597. {core_framework-2.1.0/tests/integration/api/posts/public → core_framework-2.2.0/tests/integration/api/posts}/__init__.py +0 -0
  598. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/posts/comment_count_aggregation_test.py +0 -0
  599. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/posts/post_attachments_integration_test.py +0 -0
  600. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/posts/post_deletion_integration_test.py +0 -0
  601. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/posts/post_stats_dirty_marking_test.py +0 -0
  602. {core_framework-2.1.0/tests/integration/api/system → core_framework-2.2.0/tests/integration/api/posts/public}/__init__.py +0 -0
  603. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/public_read_by_id_unavailable_detail_test.py +0 -0
  604. {core_framework-2.1.0/tests/integration/api/users → core_framework-2.2.0/tests/integration/api/system}/__init__.py +0 -0
  605. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/system/router_test.py +0 -0
  606. {core_framework-2.1.0/tests/integration/api/users/authenticated → core_framework-2.2.0/tests/integration/api/users}/__init__.py +0 -0
  607. {core_framework-2.1.0/tests/integration/api/users/public → core_framework-2.2.0/tests/integration/api/users/authenticated}/__init__.py +0 -0
  608. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/users/authenticated/avatar_upload_test.py +0 -0
  609. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/users/authenticated/banner_upload_test.py +0 -0
  610. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/users/deletion_audit_integration_test.py +0 -0
  611. {core_framework-2.1.0/tests/integration/worker → core_framework-2.2.0/tests/integration/api/users/public}/__init__.py +0 -0
  612. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/api/users/user_deletion_integration_test.py +0 -0
  613. {core_framework-2.1.0/tests/unit → core_framework-2.2.0/tests/integration/worker}/__init__.py +0 -0
  614. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/_media_upload_helpers.py +0 -0
  615. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/attachment_upload_test.py +0 -0
  616. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/avatar_upload_test.py +0 -0
  617. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/banner_upload_test.py +0 -0
  618. {core_framework-2.1.0 → core_framework-2.2.0}/tests/integration/worker/conftest.py +0 -0
  619. {core_framework-2.1.0/tests/unit/application/comments → core_framework-2.2.0/tests/unit}/__init__.py +0 -0
  620. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/api/comments/authenticated/comment_request_schemas_test.py +0 -0
  621. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/api/dedupe_preserving_order_test.py +0 -0
  622. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/api/posts/authenticated/post_update_mapper_test.py +0 -0
  623. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/api/users/profile_update_mapper_test.py +0 -0
  624. {core_framework-2.1.0/tests/unit/domains → core_framework-2.2.0/tests/unit/application/comments}/__init__.py +0 -0
  625. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/application/notifications/inbox_service_test.py +0 -0
  626. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/application/users/deletion_audit_test.py +0 -0
  627. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/core/bundled_alembic_test.py +0 -0
  628. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/core/migrate_cli_test.py +0 -0
  629. {core_framework-2.1.0/tests/unit/domains/comment → core_framework-2.2.0/tests/unit/domains}/__init__.py +0 -0
  630. {core_framework-2.1.0/tests/unit/infrastructure → core_framework-2.2.0/tests/unit/domains/comment}/__init__.py +0 -0
  631. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/domains/post/models_test.py +0 -0
  632. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/domains/user/service_test.py +0 -0
  633. {core_framework-2.1.0/tests/unit/infrastructure/media → core_framework-2.2.0/tests/unit/infrastructure}/__init__.py +0 -0
  634. {core_framework-2.1.0 → core_framework-2.2.0}/tests/unit/infrastructure/media/ssh_finals_publisher_adapter_test.py +0 -0
@@ -6,7 +6,7 @@ globs:
6
6
 
7
7
  # API layer (core-framework)
8
8
 
9
- **Framework patterns:** use the **fastapi** skill (`.cursor/skills/fastapi/`) — `Annotated`, dependencies, routers, Pydantic v2, CLI.
9
+ **Framework patterns:** use the **fastapi** skill (`.agents/skills/fastapi/`) — `Annotated`, dependencies, routers, Pydantic v2, CLI.
10
10
 
11
11
  **Validation:** **`api-validation.mdc`**. **Errors:** **`error-boundary.mdc`**. **Domain imports:** **`domain-imports.mdc`**.
12
12
 
@@ -18,7 +18,7 @@ Application services orchestrate use cases shared by API and workers. They stay
18
18
 
19
19
  - Return plain Python/domain values: `dict`, `list[dict]`, dataclasses, primitives, `None`, or empty collections.
20
20
  - Do not return API/Pydantic `BaseModel` instances.
21
- - Signal HTTP-meaningful failures with **`application.shared.exceptions`** or plain outcomes (`None`, empty), never typed domain exceptions. See **`error-boundary.mdc`**.
21
+ - Signal HTTP-meaningful failures with **`application.shared.exceptions`** or plain outcomes (`None`, empty), never typed domain exceptions. Full boundary contract: **`error-boundary.mdc`**.
22
22
 
23
23
  Use a domain dataclass when one domain row matches the response shape; use a `dict` when the payload is composed from several sources.
24
24
 
@@ -10,6 +10,7 @@ alwaysApply: true
10
10
  - State assumptions; ask when unclear. Prefer the simplest correct solution.
11
11
  - Touch only what the task requires. Match existing style. Remove orphans your edits create.
12
12
  - Define verifiable success criteria for non-trivial work.
13
+ - **Inline small single-use helpers** — do not extract a private function used once and only a few lines (identifier quoting, a short SQL fragment, pass-through wrappers). Extract when the logic is **reused**, **~15+ lines / non-obvious branching**, or a scoped rule requires sharing (e.g. normal + `*_strong` repository reads in **`strong-reads.mdc`**). Do not repo-wide refactor unrelated existing helpers.
13
14
 
14
15
  ## Tech stack
15
16
 
@@ -25,7 +26,12 @@ Dependencies point inward: API/worker → application → domain. Never reverse.
25
26
  - **Application** — orchestration shared by API + worker; no FastAPI types.
26
27
  - **Domain** — models, repositories (Postgres only), services. No API/worker/application imports except wiring in `dependencies.py`.
27
28
 
28
- Path-scoped rules under `.cursor/rules/` add detail (API, domains, docs, etc.). For FastAPI/Pydantic work in `core_framework/api/`, use the **fastapi** skill (`.cursor/skills/fastapi/`).
29
+ Path-scoped rules under `.cursor/rules/` add detail (API, domains, docs, etc.). For FastAPI/Pydantic work in `core_framework/api/`, use the **fastapi** skill (`.agents/skills/fastapi/`).
30
+
31
+ ## Agent skills
32
+
33
+ - Package skills (for example **fastapi**) are Library Skills-managed symlinks under **`.agents/skills/<name>/`**. Rules and hand-authored skills reference that path, not a copied tree under **`.cursor/skills/`**.
34
+ - **`.cursor/skills/<name>`** may symlink to **`.agents/skills/<name>`** for Cursor; Library Skills repairs **`.agents/skills`** links when packages move. After **`uv sync`** or a dependency upgrade, run **`uvx library-skills --yes`** if symlinks are stale.
29
35
 
30
36
  ## Host applications
31
37
 
@@ -34,7 +34,7 @@ Domain layer names must describe domain concepts and data semantics, not who cal
34
34
  - `tombstone_post` ✅
35
35
  - `detach_post_authors_by_author_id` ✅
36
36
  - Prefer naming by data shape or business rule, not persona:
37
- - `select_post_with_metadata_by_id` ✅
37
+ - `select_post_with_metadata_by_id_if_exists` ✅
38
38
  - `retrieve_user_for_detail` ✅
39
39
  - Keep caller-specific naming in API/application layers only.
40
40
 
@@ -16,7 +16,7 @@ When importing from **`core_framework/domains/*`** in API or application code:
16
16
 
17
17
  ## Prohibited
18
18
 
19
- - Typed or base **domain exceptions** in API/application — use **`application.shared.exceptions`**.
19
+ - Typed or base **domain exceptions** in API/application — use **`application.shared.exceptions`**. Full policy: **`error-boundary.mdc`**.
20
20
  - Direct imports from internal modules (`models`, `enums`, `repository`, `service`, `exceptions`).
21
21
 
22
22
  ```python
@@ -41,4 +41,4 @@ To see what a domain exports, check its **`__init__.py`** **`__all__`**.
41
41
  2. Raise an **application** exception when HTTP must signal failure.
42
42
  3. Extend the domain service API to absorb typed exceptions internally.
43
43
 
44
- Application code never imports repositories. Exception boundary details: **`error-boundary.mdc`**.
44
+ Application code never imports repositories. Exception boundary: **`error-boundary.mdc`**.
@@ -6,15 +6,18 @@ globs:
6
6
 
7
7
  # Domain: repository exceptions vs service
8
8
 
9
+ Canonical HTTP/application boundary: **`error-boundary.mdc`**. Application and API must not import or handle typed domain exceptions.
10
+
9
11
  ## Thin service + single persistence step
10
12
 
11
- When a **`Service`** method in **`core_framework/domains/*/service.py`** only performs **shared input guards** (e.g. **`require_*`**, **`validate_pagination_limit`**) **and** delegates to **one** repository call with **no branching** afterward, **prefer raising domain exceptions inside the repository** when the persistence outcome is an error condition (empty `RETURNING`, unexpected row absence on insert).
13
+ When a **`Service`** method in **`core_framework/domains/*/service.py`** only performs **shared input guards** (e.g. **`require_*`**, **`validate_pagination_limit`**) **and** delegates to **one** repository call with **no branching** afterward, the repository may raise typed domain exceptions for persistence error outcomes (empty `RETURNING`, unexpected row absence on insert).
12
14
 
13
- The service stays a façade: validate arguments, then **`await`** the repository method and let **domain exceptions** propagate.
15
+ That propagation is **intra-domain only**. Methods that **application** or **workers** call must **not** leak typed exceptions outward — absorb them inside the service (return **`None`**, outcomes, or **`bool`**) or branch before re-raising. See **`error-boundary.mdc`**.
14
16
 
15
17
  ## Prefer service-side translation when
16
18
 
17
19
  - The service **composes multiple** repository calls, **branches** on outcomes, or maps the same SQL outcome to **different domain errors**.
20
+ - The method is an **application-callable** entrypoint (anything imported via **`dependencies.py`** and used from **`core_framework/application/`** or **`core_framework/api/`**).
18
21
  - Keeping the repository purely “data shaped” (**`Optional`** / **`bool`**) materially improves reuse or clarity for **multiple** service entrypoints calling the same repository method.
19
22
 
20
23
  Existing domains may mix both styles; use this guide for **new work** and when **refactoring** a call site for clarity.
@@ -2,8 +2,9 @@
2
2
  description: HTTP error boundaries — application vs domain exceptions, handlers, anti-enumeration
3
3
  globs:
4
4
  - core_framework/core/exception_handlers/**/*.py
5
- - core_framework/application/**/*_service.py
5
+ - core_framework/application/**/*.py
6
6
  - core_framework/api/**/router.py
7
+ - core_framework/api/**/schemas.py
7
8
  - core_framework/domains/**/exceptions.py
8
9
  ---
9
10
 
@@ -15,7 +16,7 @@ Platform contract: **`docs/platform/client-error-visibility.md`**. Domain import
15
16
 
16
17
  | Layer | Outward errors | HTTP |
17
18
  |-------|----------------|------|
18
- | **Application** | **`application.shared.exceptions`** | Handlers map type → status + `detail` |
19
+ | **Application** | **`application.shared.exceptions`**, **`InvalidPageTokenError`** | Handlers map type → status + `detail` |
19
20
  | **Domain typed** | Internal — not imported by API/application | No typed handlers |
20
21
  | **Domain `BaseXxxException`** | Handler catch-all only | **500** if leaked |
21
22
  | **API** | Pydantic | **422** |
@@ -30,7 +31,7 @@ Platform contract: **`docs/platform/client-error-visibility.md`**. Domain import
30
31
  ## Handler registration
31
32
 
32
33
  - Use **`register_exception_handler`** from **`core_framework.core.exception_handlers.common`** — not raw **`app.add_exception_handler`** elsewhere.
33
- - **`setup.py`**: application types (specific before any base), **`DomainValidationError`**, one **`BaseDomainException`** leak handler, then **`Exception`** unmapped.
34
+ - Register handlers in **`core_framework/core/exception_handlers/setup.py`** and **`application.py`**: application types (specific before any base), **`InvalidPageTokenError`**, **`DomainValidationError`**, one **`BaseDomainException`** leak handler, then **`Exception`** unmapped.
34
35
  - No per-domain handler modules for typed exceptions. Handlers translate only — no business logic or repository calls.
35
36
  - Do not log **error** for expected application 4xx; **`DomainValidationError`** at **warning**/**info**.
36
37
 
@@ -18,7 +18,7 @@ Dependencies point inward: **API/worker → application → domain**. Never reve
18
18
 
19
19
  ## Cross-layer rules
20
20
 
21
- - Worker code must not import `core_framework.domains` directly, except documented housekeeping cron handlers that call a configured domain facade.
21
+ - Worker code must not import `core_framework.domains` directly; call **application** services from worker tasks and schedules.
22
22
  - Domain code imports global infrastructure only in `dependencies.py`.
23
23
  - Repositories are Postgres-only and must not query other domains' schemas. See **`repository-schema-isolation`**.
24
24
  - Non-SQL I/O uses domain ports/components plus infrastructure adapters. See **`domain-services-and-adapters`**.
@@ -4,7 +4,7 @@ globs:
4
4
  - core_framework/domains/**/repository.py
5
5
  - core_framework/domains/**/service.py
6
6
  - core_framework/domains/**/dependencies.py
7
- - core_framework/application/**/*_service.py
7
+ - core_framework/application/**/*.py
8
8
  ---
9
9
 
10
10
  # Strong reads
@@ -13,6 +13,7 @@ globs:
13
13
 
14
14
  - **Read-after-write** in the same HTTP request or worker job → **strong** read (required). Refetch with `strong_read_database`, `*_strong` repository methods, or service accessors that call them.
15
15
  - **Decision-critical guards** where stale data can cause incorrect branching → **strong** read (required). These are reads performed to decide a branch (for example pre-write existence, role, or state checks that determine whether a write runs or which outcome is returned), even when there is no immediate prior write in the flow. See the "Read Consistency (Strong vs Normal Reads)" ADR.
16
+ - **Accepted exception:** **`check_not_banned`** / **`get_user_detail`** (`USER_DETAIL` cache + normal reads) — ban visibility is eventually consistent by design. See **`docs/platform/architecture-decisions.md`** → *Ban enforcement via cached `USER_DETAIL` is eventually consistent*. Do not flag as a strong-read defect unless that ADR is updated.
16
17
  - **All other strong-read usage** (e.g., list/browse freshness) → opt-in unless the user explicitly requested it in the task.
17
18
  - If a flow writes then reads and only a normal-read API exists, add or extend the `*_strong` path and call it from that flow.
18
19
  - Repositories accept `strong_read_database: Postgres` on `__init__` for wiring symmetry even when unused.
@@ -21,9 +22,8 @@ globs:
21
22
 
22
23
  - Normal reads: explicit methods (e.g. `select_appeal`) using `read_database`.
23
24
  - Strong reads: separate methods only where needed (e.g. `select_appeal_strong`) using `strong_read_database`.
24
- - Share one private helper that accepts a database handle — do not duplicate SQL or mapping.
25
- - If only strong-read behavior is needed today, use a single method with `_strong` in the name.
26
- - Service accessors that call strong repository methods should also include `_strong`.
25
+ - Share one private helper that accepts a database handle when **both** normal and strong public methods exist — do not duplicate SQL or mapping. If only a `*_strong` method exists today, keep SQL inline in that method (constitution → inline small single-use helpers).
26
+ - Service accessors that call strong repository methods should use **`retrieve_*_strong`** naming (repositories keep **`select_*_strong`**).
27
27
 
28
28
  ```python
29
29
  # Preferred
@@ -25,7 +25,7 @@ Do **not** flag documented accepted trade-offs in **`docs/platform/architecture-
25
25
  ## Quick checks
26
26
 
27
27
  - Application services: no HTTP types, no domain exceptions, no Pydantic return types, one-line docstrings.
28
- - API: thin routers, validation in schemas, orchestration in application — **fastapi** skill + **`api-layer`** / **`api-validation`** / **`error-boundary`** rules.
28
+ - API: thin routers, validation in schemas, orchestration in application — **fastapi** skill (`.agents/skills/fastapi/`) + **`api-layer`** / **`api-validation`** / **`error-boundary`** rules.
29
29
  - Domain: imports only via **`__init__.py`** / **`dependencies`** from outer layers; no caller-context names (**`domain-caller-context`**).
30
30
  - Read-after-write refetches use **`*_strong`** where applicable.
31
31
 
@@ -24,7 +24,7 @@ Implement **one step at a time**. Stop after each step and wait for user review.
24
24
  After the user accepts database changes (or if there were none):
25
25
 
26
26
  - **Only** implement the API layer: schemas and router.
27
- - Follow the **fastapi** skill and **`api-layer`** / **`api-validation`** / **`error-boundary`** rules.
27
+ - Follow the **fastapi** skill (`.agents/skills/fastapi/`) and **`api-layer`** / **`api-validation`** / **`error-boundary`** rules.
28
28
  - **No** changes in domain, service, or application layers.
29
29
  - Include request/response schemas, error handling, and HTTP-related logic.
30
30
  - If the feature is not yet implemented, return 501 Not Implemented from the route.
@@ -55,10 +55,12 @@ jobs:
55
55
  IMAGE_SERVER_PORT: ${{ vars.IMAGE_SERVER_PORT }}
56
56
  IMAGE_SERVER_USER: ${{ vars.IMAGE_SERVER_USER }}
57
57
  LOGFIRE_TOKEN: ${{ secrets.LOGFIRE_TOKEN }}
58
+ OBSERVABILITY_ENABLED: ${{ vars.OBSERVABILITY_ENABLED }}
58
59
  PROFILING_KEY: ${{ vars.PROFILING_KEY }}
59
60
  PROFILING_ENABLED: ${{ vars.PROFILING_ENABLED }}
60
61
  LOG_LEVEL: ${{ vars.LOG_LEVEL }}
61
62
  CORS_ALLOWED_ORIGINS: ${{ vars.CORS_ALLOWED_ORIGINS }}
63
+ RETENTION_POST_VIEWS_DAYS: ${{ vars.RETENTION_POST_VIEWS_DAYS }}
62
64
  run: |
63
65
  set -euo pipefail
64
66
 
@@ -32,19 +32,14 @@ jobs:
32
32
  run: uv run ruff check
33
33
 
34
34
  - name: Install Firebase CLI
35
- run: npm install -g firebase-tools
36
-
37
- - name: Start Firebase Emulator
38
- run: |
39
- firebase emulators:start --only auth --project=test &
40
- sleep 5
41
- env:
42
- FIREBASE_AUTH_EMULATOR_HOST: localhost:9099
35
+ run: npm install -g firebase-tools@15.20.0
43
36
 
44
37
  - name: pytest
45
- run: uv run pytest tests/unit tests/integration -n 2
38
+ run: |
39
+ firebase --version
40
+ uv run pytest tests/unit tests/integration -n 2
46
41
  env:
47
- FIREBASE_AUTH_EMULATOR_HOST: localhost:9099
42
+ FIREBASE_AUTH_EMULATOR_HOST: 127.0.0.1:9099
48
43
 
49
44
  package-smoke:
50
45
  runs-on: ubuntu-latest
@@ -4,6 +4,37 @@ Notable changes to **core-framework** (import **`core_framework`**). Format foll
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.2.0] - 2026-06-30
8
+
9
+ Transactional outbox (block, follow, restriction), post views retention, and incremental view-count aggregation. Hosts must update **`config.toml`**, run **`cf-alembic`**, and run the worker for mirror fanout and retention jobs.
10
+
11
+ ### Added
12
+
13
+ - **Post views retention:** Incremental **`view_count`** aggregation via **`post_stats.view_count_aggregated_up_to`** (high-water mark on **`post_views.created_at`**); daily worker **`schedule_prune_post_views`** (05:00 UTC) deletes aggregated rows older than **`retention.post_views_retention_days`** (default **90**). See **`docs/domains/posts/post_stats_aggregation.md`**.
14
+ - **Transactional outbox (block pilot):** `user.event_outbox`, worker poller/handler for **`user.block.relationship_changed`**, durable post/comment/notification block mirror fanout. See **`docs/platform/event-outbox-design.md`**.
15
+ - **Transactional outbox (follow, Phase 2):** **`user.follow.relationship_changed`** enqueued with truth changes; worker reconciles **`post.user_followers_lookup`** (outbox-only mirror path, matching block). Non-retryable handler errors dead-letter immediately (decision **#22**).
16
+ - **Transactional outbox (restriction, Phase 3):** **`moderation.restriction.relationship_changed`** enqueued on truth changes and no-op healing; worker reconciles post/comment/user/notification restriction lookup mirrors (outbox-only, matching block/follow). Poller E2E in **`tests/integration/worker/moderation_outbox_test.py`**. Run **`cf-alembic`** for **`moderation_add_event_outbox`**.
17
+
18
+ ### Fixed
19
+
20
+ - **Appeal approval retry:** Same-decision retries on already-approved appeals re-run `clear_user_restriction` instead of returning **400**, recovering when restriction removal failed after the appeal was persisted.
21
+ - **Worker staging sweeps:** Avatar and banner stale-staging cron schedules call **`sweep_*_staging_housekeeping`** application entrypoints instead of domain dependencies directly.
22
+
23
+ ### Changed
24
+
25
+ - **Post stats aggregation:** **`view_count`** is maintained incrementally from **`post_views`** since the last high-water mark instead of a full **`count(*)`** per run; tombstone resets clear **`view_count_aggregated_up_to`**.
26
+
27
+ ### Breaking
28
+
29
+ - **Breaking (hosts — config):** When upgrading to a release that includes the outbox block pilot, update **`config.toml`** (and deploy templates) before startup:
30
+ - Rename **`[http-client]`** → **`[http_client]`** (field name on **`Settings`** is now **`http_client`** with no hyphen alias).
31
+ - Add **`[outbox]`** with **`min_connections`** and **`max_connections`** (defaults in core **`config.toml.template`**: **2** / **12**). The outbox pool is opened only by the **worker** process (and test workers via **`create_worker_settings_for_shared_runtime`**), not the API lifespan.
32
+ - Run **`cf-alembic`** so the **`user`** migration stream applies **`user_add_event_outbox`** (`"user".event_outbox`).
33
+ - Hosts that only run the API (no worker) still need **`[outbox]`** in config because **`Settings`** requires it; the API does not connect that pool.
34
+ - **Breaking (hosts — migration):** When upgrading to a release that includes restriction outbox (Phase 3), run **`cf-alembic`** so the **`moderation`** migration stream applies **`moderation_add_event_outbox`** (`moderation.event_outbox`). The worker must run **`schedule_poll_moderation_outbox`** (registered in core worker schedules) for durable restriction mirror fanout.
35
+ - **Breaking (hosts — config):** Add **`[retention]`** with **`post_views_retention_days`** (default **90**). Deploy variable **`RETENTION_POST_VIEWS_DAYS`**. Hosts that subclass **`Settings`** may extend **`RetentionConfig`** with additional retention keys (for example calculator views on Henry).
36
+ - **Breaking (hosts — migration):** When upgrading to a release that includes post views retention, run **`cf-alembic`** so the **`post`** migration stream applies **`post_post_views_retention_high_water_mark`** (`post_stats.view_count_aggregated_up_to`, **`post_views`** retention indexes, backfill). The worker must run **`schedule_prune_post_views`** (registered in core worker schedules) for age-based **`post_views`** pruning.
37
+
7
38
  ## [2.1.0] - 2026-06-25
8
39
 
9
40
  Dependency and tooling refresh. No API, schema, or host config changes — bump the package and redeploy; no **`cf-alembic`** step.
@@ -349,4 +380,5 @@ First **SemVer-stable** release per **`docs/library/package-api.md`**.
349
380
  [1.8.1]: https://github.com/NepNepFFXIV/core-framework/compare/v1.8.0...v1.8.1
350
381
  [2.0.0]: https://github.com/NepNepFFXIV/core-framework/compare/v1.8.1...v2.0.0
351
382
  [2.1.0]: https://github.com/NepNepFFXIV/core-framework/compare/v2.0.0...v2.1.0
352
- [unreleased]: https://github.com/NepNepFFXIV/core-framework/compare/v2.1.0...HEAD
383
+ [2.2.0]: https://github.com/NepNepFFXIV/core-framework/compare/v2.1.0...v2.2.0
384
+ [unreleased]: https://github.com/NepNepFFXIV/core-framework/compare/v2.2.0...HEAD
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-framework
3
- Version: 2.1.0
3
+ Version: 2.2.0
4
4
  Summary: Core framework package (import as core_framework)
5
5
  Project-URL: Homepage, https://github.com/NepNepFFXIV/core-framework
6
6
  Project-URL: Repository, https://github.com/NepNepFFXIV/core-framework
@@ -0,0 +1,52 @@
1
+ """add event_outbox table for transactional outbox
2
+
3
+ Revision ID: 3a8e61ac8ae2
4
+ Revises: v1_mod_init
5
+ Create Date: 2026-06-27 12:00:00.000000
6
+
7
+ """
8
+
9
+ from collections.abc import Sequence
10
+
11
+ from alembic import op
12
+
13
+ revision: str = "3a8e61ac8ae2"
14
+ down_revision: str | Sequence[str] | None = "v1_mod_init"
15
+ branch_labels: str | Sequence[str] | None = None
16
+ depends_on: str | Sequence[str] | None = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.execute("""
21
+ create table event_outbox (
22
+ id bigint generated always as identity primary key,
23
+ created_at timestamptz not null default now(),
24
+ event_name text not null,
25
+ payload jsonb not null,
26
+ payload_version smallint not null default 1,
27
+ idempotency_key text not null,
28
+ aggregate_type text not null,
29
+ aggregate_id text not null,
30
+ status text not null default 'pending',
31
+ available_at timestamptz not null default now(),
32
+ attempt_count integer not null default 0,
33
+ failure_count integer not null default 0,
34
+ locked_at timestamptz,
35
+ locked_by text,
36
+ last_error text,
37
+ metadata jsonb,
38
+ constraint event_outbox_idempotency_key_unique unique (idempotency_key),
39
+ constraint event_outbox_status_valid
40
+ check (status in ('pending', 'processing', 'done', 'dead'))
41
+ );
42
+ """)
43
+
44
+ op.execute("""
45
+ create index idx_event_outbox_pending_available
46
+ on event_outbox (available_at, id)
47
+ where status = 'pending';
48
+ """)
49
+
50
+
51
+ def downgrade() -> None:
52
+ op.execute("drop table if exists event_outbox;")
@@ -0,0 +1,34 @@
1
+ """add dead-row partial indexes on event_outbox for admin ops
2
+
3
+ Revision ID: de7c41fba3e8
4
+ Revises: 3a8e61ac8ae2
5
+ Create Date: 2026-06-28 12:00:00.000000
6
+
7
+ """
8
+
9
+ from collections.abc import Sequence
10
+
11
+ from alembic import op
12
+
13
+ revision: str = "de7c41fba3e8"
14
+ down_revision: str | Sequence[str] | None = "3a8e61ac8ae2"
15
+ branch_labels: str | Sequence[str] | None = None
16
+ depends_on: str | Sequence[str] | None = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.execute("""
21
+ create index idx_event_outbox_dead_created_at
22
+ on event_outbox (created_at desc, id)
23
+ where status = 'dead';
24
+ """)
25
+ op.execute("""
26
+ create index idx_event_outbox_dead_event_created
27
+ on event_outbox (event_name, created_at)
28
+ where status = 'dead';
29
+ """)
30
+
31
+
32
+ def downgrade() -> None:
33
+ op.execute("drop index if exists idx_event_outbox_dead_event_created;")
34
+ op.execute("drop index if exists idx_event_outbox_dead_created_at;")
@@ -0,0 +1,28 @@
1
+ """add pending created_at partial index on event_outbox for admin oldest-pending
2
+
3
+ Revision ID: cf840f06eff3
4
+ Revises: de7c41fba3e8
5
+ Create Date: 2026-06-29 12:00:00.000000
6
+
7
+ """
8
+
9
+ from collections.abc import Sequence
10
+
11
+ from alembic import op
12
+
13
+ revision: str = "cf840f06eff3"
14
+ down_revision: str | Sequence[str] | None = "de7c41fba3e8"
15
+ branch_labels: str | Sequence[str] | None = None
16
+ depends_on: str | Sequence[str] | None = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.execute("""
21
+ create index idx_event_outbox_pending_created_at
22
+ on event_outbox (created_at, id)
23
+ where status = 'pending';
24
+ """)
25
+
26
+
27
+ def downgrade() -> None:
28
+ op.execute("drop index if exists idx_event_outbox_pending_created_at;")
@@ -0,0 +1,64 @@
1
+ """post_views retention: view_count_aggregated_up_to and created_at indexes
2
+
3
+ Revision ID: 1602f054c545
4
+ Revises: 10849f6f72ff
5
+ Create Date: 2026-06-30 12:00:00.000000
6
+
7
+ """
8
+
9
+ from collections.abc import Sequence
10
+
11
+ from alembic import op
12
+
13
+ revision: str = "1602f054c545"
14
+ down_revision: str | Sequence[str] | None = "10849f6f72ff"
15
+ branch_labels: str | Sequence[str] | None = None
16
+ depends_on: str | Sequence[str] | None = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.execute("""
21
+ alter table post_stats
22
+ add column view_count_aggregated_up_to timestamptz;
23
+ """)
24
+
25
+ op.execute("""
26
+ update post_stats ps
27
+ set view_count = sub.cnt
28
+ from (
29
+ select post_id, count(*)::bigint as cnt
30
+ from post_views
31
+ group by post_id
32
+ ) sub
33
+ where ps.post_id = sub.post_id;
34
+ """)
35
+
36
+ op.execute("""
37
+ update post_stats ps
38
+ set view_count_aggregated_up_to = sub.max_created_at
39
+ from (
40
+ select post_id, max(created_at) as max_created_at
41
+ from post_views
42
+ group by post_id
43
+ ) sub
44
+ where ps.post_id = sub.post_id;
45
+ """)
46
+
47
+ op.execute("""
48
+ create index idx_post_views_created_at
49
+ on post_views (created_at);
50
+ """)
51
+
52
+ op.execute("""
53
+ create index idx_post_views_post_created_at
54
+ on post_views (post_id, created_at desc);
55
+ """)
56
+
57
+
58
+ def downgrade() -> None:
59
+ op.execute("drop index if exists idx_post_views_post_created_at")
60
+ op.execute("drop index if exists idx_post_views_created_at")
61
+ op.execute("""
62
+ alter table post_stats
63
+ drop column if exists view_count_aggregated_up_to;
64
+ """)
@@ -0,0 +1,52 @@
1
+ """add event_outbox table for transactional outbox
2
+
3
+ Revision ID: 5f7110e39a55
4
+ Revises: 946c8f297876
5
+ Create Date: 2026-06-27 12:00:00.000000
6
+
7
+ """
8
+
9
+ from collections.abc import Sequence
10
+
11
+ from alembic import op
12
+
13
+ revision: str = "5f7110e39a55"
14
+ down_revision: str | Sequence[str] | None = "946c8f297876"
15
+ branch_labels: str | Sequence[str] | None = None
16
+ depends_on: str | Sequence[str] | None = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.execute("""
21
+ create table event_outbox (
22
+ id bigint generated always as identity primary key,
23
+ created_at timestamptz not null default now(),
24
+ event_name text not null,
25
+ payload jsonb not null,
26
+ payload_version smallint not null default 1,
27
+ idempotency_key text not null,
28
+ aggregate_type text not null,
29
+ aggregate_id text not null,
30
+ status text not null default 'pending',
31
+ available_at timestamptz not null default now(),
32
+ attempt_count integer not null default 0,
33
+ failure_count integer not null default 0,
34
+ locked_at timestamptz,
35
+ locked_by text,
36
+ last_error text,
37
+ metadata jsonb,
38
+ constraint event_outbox_idempotency_key_unique unique (idempotency_key),
39
+ constraint event_outbox_status_valid
40
+ check (status in ('pending', 'processing', 'done', 'dead'))
41
+ );
42
+ """)
43
+
44
+ op.execute("""
45
+ create index idx_event_outbox_pending_available
46
+ on event_outbox (available_at, id)
47
+ where status = 'pending';
48
+ """)
49
+
50
+
51
+ def downgrade() -> None:
52
+ op.execute("drop table if exists event_outbox;")
@@ -0,0 +1,34 @@
1
+ """add dead-row partial indexes on event_outbox for admin ops
2
+
3
+ Revision ID: d528956664b9
4
+ Revises: 5f7110e39a55
5
+ Create Date: 2026-06-28 12:00:00.000000
6
+
7
+ """
8
+
9
+ from collections.abc import Sequence
10
+
11
+ from alembic import op
12
+
13
+ revision: str = "d528956664b9"
14
+ down_revision: str | Sequence[str] | None = "5f7110e39a55"
15
+ branch_labels: str | Sequence[str] | None = None
16
+ depends_on: str | Sequence[str] | None = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.execute("""
21
+ create index idx_event_outbox_dead_created_at
22
+ on event_outbox (created_at desc, id)
23
+ where status = 'dead';
24
+ """)
25
+ op.execute("""
26
+ create index idx_event_outbox_dead_event_created
27
+ on event_outbox (event_name, created_at)
28
+ where status = 'dead';
29
+ """)
30
+
31
+
32
+ def downgrade() -> None:
33
+ op.execute("drop index if exists idx_event_outbox_dead_event_created;")
34
+ op.execute("drop index if exists idx_event_outbox_dead_created_at;")
@@ -0,0 +1,28 @@
1
+ """add pending created_at partial index on event_outbox for admin oldest-pending
2
+
3
+ Revision ID: 9d9611e47ce2
4
+ Revises: d528956664b9
5
+ Create Date: 2026-06-29 12:00:00.000000
6
+
7
+ """
8
+
9
+ from collections.abc import Sequence
10
+
11
+ from alembic import op
12
+
13
+ revision: str = "9d9611e47ce2"
14
+ down_revision: str | Sequence[str] | None = "d528956664b9"
15
+ branch_labels: str | Sequence[str] | None = None
16
+ depends_on: str | Sequence[str] | None = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.execute("""
21
+ create index idx_event_outbox_pending_created_at
22
+ on event_outbox (created_at, id)
23
+ where status = 'pending';
24
+ """)
25
+
26
+
27
+ def downgrade() -> None:
28
+ op.execute("drop index if exists idx_event_outbox_pending_created_at;")
@@ -79,7 +79,7 @@ allowed_headers = [
79
79
  "Profiling-Key",
80
80
  ]
81
81
 
82
- [http-client]
82
+ [http_client]
83
83
  timeout = 5.0
84
84
  max_connections = 100
85
85
  max_keepalive_connections = 10
@@ -102,6 +102,17 @@ db_name = "postgres"
102
102
  min_connections = 8
103
103
  max_connections = 15
104
104
 
105
+ [outbox]
106
+ min_connections = 2
107
+ max_connections = 4
108
+
109
+ [worker]
110
+ max_jobs = 10
111
+ max_tries = 2
112
+
113
+ [retention]
114
+ post_views_retention_days = 90
115
+
105
116
  [postgres_schemas]
106
117
  schema_extension = "extension"
107
118
  schema_user = "user"
@@ -39,7 +39,7 @@ connect_timeout = 30.0
39
39
  level = "$LOG_LEVEL"
40
40
 
41
41
  [observability]
42
- enabled = true
42
+ enabled = $OBSERVABILITY_ENABLED
43
43
  logfire_token = "$LOGFIRE_TOKEN"
44
44
  profiling_enabled = $PROFILING_ENABLED
45
45
  profiling_key = "$PROFILING_KEY"
@@ -63,7 +63,7 @@ allowed_headers = [
63
63
  "Profiling-Key",
64
64
  ]
65
65
 
66
- [http-client]
66
+ [http_client]
67
67
  timeout = 5.0
68
68
  max_connections = 100
69
69
  max_keepalive_connections = 10
@@ -86,6 +86,17 @@ db_name = "$READ_POSTGRES_DB"
86
86
  min_connections = 8
87
87
  max_connections = 15
88
88
 
89
+ [outbox]
90
+ min_connections = 2
91
+ max_connections = 4
92
+
93
+ [worker]
94
+ max_jobs = 10
95
+ max_tries = 2
96
+
97
+ [retention]
98
+ post_views_retention_days = $RETENTION_POST_VIEWS_DAYS
99
+
89
100
  [postgres_schemas]
90
101
  schema_extension = "extension"
91
102
  schema_user = "user"