core-framework 2.3.0__tar.gz → 2.3.2__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 (706) hide show
  1. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/api-reference-docs.mdc +9 -0
  2. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/constitution.mdc +1 -1
  3. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/error-boundary.mdc +3 -3
  4. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/no-code-in-docs.mdc +1 -1
  5. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/postgres-config-conventions.mdc +9 -0
  6. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/repository-schema-isolation.mdc +21 -8
  7. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/skills/add-domain/SKILL.md +1 -1
  8. core_framework-2.3.2/.cursor/skills/implement-feature/SKILL.md +93 -0
  9. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/skills/sync-host-rules/SKILL.md +5 -5
  10. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/skills/write-flow-doc/SKILL.md +2 -1
  11. {core_framework-2.3.0 → core_framework-2.3.2}/CHANGELOG.md +40 -5
  12. {core_framework-2.3.0 → core_framework-2.3.2}/PKG-INFO +3 -2
  13. {core_framework-2.3.0 → core_framework-2.3.2}/README.md +2 -0
  14. core_framework-2.3.2/alembic/analytics/alembic/versions/585105e1149e_analytics_add_utm_events.py +38 -0
  15. core_framework-2.3.2/alembic/user/alembic/versions/44df70a45ba6_user_add_signup_events.py +32 -0
  16. {core_framework-2.3.0 → core_framework-2.3.2}/config.toml +1 -0
  17. {core_framework-2.3.0 → core_framework-2.3.2}/config.toml.template +1 -0
  18. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/outbox/schemas.py +7 -3
  19. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/auth/schemas.py +1 -12
  20. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/dependencies.py +12 -14
  21. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/analytics/read_service.py +25 -0
  22. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/analytics/sources/comment_created.py +7 -0
  23. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/analytics/sources/post_created.py +7 -0
  24. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/analytics/sources/post_viewed.py +7 -0
  25. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/analytics/sources/user_registered.py +7 -0
  26. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/auth/access_service.py +2 -1
  27. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/auth/models.py +2 -0
  28. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/bootstrap.py +0 -5
  29. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/cache/models.py +4 -0
  30. core_framework-2.3.2/core_framework/application/events/README.md +29 -0
  31. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/events/event_service.py +48 -2
  32. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/events/event_token.py +2 -2
  33. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/events/models.py +2 -0
  34. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/media/attachment_read.py +1 -0
  35. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/media/attachment_service.py +15 -3
  36. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/media/read_url_config.py +4 -0
  37. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/notifications/enums.py +2 -0
  38. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/outbox/events.py +9 -0
  39. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/shared/enums.py +9 -1
  40. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/shared/exceptions.py +20 -0
  41. core_framework-2.3.2/core_framework/application/shared/request_context.py +66 -0
  42. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/users/admin_service.py +0 -2
  43. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/users/deletion_audit.py +1 -0
  44. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/users/enums.py +4 -0
  45. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/users/public_service.py +4 -2
  46. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/users/user_deletion_service.py +21 -2
  47. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/cache.py +18 -2
  48. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/database.py +5 -0
  49. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/analytics/README.md +17 -2
  50. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/analytics/__init__.py +7 -2
  51. core_framework-2.3.2/core_framework/domains/analytics/constants.py +15 -0
  52. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/analytics/dependencies.py +6 -1
  53. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/analytics/models.py +6 -0
  54. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/analytics/ports/activity_source.py +2 -0
  55. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/analytics/repository.py +95 -13
  56. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/analytics/service.py +84 -2
  57. core_framework-2.3.2/core_framework/domains/auth/README.md +68 -0
  58. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/auth/ports/auth.py +2 -0
  59. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/comment/README.md +2 -0
  60. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/comment/dependencies.py +6 -1
  61. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/comment/repository.py +219 -208
  62. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/comment/service.py +2 -0
  63. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/README.md +3 -1
  64. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/attachment/components/finals_publisher.py +2 -0
  65. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/attachment/components/staging.py +2 -0
  66. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/attachment/components/variant_encoder.py +2 -0
  67. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/attachment/ports/finals_publisher.py +2 -0
  68. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/attachment/ports/staging.py +2 -0
  69. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/attachment/ports/variant_encoder.py +2 -0
  70. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/attachment/service.py +2 -0
  71. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/components/finals_publisher.py +2 -0
  72. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/components/staging.py +3 -0
  73. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/components/variant_encoder.py +2 -0
  74. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/ports/finals_publisher.py +2 -0
  75. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/ports/staging.py +2 -0
  76. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/ports/variant_encoder.py +2 -0
  77. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/service.py +2 -0
  78. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/banner/components/finals_publisher.py +2 -0
  79. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/banner/components/staging.py +3 -0
  80. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/banner/components/variant_encoder.py +2 -0
  81. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/banner/ports/finals_publisher.py +2 -0
  82. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/banner/ports/staging.py +2 -0
  83. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/banner/ports/variant_encoder.py +2 -0
  84. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/banner/service.py +2 -0
  85. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/dependencies.py +6 -1
  86. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/shared/repository.py +63 -52
  87. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/shared/service.py +2 -0
  88. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/README.md +2 -0
  89. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/dependencies.py +14 -6
  90. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/outbox_repository.py +19 -11
  91. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/repository.py +104 -102
  92. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/service.py +2 -0
  93. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/notification/README.md +3 -3
  94. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/notification/dependencies.py +6 -1
  95. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/notification/repository.py +85 -74
  96. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/notification/service.py +2 -0
  97. core_framework-2.3.2/core_framework/domains/outbox/README.md +65 -0
  98. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/outbox/ports/consumer.py +2 -0
  99. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/outbox/ports/producer.py +4 -4
  100. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/post/README.md +2 -0
  101. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/post/dependencies.py +6 -1
  102. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/post/repository.py +238 -227
  103. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/post/service.py +2 -0
  104. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/README.md +7 -1
  105. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/dependencies.py +14 -6
  106. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/outbox_repository.py +19 -11
  107. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/repository.py +153 -126
  108. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/service.py +23 -0
  109. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/attachment_staging_display_geometry.py +4 -0
  110. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/local_attachment_staging_adapter.py +2 -0
  111. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/local_banner_staging_adapter.py +2 -0
  112. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/local_staging_adapter.py +2 -0
  113. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/pillow_attachment_variant_encoder_adapter.py +2 -0
  114. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/pillow_avatar_variant_encoder_adapter.py +2 -0
  115. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/pillow_banner_variant_encoder_adapter.py +2 -0
  116. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/ssh_attachment_finals_publisher_adapter.py +2 -0
  117. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/ssh_banner_finals_publisher_adapter.py +2 -0
  118. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/ssh_finals_publisher_adapter.py +2 -0
  119. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/outbox/outbox_consumer_adapter.py +21 -10
  120. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/outbox/outbox_producer_adapter.py +6 -4
  121. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/auth.py +20 -30
  122. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/main.py +6 -0
  123. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/analytics_refresh_cron.py +2 -0
  124. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_expired_account_deletions.py +1 -0
  125. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_expired_mute_lifts.py +1 -0
  126. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/worker_context.py +4 -0
  127. core_framework-2.3.2/docs/README.md +46 -0
  128. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/README.md +1 -1
  129. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/deploy-playbook.md +2 -1
  130. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/e2e-smoke-tests-design.md +1 -1
  131. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/edge-upload-limits.md +1 -1
  132. core_framework-2.3.2/docs/design/README.md +30 -0
  133. {core_framework-2.3.0/docs/platform → core_framework-2.3.2/docs/design}/analytics-rollup-design.md +40 -45
  134. core_framework-2.3.2/docs/design/cache-invalidation-design.md +141 -0
  135. {core_framework-2.3.0/docs/platform → core_framework-2.3.2/docs/design}/create-idempotency-design.md +19 -18
  136. {core_framework-2.3.0/docs/platform → core_framework-2.3.2/docs/design}/event-outbox-design.md +50 -169
  137. core_framework-2.3.2/docs/design/events-ingest-design.md +202 -0
  138. {core_framework-2.3.0/docs/platform → core_framework-2.3.2/docs/design}/media-storage-topology.md +2 -2
  139. {core_framework-2.3.0/docs/platform → core_framework-2.3.2/docs/design}/outbox-admin-ops-design.md +3 -3
  140. core_framework-2.3.2/docs/design/utm-events-design.md +233 -0
  141. core_framework-2.3.2/docs/domains/README.md +23 -0
  142. core_framework-2.3.2/docs/domains/analytics/admin_analytics_reads.md +135 -0
  143. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/auth/access_control.md +1 -1
  144. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/auth/registration.md +4 -3
  145. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/cache/admin_cache_invalidation.md +11 -50
  146. core_framework-2.3.2/docs/domains/comments/README.md +31 -0
  147. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/comments/admin_comments.md +6 -5
  148. core_framework-2.3.2/docs/domains/comments/comment_like.md +96 -0
  149. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/comments/comment_report.md +4 -3
  150. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/comments/comment_stats_aggregation.md +6 -7
  151. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/comments/create_comment.md +22 -18
  152. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/comments/edit_comment.md +7 -5
  153. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/comments/retrieve_comments.md +13 -9
  154. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/deletion/comments.md +1 -1
  155. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/deletion/overview.md +11 -3
  156. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/deletion/posts.md +1 -1
  157. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/deletion/users.md +110 -68
  158. core_framework-2.3.2/docs/domains/events/events.md +231 -0
  159. core_framework-2.3.2/docs/domains/media/README.md +36 -0
  160. core_framework-2.3.2/docs/domains/media/attachment_upload.md +73 -0
  161. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/media/avatar-upload-design.md +9 -9
  162. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/media/banner-upload-design.md +14 -14
  163. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/media/post-comment-attachments-design.md +10 -10
  164. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/media/upload-pipeline-design.md +51 -46
  165. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/media/upload_pipeline.md +20 -5
  166. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/mentions/mentions_in_content.md +12 -11
  167. core_framework-2.3.2/docs/domains/moderation/README.md +28 -0
  168. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/moderation/appeals.md +18 -8
  169. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/moderation/internal_notes.md +11 -10
  170. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/moderation/moderator_actions.md +6 -5
  171. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/moderation/reports.md +10 -8
  172. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/moderation/restrictions.md +55 -23
  173. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/notifications/notification_inbox.md +19 -17
  174. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/outbox/admin_outbox_ops.md +8 -6
  175. core_framework-2.3.2/docs/domains/posts/README.md +33 -0
  176. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/posts/admin_posts.md +8 -6
  177. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/posts/author_context.md +1 -1
  178. core_framework-2.3.2/docs/domains/posts/create_post.md +112 -0
  179. core_framework-2.3.2/docs/domains/posts/edit_post.md +80 -0
  180. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/posts/hashtag_discovery.md +6 -4
  181. core_framework-2.3.2/docs/domains/posts/post_report.md +105 -0
  182. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/posts/post_stats_aggregation.md +7 -8
  183. core_framework-2.3.2/docs/domains/posts/retrieve_posts.md +190 -0
  184. core_framework-2.3.2/docs/domains/users/account.md +106 -0
  185. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/account_deletion.md +6 -7
  186. core_framework-2.3.2/docs/domains/users/admin_users.md +166 -0
  187. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/avatar.md +1 -3
  188. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/banner.md +7 -8
  189. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/blocks.md +10 -9
  190. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/change_history.md +5 -4
  191. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/check_username_exists.md +3 -3
  192. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/follow-system-design.md +26 -32
  193. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/follow.md +13 -10
  194. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/my_posts_and_comments.md +4 -4
  195. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/preferences.md +1 -1
  196. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/public_profile.md +5 -5
  197. core_framework-2.3.2/docs/domains/users/user_removal.md +86 -0
  198. core_framework-2.3.2/docs/domains/users/user_stats_aggregation.md +79 -0
  199. core_framework-2.3.2/docs/library/README.md +15 -0
  200. core_framework-2.3.2/docs/library/api.md +212 -0
  201. core_framework-2.3.2/docs/library/capability-wiring.md +123 -0
  202. {core_framework-2.3.0 → core_framework-2.3.2}/docs/library/core-framework-migration.md +21 -65
  203. {core_framework-2.3.0 → core_framework-2.3.2}/docs/library/overview.md +19 -17
  204. {core_framework-2.3.0 → core_framework-2.3.2}/docs/library/package-api.md +9 -7
  205. {core_framework-2.3.0 → core_framework-2.3.2}/docs/library/testing-plugin-design.md +30 -32
  206. core_framework-2.3.2/docs/library/workers.md +81 -0
  207. core_framework-2.3.2/docs/platform/README.md +18 -0
  208. {core_framework-2.3.0 → core_framework-2.3.2}/docs/platform/architecture-decisions.md +11 -13
  209. {core_framework-2.3.0 → core_framework-2.3.2}/docs/platform/client-error-visibility.md +100 -56
  210. {core_framework-2.3.0 → core_framework-2.3.2}/docs/platform/conventions.md +22 -1
  211. core_framework-2.3.2/docs/platform/domain-services-and-adapters.md +60 -0
  212. {core_framework-2.3.0 → core_framework-2.3.2}/docs/platform/patch-update-typed-payload.md +2 -1
  213. core_framework-2.3.2/docs/testing.md +150 -0
  214. core_framework-2.3.2/docs/todo.md +75 -0
  215. {core_framework-2.3.0 → core_framework-2.3.2}/pyproject.toml +2 -2
  216. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/analytics/_helpers.py +9 -4
  217. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/_outbox_helpers.py +4 -7
  218. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/moderation/router_test.py +13 -7
  219. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/posts/router_test.py +14 -8
  220. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/users/router_test.py +9 -2
  221. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/comments/comment_attachments_integration_test.py +236 -0
  222. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/create_idempotency_integration_test.py +16 -10
  223. core_framework-2.3.2/tests/integration/api/events/router_test.py +543 -0
  224. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/notifications/router_test.py +9 -4
  225. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/posts/post_attachments_integration_test.py +294 -0
  226. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/posts/post_deletion_integration_test.py +14 -9
  227. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/posts/post_stats_dirty_marking_test.py +2 -2
  228. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/users/deletion_audit_integration_test.py +6 -1
  229. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/users/user_deletion_integration_test.py +134 -0
  230. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/account_deletion_test.py +16 -8
  231. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/create_idempotency_retention_test.py +14 -8
  232. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/moderation_outbox_test.py +15 -7
  233. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/stale_staging_sweep_test.py +6 -1
  234. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/application/events/event_service_test.py +47 -1
  235. core_framework-2.3.2/tests/unit/application/shared/request_context_test.py +30 -0
  236. core_framework-2.3.2/tests/unit/docs/_api_reference.py +67 -0
  237. core_framework-2.3.2/tests/unit/docs/api_routes_test.py +54 -0
  238. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/domains/user/service_test.py +46 -0
  239. {core_framework-2.3.0 → core_framework-2.3.2}/uv.lock +101 -12
  240. core_framework-2.3.0/.cursor/skills/implement-feature/SKILL.md +0 -66
  241. core_framework-2.3.0/core_framework/application/events/README.md +0 -35
  242. core_framework-2.3.0/core_framework/application/shared/user_agent.py +0 -25
  243. core_framework-2.3.0/core_framework/domains/analytics/constants.py +0 -3
  244. core_framework-2.3.0/docs/README.md +0 -28
  245. core_framework-2.3.0/docs/domains/README.md +0 -18
  246. core_framework-2.3.0/docs/domains/events/events.md +0 -126
  247. core_framework-2.3.0/docs/domains/users/account.md +0 -61
  248. core_framework-2.3.0/docs/domains/users/user_removal.md +0 -129
  249. core_framework-2.3.0/docs/library/README.md +0 -11
  250. core_framework-2.3.0/docs/library/api.md +0 -205
  251. core_framework-2.3.0/docs/platform/README.md +0 -19
  252. core_framework-2.3.0/docs/platform/domain-services-and-adapters.md +0 -116
  253. core_framework-2.3.0/docs/platform/events-ingest-design.md +0 -109
  254. core_framework-2.3.0/docs/todo.md +0 -11
  255. core_framework-2.3.0/tests/integration/api/events/router_test.py +0 -180
  256. {core_framework-2.3.0 → core_framework-2.3.2}/.agents/skills/fastapi +0 -0
  257. {core_framework-2.3.0 → core_framework-2.3.2}/.agents/skills/library-skills/.library-skills.json +0 -0
  258. {core_framework-2.3.0 → core_framework-2.3.2}/.agents/skills/library-skills/SKILL.md +0 -0
  259. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/alembic-migrations.mdc +0 -0
  260. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/api-layer.mdc +0 -0
  261. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/api-validation.mdc +0 -0
  262. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/application-layer.mdc +0 -0
  263. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/constants-final.mdc +0 -0
  264. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/database-triggers.mdc +0 -0
  265. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/docstrings.mdc +0 -0
  266. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/domain-caller-context.mdc +0 -0
  267. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/domain-imports.mdc +0 -0
  268. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/domain-input-guards.mdc +0 -0
  269. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/domain-repository-exceptions.mdc +0 -0
  270. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/domain-services-and-adapters.mdc +0 -0
  271. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/flow-documentation.mdc +0 -0
  272. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/inline-raise-messages.mdc +0 -0
  273. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/integration-test-strategy.mdc +0 -0
  274. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/layer-boundaries.mdc +0 -0
  275. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/strong-reads.mdc +0 -0
  276. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/rules/structured-logging.mdc +0 -0
  277. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/skills/add-config/SKILL.md +0 -0
  278. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/skills/code-review/SKILL.md +0 -0
  279. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/skills/fastapi +0 -0
  280. {core_framework-2.3.0 → core_framework-2.3.2}/.cursor/skills/recommend-features/SKILL.md +0 -0
  281. {core_framework-2.3.0 → core_framework-2.3.2}/.dockerignore +0 -0
  282. {core_framework-2.3.0 → core_framework-2.3.2}/.github/workflows/_deploy.yml +0 -0
  283. {core_framework-2.3.0 → core_framework-2.3.2}/.github/workflows/dev-ci-cd.yaml +0 -0
  284. {core_framework-2.3.0 → core_framework-2.3.2}/.github/workflows/manual-deployment.yaml +0 -0
  285. {core_framework-2.3.0 → core_framework-2.3.2}/.github/workflows/publish-pypi.yml +0 -0
  286. {core_framework-2.3.0 → core_framework-2.3.2}/.github/workflows/test.yaml +0 -0
  287. {core_framework-2.3.0 → core_framework-2.3.2}/.gitignore +0 -0
  288. {core_framework-2.3.0 → core_framework-2.3.2}/.pre-commit-config.yaml +0 -0
  289. {core_framework-2.3.0 → core_framework-2.3.2}/.python-version +0 -0
  290. {core_framework-2.3.0 → core_framework-2.3.2}/LICENSE +0 -0
  291. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/analytics/alembic/README +0 -0
  292. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/analytics/alembic/env.py +0 -0
  293. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/analytics/alembic/script.py.mako +0 -0
  294. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/analytics/alembic/versions/5b9ac98bb150_analytics_daily_fact.py +0 -0
  295. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/analytics/alembic/versions/7f2a9c1d4e8b_analytics_daily_fact_day_index.py +0 -0
  296. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/analytics/alembic.ini +0 -0
  297. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/comment/alembic/README +0 -0
  298. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/comment/alembic/env.py +0 -0
  299. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/comment/alembic/script.py.mako +0 -0
  300. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/comment/alembic/versions/comment_add_comment_attachments.py +0 -0
  301. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/comment/alembic/versions/comment_add_comment_create_idempotency.py +0 -0
  302. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/comment/alembic/versions/comment_add_comment_create_idempotency_created_at_index.py +0 -0
  303. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/comment/alembic/versions/comment_add_comment_mentions.py +0 -0
  304. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/comment/alembic/versions/comment_tombstone_status_model.py +0 -0
  305. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/comment/alembic/versions/v1_comment_init_baseline.py +0 -0
  306. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/comment/alembic.ini +0 -0
  307. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/extension/alembic/README +0 -0
  308. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/extension/alembic/env.py +0 -0
  309. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/extension/alembic/script.py.mako +0 -0
  310. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/extension/alembic/versions/v1_ext_init_baseline.py +0 -0
  311. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/extension/alembic.ini +0 -0
  312. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/media/alembic/README +0 -0
  313. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/media/alembic/env.py +0 -0
  314. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/media/alembic/script.py.mako +0 -0
  315. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/media/alembic/versions/media_add_attachment_staging_registry.py +0 -0
  316. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/media/alembic/versions/media_add_banner_staging_and_lease.py +0 -0
  317. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/media/alembic/versions/media_attachment_staging_registry_published_at.py +0 -0
  318. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/media/alembic/versions/v1_media_init_baseline.py +0 -0
  319. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/media/alembic.ini +0 -0
  320. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/moderation/alembic/README +0 -0
  321. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/moderation/alembic/env.py +0 -0
  322. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/moderation/alembic/script.py.mako +0 -0
  323. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/moderation/alembic/versions/moderation_add_event_outbox.py +0 -0
  324. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/moderation/alembic/versions/moderation_add_event_outbox_dead_indexes.py +0 -0
  325. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/moderation/alembic/versions/moderation_add_event_outbox_pending_created_at_index.py +0 -0
  326. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/moderation/alembic/versions/v1_mod_init_baseline.py +0 -0
  327. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/moderation/alembic.ini +0 -0
  328. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/notification/alembic/README +0 -0
  329. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/notification/alembic/env.py +0 -0
  330. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/notification/alembic/script.py.mako +0 -0
  331. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/notification/alembic/versions/v1_notif_init_baseline.py +0 -0
  332. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/notification/alembic.ini +0 -0
  333. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic/README +0 -0
  334. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic/env.py +0 -0
  335. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic/script.py.mako +0 -0
  336. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic/versions/post_add_post_attachments.py +0 -0
  337. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic/versions/post_add_post_create_idempotency.py +0 -0
  338. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic/versions/post_add_post_create_idempotency_created_at_index.py +0 -0
  339. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic/versions/post_add_post_mentions.py +0 -0
  340. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic/versions/post_post_views_retention_high_water_mark.py +0 -0
  341. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic/versions/post_tombstone_status_model.py +0 -0
  342. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic/versions/v1_post_init_baseline.py +0 -0
  343. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/post/alembic.ini +0 -0
  344. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/README +0 -0
  345. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/env.py +0 -0
  346. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/script.py.mako +0 -0
  347. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/versions/user_add_avatar_ingest_sequences.py +0 -0
  348. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/versions/user_add_banner_ingest_sequences.py +0 -0
  349. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/versions/user_add_date_of_birth_to_profiles.py +0 -0
  350. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/versions/user_add_event_outbox.py +0 -0
  351. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/versions/user_add_event_outbox_dead_indexes.py +0 -0
  352. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/versions/user_add_event_outbox_pending_created_at_index.py +0 -0
  353. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/versions/user_reserve_sentinel_user_ids.py +0 -0
  354. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic/versions/v1_user_init_baseline.py +0 -0
  355. {core_framework-2.3.0 → core_framework-2.3.2}/alembic/user/alembic.ini +0 -0
  356. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/__init__.py +0 -0
  357. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/__init__.py +0 -0
  358. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/__init__.py +0 -0
  359. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/analytics/router.py +0 -0
  360. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/analytics/schemas.py +0 -0
  361. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/cache/router.py +0 -0
  362. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/cache/schemas.py +0 -0
  363. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/comments/router.py +0 -0
  364. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/comments/schemas.py +0 -0
  365. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/moderation/__init__.py +0 -0
  366. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/moderation/router.py +0 -0
  367. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/moderation/schemas.py +0 -0
  368. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/outbox/router.py +0 -0
  369. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/posts/router.py +0 -0
  370. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/posts/schemas.py +0 -0
  371. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/router.py +0 -0
  372. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/users/__init__.py +0 -0
  373. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/users/router.py +0 -0
  374. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/admin/users/schemas.py +0 -0
  375. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/attachments/router.py +0 -0
  376. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/attachments/schemas.py +0 -0
  377. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/auth/__init__.py +0 -0
  378. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/auth/router.py +0 -0
  379. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/comments/authenticated/mappers.py +0 -0
  380. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/comments/authenticated/router.py +0 -0
  381. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/comments/authenticated/schemas.py +0 -0
  382. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/comments/public/router.py +0 -0
  383. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/comments/public/schemas.py +0 -0
  384. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/comments/router.py +0 -0
  385. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/comments/schemas.py +0 -0
  386. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/constants.py +0 -0
  387. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/events/router.py +0 -0
  388. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/events/schemas.py +0 -0
  389. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/idempotency/__init__.py +0 -0
  390. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/idempotency/dependencies.py +0 -0
  391. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/notifications/authenticated/router.py +0 -0
  392. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/notifications/authenticated/schemas.py +0 -0
  393. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/notifications/router.py +0 -0
  394. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/posts/authenticated/mappers.py +0 -0
  395. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/posts/authenticated/router.py +0 -0
  396. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/posts/authenticated/schemas.py +0 -0
  397. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/posts/public/router.py +0 -0
  398. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/posts/public/schemas.py +0 -0
  399. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/posts/router.py +0 -0
  400. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/posts/schemas.py +0 -0
  401. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/router.py +0 -0
  402. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/schemas.py +0 -0
  403. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/system/__init__.py +0 -0
  404. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/system/router.py +0 -0
  405. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/__init__.py +0 -0
  406. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/authenticated/__init__.py +0 -0
  407. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/authenticated/mappers.py +0 -0
  408. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/authenticated/router.py +0 -0
  409. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/authenticated/schemas.py +0 -0
  410. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/mappers.py +0 -0
  411. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/public/__init__.py +0 -0
  412. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/public/router.py +0 -0
  413. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/public/schemas.py +0 -0
  414. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/router.py +0 -0
  415. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/api/users/shared/schemas.py +0 -0
  416. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/__init__.py +0 -0
  417. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/analytics/bucket_service.py +0 -0
  418. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/analytics/prune_service.py +0 -0
  419. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/analytics/refresh_service.py +0 -0
  420. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/analytics/registry.py +0 -0
  421. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/auth/__init__.py +0 -0
  422. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/auth/auth_service.py +0 -0
  423. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/cache/invalidate_service.py +0 -0
  424. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/comments/admin_service.py +0 -0
  425. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/comments/aggregation_service.py +0 -0
  426. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/comments/authenticated_service.py +0 -0
  427. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/comments/cleanup_service.py +0 -0
  428. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/comments/public_service.py +0 -0
  429. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/media/README.md +0 -0
  430. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/media/avatar_service.py +0 -0
  431. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/media/banner_service.py +0 -0
  432. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/media/ingest_guards.py +0 -0
  433. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/moderation/__init__.py +0 -0
  434. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/moderation/appeal_service.py +0 -0
  435. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/moderation/moderator_service.py +0 -0
  436. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/moderation/report_service.py +0 -0
  437. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/moderation/scheduled_service.py +0 -0
  438. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/moderation/user_service.py +0 -0
  439. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/notifications/README.md +0 -0
  440. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/notifications/inbox_service.py +0 -0
  441. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/notifications/mute_service.py +0 -0
  442. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/notifications/notification_service.py +0 -0
  443. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/outbox/block_mirrors.py +0 -0
  444. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/outbox/exceptions.py +0 -0
  445. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/outbox/follow_mirrors.py +0 -0
  446. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/outbox/handlers.py +0 -0
  447. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/outbox/ops_service.py +0 -0
  448. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/outbox/polling_service.py +0 -0
  449. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/outbox/processing_service.py +0 -0
  450. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/outbox/restriction_mirrors.py +0 -0
  451. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/posts/admin_service.py +0 -0
  452. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/posts/aggregation_service.py +0 -0
  453. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/posts/authenticated_service.py +0 -0
  454. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/posts/cleanup_service.py +0 -0
  455. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/posts/public_service.py +0 -0
  456. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/shared/__init__.py +0 -0
  457. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/shared/worker_jobs.py +0 -0
  458. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/users/__init__.py +0 -0
  459. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/users/aggregation_service.py +0 -0
  460. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/users/authenticated_service.py +0 -0
  461. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/application/users/scheduled_service.py +0 -0
  462. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/asgi.py +0 -0
  463. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/bundled_alembic.py +0 -0
  464. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/constants.py +0 -0
  465. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/__init__.py +0 -0
  466. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/context.py +0 -0
  467. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/exception_handlers/__init__.py +0 -0
  468. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/exception_handlers/application.py +0 -0
  469. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/exception_handlers/common.py +0 -0
  470. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/exception_handlers/setup.py +0 -0
  471. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/exceptions.py +0 -0
  472. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/firebase.py +0 -0
  473. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/http_client.py +0 -0
  474. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/logging.py +0 -0
  475. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/middleware.py +0 -0
  476. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/observability.py +0 -0
  477. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/pagination.py +0 -0
  478. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/redis.py +0 -0
  479. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/runtime.py +0 -0
  480. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/core/settings.py +0 -0
  481. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/__init__.py +0 -0
  482. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/analytics/exceptions.py +0 -0
  483. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/auth/__init__.py +0 -0
  484. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/auth/dependencies.py +0 -0
  485. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/auth/exceptions.py +0 -0
  486. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/auth/models.py +0 -0
  487. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/auth/ports/__init__.py +0 -0
  488. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/auth/service.py +0 -0
  489. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/comment/__init__.py +0 -0
  490. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/comment/constants.py +0 -0
  491. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/comment/enums.py +0 -0
  492. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/comment/exceptions.py +0 -0
  493. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/comment/models.py +0 -0
  494. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/comment/outcomes.py +0 -0
  495. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/exceptions.py +0 -0
  496. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/__init__.py +0 -0
  497. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/attachment/constants.py +0 -0
  498. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/attachment/exceptions.py +0 -0
  499. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/attachment/models.py +0 -0
  500. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/__init__.py +0 -0
  501. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/components/__init__.py +0 -0
  502. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/constants.py +0 -0
  503. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/exceptions.py +0 -0
  504. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/models.py +0 -0
  505. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/avatar/ports/__init__.py +0 -0
  506. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/banner/constants.py +0 -0
  507. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/banner/exceptions.py +0 -0
  508. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/banner/models.py +0 -0
  509. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/shared/__init__.py +0 -0
  510. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/shared/constants.py +0 -0
  511. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/shared/exceptions.py +0 -0
  512. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/shared/outcomes.py +0 -0
  513. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/media/shared/utils.py +0 -0
  514. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/__init__.py +0 -0
  515. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/enums.py +0 -0
  516. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/exceptions.py +0 -0
  517. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/models.py +0 -0
  518. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/outbox_service.py +0 -0
  519. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/moderation/outcomes.py +0 -0
  520. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/notification/__init__.py +0 -0
  521. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/notification/enums.py +0 -0
  522. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/notification/exceptions.py +0 -0
  523. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/notification/models.py +0 -0
  524. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/outbox/__init__.py +0 -0
  525. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/outbox/dependencies.py +0 -0
  526. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/outbox/models.py +0 -0
  527. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/outbox/ports/admin.py +0 -0
  528. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/outbox/service.py +0 -0
  529. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/post/__init__.py +0 -0
  530. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/post/constants.py +0 -0
  531. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/post/enums.py +0 -0
  532. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/post/exceptions.py +0 -0
  533. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/post/models.py +0 -0
  534. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/post/outcomes.py +0 -0
  535. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/__init__.py +0 -0
  536. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/constants.py +0 -0
  537. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/enums.py +0 -0
  538. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/exceptions.py +0 -0
  539. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/models.py +0 -0
  540. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/outbox_service.py +0 -0
  541. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/outcomes.py +0 -0
  542. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/user/utils.py +0 -0
  543. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/domains/utils.py +0 -0
  544. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/__init__.py +0 -0
  545. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/firebase/__init__.py +0 -0
  546. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/firebase/firebase_auth_adapter.py +0 -0
  547. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/__init__.py +0 -0
  548. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/infrastructure/media/pillow_staging_image.py +0 -0
  549. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/main.py +0 -0
  550. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/migrate_cli.py +0 -0
  551. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/__init__.py +0 -0
  552. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/arq.py +0 -0
  553. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/config.py +0 -0
  554. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/containers.py +0 -0
  555. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/firebase.py +0 -0
  556. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/firebase_identity_toolkit.py +0 -0
  557. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/hookspecs.py +0 -0
  558. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/httpx_test_client.py +0 -0
  559. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/media.py +0 -0
  560. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/migrations.py +0 -0
  561. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/testing/plugin.py +0 -0
  562. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/__init__.py +0 -0
  563. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/__init__.py +0 -0
  564. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_aggregate_comment_stats.py +0 -0
  565. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_aggregate_post_stats.py +0 -0
  566. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_aggregate_user_stats.py +0 -0
  567. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_poll_outbox.py +0 -0
  568. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_prune_analytics_daily_facts.py +0 -0
  569. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_prune_post_views.py +0 -0
  570. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_purge_expired_create_idempotency_keys.py +0 -0
  571. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_refresh_analytics.py +0 -0
  572. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_sweep_stale_attachment_staging.py +0 -0
  573. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_sweep_stale_avatar_staging.py +0 -0
  574. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/schedules/schedule_sweep_stale_banner_staging.py +0 -0
  575. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/__init__.py +0 -0
  576. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/delete_attachment_finals.py +0 -0
  577. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/delete_superseded_avatar_finals.py +0 -0
  578. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/delete_superseded_banner_finals.py +0 -0
  579. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_account_deletion.py +0 -0
  580. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_admin_user_deletion.py +0 -0
  581. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_aggregate_comment_stats.py +0 -0
  582. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_aggregate_post_stats.py +0 -0
  583. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_aggregate_user_stats.py +0 -0
  584. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_attachment_asset_variants.py +0 -0
  585. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_banner_asset_variants.py +0 -0
  586. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_cache_pattern_invalidation.py +0 -0
  587. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_destructive_comment_delete.py +0 -0
  588. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_destructive_post_delete.py +0 -0
  589. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_media_asset_variants.py +0 -0
  590. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_mute_lift.py +0 -0
  591. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_outbox_row.py +0 -0
  592. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_refresh_analytics_bucket.py +0 -0
  593. {core_framework-2.3.0 → core_framework-2.3.2}/core_framework/worker/tasks/process_user_content_deletion.py +0 -0
  594. {core_framework-2.3.0 → core_framework-2.3.2}/docker-compose.dev.yaml +0 -0
  595. {core_framework-2.3.0 → core_framework-2.3.2}/docker-compose.yml +0 -0
  596. {core_framework-2.3.0 → core_framework-2.3.2}/dockerfile +0 -0
  597. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/examples/Caddyfile.example +0 -0
  598. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/examples/image-server-known-hosts.example +0 -0
  599. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/guides/app-server-deploy-ssh.md +0 -0
  600. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/guides/image-server-ssh.md +0 -0
  601. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/guides/postgres-setup.md +0 -0
  602. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/guides/redis-setup.md +0 -0
  603. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/guides/ubuntu-server-setup.md +0 -0
  604. {core_framework-2.3.0 → core_framework-2.3.2}/docs/deployments/release-playbook.md +0 -0
  605. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/comments/delete_comment.md +0 -0
  606. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/posts/post_like.md +0 -0
  607. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/posts/post_visibility.md +0 -0
  608. {core_framework-2.3.0 → core_framework-2.3.2}/docs/domains/users/profile.md +0 -0
  609. {core_framework-2.3.0 → core_framework-2.3.2}/docs/platform/database-triggers.md +0 -0
  610. {core_framework-2.3.0 → core_framework-2.3.2}/docs/platform/layers-and-boundaries.md +0 -0
  611. {core_framework-2.3.0 → core_framework-2.3.2}/firebase_config.example.json +0 -0
  612. {core_framework-2.3.0 → core_framework-2.3.2}/makefile +0 -0
  613. {core_framework-2.3.0 → core_framework-2.3.2}/tests/__init__.py +0 -0
  614. {core_framework-2.3.0 → core_framework-2.3.2}/tests/conftest.py +0 -0
  615. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/_auth.py +0 -0
  616. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/_canaries.py +0 -0
  617. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/_media.py +0 -0
  618. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/_settings.py +0 -0
  619. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/_upload_payloads.py +0 -0
  620. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/conftest.py +0 -0
  621. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/media/pipeline_test.py +0 -0
  622. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/smoke/canary_test.py +0 -0
  623. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/smoke/media_test.py +0 -0
  624. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/smoke/system_test.py +0 -0
  625. {core_framework-2.3.0 → core_framework-2.3.2}/tests/e2e/smoke/tls_host_test.py +0 -0
  626. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/__init__.py +0 -0
  627. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/_http_error_details.py +0 -0
  628. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/__init__.py +0 -0
  629. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/_auth_helpers.py +0 -0
  630. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/_destructive_delete_helpers.py +0 -0
  631. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/_http_helpers.py +0 -0
  632. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/_user_deletion_helpers.py +0 -0
  633. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/_user_helpers.py +0 -0
  634. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/__init__.py +0 -0
  635. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/_auth_cases.py +0 -0
  636. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/analytics/__init__.py +0 -0
  637. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/analytics/router_test.py +0 -0
  638. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/cache/__init__.py +0 -0
  639. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/cache/router_test.py +0 -0
  640. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/comments/__init__.py +0 -0
  641. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/comments/router_test.py +0 -0
  642. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/moderation/__init__.py +0 -0
  643. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/moderation/_auth_cases.py +0 -0
  644. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/outbox/__init__.py +0 -0
  645. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/outbox/router_test.py +0 -0
  646. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/posts/__init__.py +0 -0
  647. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/admin/users/__init__.py +0 -0
  648. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/attachments/_helpers.py +0 -0
  649. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/attachments/attachment_upload_test.py +0 -0
  650. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/auth/__init__.py +0 -0
  651. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/auth/router_test.py +0 -0
  652. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/comments/__init__.py +0 -0
  653. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/comments/authenticated/__init__.py +0 -0
  654. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/comments/authenticated/comment_writes_integration_test.py +0 -0
  655. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/comments/public/__init__.py +0 -0
  656. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/comments/public/router_test.py +0 -0
  657. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/media/ingest_contract_test.py +0 -0
  658. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/mentions/mentions_integration_test.py +0 -0
  659. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/notifications/__init__.py +0 -0
  660. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/posts/__init__.py +0 -0
  661. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/posts/authenticated/post_writes_integration_test.py +0 -0
  662. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/posts/comment_count_aggregation_test.py +0 -0
  663. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/posts/followers_visibility_test.py +0 -0
  664. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/posts/public/__init__.py +0 -0
  665. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/posts/public/router_test.py +0 -0
  666. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/public_read_by_id_unavailable_detail_test.py +0 -0
  667. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/system/__init__.py +0 -0
  668. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/system/router_test.py +0 -0
  669. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/users/__init__.py +0 -0
  670. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/users/authenticated/__init__.py +0 -0
  671. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/users/authenticated/avatar_upload_test.py +0 -0
  672. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/users/authenticated/banner_upload_test.py +0 -0
  673. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/users/authenticated/router_test.py +0 -0
  674. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/users/public/__init__.py +0 -0
  675. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/api/users/public/router_test.py +0 -0
  676. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/__init__.py +0 -0
  677. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/_media_upload_helpers.py +0 -0
  678. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/aggregate_comment_stats_test.py +0 -0
  679. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/aggregate_post_stats_test.py +0 -0
  680. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/aggregate_user_stats_test.py +0 -0
  681. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/analytics_prune_test.py +0 -0
  682. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/analytics_refresh_test.py +0 -0
  683. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/attachment_upload_test.py +0 -0
  684. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/avatar_upload_test.py +0 -0
  685. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/banner_upload_test.py +0 -0
  686. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/conftest.py +0 -0
  687. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/mute_lift_test.py +0 -0
  688. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/user_outbox_test.py +0 -0
  689. {core_framework-2.3.0 → core_framework-2.3.2}/tests/integration/worker/utils_test.py +0 -0
  690. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/__init__.py +0 -0
  691. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/api/comments/authenticated/comment_request_schemas_test.py +0 -0
  692. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/api/dedupe_preserving_order_test.py +0 -0
  693. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/api/posts/authenticated/post_update_mapper_test.py +0 -0
  694. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/api/users/profile_update_mapper_test.py +0 -0
  695. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/application/comments/__init__.py +0 -0
  696. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/application/notifications/inbox_service_test.py +0 -0
  697. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/application/users/deletion_audit_test.py +0 -0
  698. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/core/bundled_alembic_test.py +0 -0
  699. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/core/migrate_cli_test.py +0 -0
  700. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/core/pagination_test.py +0 -0
  701. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/domains/__init__.py +0 -0
  702. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/domains/comment/__init__.py +0 -0
  703. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/domains/post/models_test.py +0 -0
  704. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/infrastructure/__init__.py +0 -0
  705. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/infrastructure/media/__init__.py +0 -0
  706. {core_framework-2.3.0 → core_framework-2.3.2}/tests/unit/infrastructure/media/ssh_finals_publisher_adapter_test.py +0 -0
@@ -29,3 +29,12 @@ globs:
29
29
  - Detailed behavior notes
30
30
 
31
31
  For detailed API behavior, create or update flow documentation in `docs/domains/` instead.
32
+
33
+ ## CI contract
34
+
35
+ `tests/unit/docs/api_routes_test.py` parses this file and asserts **bidirectional** parity with the core FastAPI app:
36
+
37
+ - every listed `(METHOD, path)` exists on the app with **matching path-param names**
38
+ - every app `(METHOD, path)` (GET/POST/PUT/PATCH/DELETE) is listed here
39
+
40
+ Flow docs under `docs/domains/` must not list endpoints in their `http` blocks unless those exact routes appear here. Update this index when adding or renaming routes.
@@ -39,4 +39,4 @@ Do not edit consuming host repos in the same task as core-framework work unless
39
39
 
40
40
  ## Feature implementation
41
41
 
42
- Greenfield features (DB → API → repository → service → tests): use the **implement-feature** skill — one layer per response unless the user says otherwise.
42
+ Greenfield features (DB → API → repository → service → **documentation** → tests): use the **implement-feature** skill — one layer per response unless the user says otherwise. A feature is **not done** until documentation is updated.
@@ -16,10 +16,10 @@ Platform contract: **`docs/platform/client-error-visibility.md`**. Domain import
16
16
 
17
17
  | Layer | Outward errors | HTTP |
18
18
  |-------|----------------|------|
19
- | **Application** | **`application.shared.exceptions`**, **`InvalidPageTokenError`** | Handlers map type → status + `detail` |
19
+ | **Application** | **`application.shared.exceptions`**, **`InvalidPageTokenError`** | Handlers map type → status + catalog **`detail`** |
20
+ | **API** | Pydantic; **`HTTPException`** for transport-local guards | **422** field errors; router-chosen status + **`detail`** |
20
21
  | **Domain typed** | Internal — not imported by API/application | No typed handlers |
21
22
  | **Domain `BaseXxxException`** | Handler catch-all only | **500** if leaked |
22
- | **API** | Pydantic | **422** |
23
23
 
24
24
  ## Application and domain
25
25
 
@@ -47,7 +47,7 @@ Platform contract: **`docs/platform/client-error-visibility.md`**. Domain import
47
47
 
48
48
  ## Validation order
49
49
 
50
- User-fixable input shape → API schemas (**422**). Domain backstops → **`DomainValidationError`** → generic **400**.
50
+ User-fixable input shape → API schemas (**422**) or router **`HTTPException`**. Use-case outcomes → application exceptions + handlers. Domain backstops → **`DomainValidationError`** → generic **400** (never domain text in **`detail`**).
51
51
 
52
52
  ## Logging
53
53
 
@@ -28,7 +28,7 @@ Documentation under **`docs/`** must not carry **implementation** snippets that
28
28
  ## Exceptions
29
29
 
30
30
  - **Deployment runbooks** under **`docs/deployments/`** (setup guides, deploy/release playbooks, SSH/image-server guides) may include fenced **`bash`** shell blocks. These are operator instructions for interactive server setup, not implementation that drifts from source; copy-paste commands are the practical content. This exemption does **not** extend to **`docs/deployments/*-design.md`** design docs, which follow the general rules above.
31
- - **Design docs** under **`docs/platform/`** and **`docs/library/`** (and **`docs/deployments/*-design.md`**) follow the general allow/exclude lists — DDL is allowed, DML and Python are not. Flow docs under **`docs/domains/**`** are stricter: see **`flow-documentation.mdc`** (no DDL, no JSON request bodies, fields described as text/tables).
31
+ - **Design docs** under **`docs/design/`**, **`docs/platform/`**, and **`docs/library/`** (and **`docs/deployments/*-design.md`**) follow the general allow/exclude lists — DDL is allowed, DML and Python are not. Flow docs under **`docs/domains/**`** are stricter: see **`flow-documentation.mdc`** (no DDL, no JSON request bodies, fields described as text/tables).
32
32
 
33
33
  ## Rationale
34
34
 
@@ -45,3 +45,12 @@ Use explicit write/read configuration and keep schema names shared.
45
45
  - `read_postgres`
46
46
  - Domain dependencies pass `(write, read, strong)` explicitly to repositories.
47
47
  - Until a dedicated strong instance exists, use write instance for the strong argument intentionally.
48
+
49
+ ## Schema names in SQL
50
+
51
+ - Schema names come only from `settings.postgres_schemas` (see **Settings Model** above).
52
+ - Domain `dependencies.py` passes unquoted `schema=runtime.settings.postgres_schemas.schema_<domain>` into repositories (keyword-only `__init__`).
53
+ - Repositories cache `self.schema_sql = quote_postgres_identifier(schema)` and use `{self.schema_sql}.table` in f-string SQL — never hard-coded `"post".` literals.
54
+ - Outbox producer adapter is wired per domain with `schema` at construction; consumer adapter receives unquoted `schema` per call and caches quoted SQL.
55
+
56
+ Repository isolation rules (no cross-domain schema access): **`repository-schema-isolation.mdc`**.
@@ -11,10 +11,19 @@ Each domain repository may only read/write tables in **its own** Postgres schema
11
11
 
12
12
  Canonical rule: `docs/platform/layers-and-boundaries.md` — *no cross-domain schema reads, writes, joins, or foreign keys*.
13
13
 
14
+ ## Schema qualification
15
+
16
+ Repositories receive unquoted `schema` from `runtime.settings.postgres_schemas` in `dependencies.py` (keyword-only `__init__` arg). In `__init__`:
17
+
18
+ - `self.schema` — config schema name (e.g. `post`)
19
+ - `self.schema_sql` — `quote_postgres_identifier(schema)` for SQL interpolation
20
+
21
+ Use `{self.schema_sql}.table` in f-string SQL — not hard-coded `"post".` literals.
22
+
14
23
  ## Allowed in a repository
15
24
 
16
- - SQL qualified with that domain's schema only (e.g. `"post".posts` in `PostRepository`).
17
- - **Within-schema** policy gates (e.g. `insert_post_like` checks `"post".posts.status = active`).
25
+ - SQL qualified with that domain's schema only (e.g. `{self.schema_sql}.posts` in `PostRepository`).
26
+ - **Within-schema** policy gates (e.g. `insert_post_like` checks `{self.schema_sql}.posts.status = active`).
18
27
  - **Lookup mirrors** in the same schema (`user_blocks_lookup`, `user_restrictions_lookup`, `user_followers_lookup`) — synced by application flows; mirrors are not authoritative.
19
28
 
20
29
  ## Forbidden in a repository
@@ -23,18 +32,18 @@ Canonical rule: `docs/platform/layers-and-boundaries.md` — *no cross-domain sc
23
32
  - Importing another domain's `service`, `repository`, or models to enforce policy.
24
33
 
25
34
  ```python
26
- # ❌ moderation/repository.py — cross-domain EXISTS
27
- insert into "moderation".post_reports (...)
35
+ # ❌ moderation/repository.py — cross-domain EXISTS (illustrative schema literals)
36
+ insert into {moderation_schema_sql}.post_reports (...)
28
37
  select $1, $2, $3, $4
29
38
  where exists (
30
- select 1 from "post".posts
39
+ select 1 from {post_schema_sql}.posts
31
40
  where id = $2 and status = 'active'
32
41
  )
33
42
 
34
43
  # ❌ notification/repository.py — cross-domain mute gate
35
- insert into "notification".notification_mutes (...)
44
+ insert into {notification_schema_sql}.notification_mutes (...)
36
45
  select ...
37
- where exists (select 1 from "comment".comments where ...)
46
+ where exists (select 1 from {comment_schema_sql}.comments where ...)
38
47
  ```
39
48
 
40
49
  ## Alembic migrations (different convention)
@@ -69,4 +78,8 @@ Before adding a repository write that depends on another domain's row state:
69
78
 
70
79
  ## Self-check (repositories only)
71
80
 
72
- In `domains/<name>/repository.py`, every `"<schema>".` qualifier in SQL must be `<name>` (or that domain's documented mirror tables in the same schema).
81
+ In `domains/<name>/repository.py`:
82
+
83
+ - Every table/type qualifier in SQL must use `{self.schema_sql}.…` (that domain's schema only).
84
+ - Do not hard-code `"user".`, `"post".`, etc. — use `self.schema` / `self.schema_sql` from config.
85
+ - Mirror lookup tables (`user_blocks_lookup`, etc.) still live under `{self.schema_sql}` when they belong to that domain's schema.
@@ -18,7 +18,7 @@ Follow the **implement-feature** skill: one step per response, wait for review.
18
18
  Not every domain owns persistence. A **capability-only** domain wraps a non-SQL capability (for example `auth`, which wraps Firebase Admin via `domains/auth/ports/`, `domains/auth/service.py`, and `core_framework/infrastructure/firebase/`). For those, **skip** schema config, the Alembic tree, and `ALEMBIC_DOMAINS` entirely — no `schema_<domain>` in `PostgresSchemasConfig` / `[postgres_schemas]`, no `alembic/<domain>/`, no repository. Scaffold only:
19
19
 
20
20
  - `domains/<domain>/{__init__.py, exceptions.py, models.py, ports/, service.py, dependencies.py}`
21
- - A port (`<Name>Port`) describing the capability, a facade `*Service` over it, and an adapter under `core_framework/infrastructure/<domain>/` wired in `dependencies.py` — see `docs/platform/domain-services-and-adapters.md` (Auth section) for the layout.
21
+ - A port (`<Name>Port`) describing the capability, a facade `*Service` over it, and an adapter under `core_framework/infrastructure/<domain>/` wired in `dependencies.py` — see `docs/platform/domain-services-and-adapters.md` (rules) and `docs/library/capability-wiring.md` (Auth example).
22
22
  - Export only `Base<Domain>Exception` + public models from `__init__.py`; keep the facade service in `dependencies.py`.
23
23
  - Wire `configure_<domain>_dependencies()` in `application/bootstrap.py` (no `runtime` needed when there is no Postgres handle).
24
24
 
@@ -0,0 +1,93 @@
1
+ ---
2
+ name: implement-feature
3
+ description: Step-by-step feature implementation — DB → API → repository → service/application → documentation → tests. Use when adding a new feature, endpoint, or domain behavior across layers, or when the user asks to follow the implementation workflow.
4
+ ---
5
+
6
+ # Implement Feature
7
+
8
+ Implement **one step at a time**. Stop after each step and wait for user review. Do **not** skip ahead or implement multiple layers in one response unless the user **explicitly** says "implement everything" or "do it all at once".
9
+
10
+ ## Definition of done
11
+
12
+ A feature is **not complete** until **all** documentation for the shipped behavior is updated. Code merged without matching docs is **unfinished work** — do not treat the feature as done or move on until the documentation step is accepted.
13
+
14
+ ## Before you start
15
+
16
+ - Do **not** implement repository, service, or application code when doing the API layer.
17
+ - Do **not** implement multiple layers in a single response.
18
+ - When in doubt, do **less** and wait for review.
19
+
20
+ ## 1. Database changes (if needed)
21
+
22
+ - **Only** create the Alembic migration file(s).
23
+ - **No** code changes anywhere else.
24
+ - Wait for the user to review and accept the database structure before proceeding.
25
+
26
+ ## 2. API layer (if needed)
27
+
28
+ After the user accepts database changes (or if there were none):
29
+
30
+ - **Only** implement the API layer: schemas and router.
31
+ - Follow the **fastapi** skill (`.agents/skills/fastapi/`) and **`api-layer`** / **`api-validation`** / **`error-boundary`** rules.
32
+ - **No** changes in domain, service, or application layers.
33
+ - Include request/response schemas, error handling, and HTTP-related logic.
34
+ - If the feature is not yet implemented, return 501 Not Implemented from the route.
35
+ - Wait for the user to review and accept before proceeding.
36
+
37
+ ## 3. Repository and domain model
38
+
39
+ After the user accepts the API layer (or if there was no API layer):
40
+
41
+ - Implement the **Repository** for the domain layer (Postgres only).
42
+ - Include the **domain model** if data is retrieved from the database.
43
+ - If the feature needs non-SQL I/O (filesystem, HTTP, SSH), add **ports** in the domain and **adapter implementations** under `core_framework/infrastructure/<domain>/` per `docs/platform/domain-services-and-adapters.md` — not in the repository.
44
+ - Wait for the user to review and accept before proceeding.
45
+
46
+ ## 4. Service and application layer
47
+
48
+ After the user accepts the repository (and any ports/adapters):
49
+
50
+ - Implement **domain service(s)** (persistence and any port-backed collaborators); wire in `dependencies.py`.
51
+ - Implement the **application** layer (orchestration across domains and transports — no permanent home for raw I/O libraries).
52
+ - Wire everything together (replace 501 with real logic).
53
+ - Wait for the user to review and accept before proceeding.
54
+
55
+ ## 5. Documentation (required)
56
+
57
+ After the user accepts the service and application layer:
58
+
59
+ Update **every** doc surface the feature touches. Use the **write-flow-doc** skill for new or changed HTTP behavior. Follow **`no-code-in-docs.mdc`** and **`flow-documentation.mdc`**.
60
+
61
+ | Change | Update |
62
+ | ------------------------------------------- | -------------------------------------------------------------------------------- |
63
+ | New or changed HTTP endpoint | Flow doc under `docs/domains/{domain}/`; add **`Current Implementation Status`** |
64
+ | New or changed route in the index | `docs/library/api.md` (endpoint list only — see **`api-reference-docs.mdc`**) |
65
+ | New flow or design doc file | `docs/domains/README.md` (and `docs/design/README.md` if cross-cutting) |
66
+ | New cross-cutting mechanism | `docs/design/*-design.md` |
67
+ | New or changed worker schedule or ARQ task | `docs/library/workers.md`; link from domain flow or design doc |
68
+ | Domain scope, tables, or invariants changed | `core_framework/domains/{domain}/README.md` |
69
+ | New audit trigger | `docs/platform/database-triggers.md` |
70
+ | Settings / config the host must wire | `docs/library/package-api.md` and/or **add-config** skill targets |
71
+ | Accepted policy or ADR | `docs/platform/architecture-decisions.md` when the feature locks a new decision |
72
+
73
+ **Do not** mark a feature done while any row above still applies and is missing an update.
74
+
75
+ Wait for the user to review and accept documentation before proceeding (or before declaring the feature complete when tests are skipped).
76
+
77
+ ## 6. Tests (when requested)
78
+
79
+ After documentation is accepted:
80
+
81
+ - Add or update integration tests when the user asks for tests in this task.
82
+ - If the user did not ask for tests, the feature is **done** after step 5 is accepted.
83
+
84
+ ## Flexibility
85
+
86
+ If the feature has no database change (e.g., pure logic, workers) or no API layer (e.g., background workers, internal jobs), skip the irrelevant steps and follow the remaining order. **Documentation (step 5) still applies** whenever behavior ships.
87
+
88
+ ## Checklist (verify before every response)
89
+
90
+ - [ ] Did I implement only one step?
91
+ - [ ] Did I stop and wait for review?
92
+ - [ ] Did I skip ahead to other layers? (If yes, roll back and redo.)
93
+ - [ ] If this step finishes the feature: is **all** required documentation updated? (If no, the feature is **not** done.)
@@ -12,7 +12,7 @@ Consuming applications embed **core-framework** as a dependency.
12
12
  When changing **core-framework** code, migrations, tests, or **`docs/`**:
13
13
 
14
14
  - **Do not** edit host repos in the same task.
15
- - **Do not** port **`docs/platform/`**, **`docs/deployments/`**, **`.cursor/rules/`**, or **`.cursor/skills/`** to hosts proactively.
15
+ - **Do not** port **`docs/platform/`**, **`docs/design/`**, **`docs/deployments/`**, **`.cursor/rules/`**, or **`.cursor/skills/`** to hosts proactively.
16
16
  - Mention that host sync is **deferred until the host bumps its core-framework version** (unless the user asked otherwise).
17
17
 
18
18
  ## When host changes are allowed
@@ -35,7 +35,7 @@ Diff by **basename** against the host's **`.cursor/`** and applicable **`docs/`*
35
35
 
36
36
  **Core `docs/` must stay host-agnostic** — no references to specific consuming applications.
37
37
 
38
- | Core path | Host behavior |
39
- | --------------------------------------------- | ------------------------------------------------------------- |
40
- | **`docs/platform/`**, **`docs/deployments/`** | Sync on dependency upgrade or explicit sync request |
41
- | **`docs/domains/`**, **`docs/library/`** | Canonical in core only — do not mirror product trees to hosts |
38
+ | Core path | Host behavior |
39
+ | ----------------------------------------------------------------- | ------------------------------------------------------------- |
40
+ | **`docs/platform/`**, **`docs/design/`**, **`docs/deployments/`** | Sync on dependency upgrade or explicit sync request |
41
+ | **`docs/domains/`**, **`docs/library/`** | Canonical in core only — do not mirror product trees to hosts |
@@ -74,5 +74,6 @@ Concise, active voice, present tense, client perspective. Horizontal rules betwe
74
74
 
75
75
  - [ ] Endpoint list at top; each endpoint has Goal, Preconditions, Flow, Errors
76
76
  - [ ] No implementation identifiers or code snippets
77
- - [ ] Links to **`docs/platform/architecture-decisions.md`** when referencing design choices
77
+ - [ ] Links to **`docs/platform/architecture-decisions.md`** when referencing accepted policy or ADR decisions
78
+ - [ ] Links to **`docs/design/`** when referencing cross-cutting mechanisms (outbox, events ingest, idempotency, analytics rollup, etc.)
78
79
  ```
@@ -4,13 +4,45 @@ Notable changes to **core-framework** (import **`core_framework`**). Format foll
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.3.2] - 2026-07-05
8
+
9
+ ### Added
10
+
11
+ - **UTM attribution ingest:** `POST /events` with `type: "utm_data"` records `analytics.utm_events` (`utm` and `request_context` jsonb; optional `user_id`). UTM keys are sent as `events[]` items (`subject_type` = field name, `subject` = value). See **`docs/domains/events/events.md`** and **`docs/design/utm-events-design.md`**.
12
+ - **Signup telemetry:** `POST /events` with `type: "signup"` records `user_signup_events` (one row per user, `request_context` jsonb) after `POST /auth/register`. See **`docs/domains/events/events.md`**.
13
+ - **Request context parsing:** `application/shared/request_context.py` normalizes `User-Agent`, `client-referrer` (`referrer_url`, `referrer_host`), and `Cf-Ipcountry` for events ingest.
14
+
15
+ ### Breaking
16
+
17
+ - **Breaking (clients — events ingest):** Traffic source for request context uses the **`client-referrer`** header instead of browser **`Referer`**. Clients should send an explicit referrer URL (for example captured from `document.referrer` on first load).
18
+ - **Breaking (clients — events ingest):** Rename event type **`view`** → **`impression`** on `POST /events`. Clients and hosts must send `type: "impression"` for subject-impression batches (post views, calculator opens, etc.). Core enum: **`EventType.IMPRESSION`** (replaces **`EventType.VIEW`**). Host handlers registered on `"view"` must re-register on **`"impression"`** (for example Henry calculator view ingest).
19
+ - **Breaking (hosts — imports):** Rename **`EVENT_TOKEN_MAX_AGE_VIEW_SECONDS`** → **`EVENT_TOKEN_MAX_AGE_SECONDS`** in **`core_framework.application.events.event_token`** (behavior unchanged; token max-age remains 600s for all event types).
20
+
21
+ ### Migration
22
+
23
+ - **`analytics` schema:** **`585105e1149e_analytics_add_utm_events`** — `utm_events` table. Run **`cf-alembic`** when upgrading.
24
+ - **`user` schema:** **`44df70a45ba6_user_add_signup_events`** — `user_signup_events` table (`user_id` unique, `request_context` jsonb). Run **`cf-alembic`** when upgrading.
25
+
26
+ ## [2.3.1] - 2026-07-03
27
+
28
+ ### Added
29
+
30
+ - **Partial admin user deletions:** `tombstone_authored_posts_only` and `tombstone_authored_comments_only` on `POST /admin/users/{user_id}/deletions` — moderator tombstone of authored posts or comments while keeping the account. See **`docs/domains/deletion/users.md`**.
31
+ - **`docs/testing.md`** — usage-focused pytest plugin guide for host adopters (wiring, fixtures, tiers, troubleshooting). Design reference remains **`docs/library/testing-plugin-design.md`**.
32
+ - **Post/comment attachment integration tests:** v1.1 create/edit coverage — best-effort attach (unknown or already-linked assets), attach before worker publish, edit-budget enforcement, clear-all patch, and tombstone finals cleanup. See **`tests/integration/api/posts/post_attachments_integration_test.py`** and **`tests/integration/api/comments/comment_attachments_integration_test.py`**.
33
+ - **Analytics rollup:** `retrieve_daily_fact_kind_totals_for_range` on `AnalyticsService` and `retrieve_analytics_kind_totals_for_range` in `application/analytics/read_service` — sum `daily_fact` counts per `kind` over an inclusive UTC day range (for host catalog and similar reads).
34
+
35
+ ### Fixed
36
+
37
+ - **Admin outbox schemas:** rename response field `schema` to `producing_schema` with JSON alias `schema` so Pydantic no longer warns about shadowing `BaseModel.schema`.
38
+
7
39
  ## [2.3.0] - 2026-07-03
8
40
 
9
41
  Analytics rollup domain (materialized daily activity counts), admin read API, and retention prune. Hosts must add **`[analytics]`** and **`schema_analytics`**, run **`cf-alembic`**, and run the worker for rollup refresh and daily-fact prune.
10
42
 
11
43
  ### Added
12
44
 
13
- - **Analytics rollup (Phase 1):** `analytics` domain scaffold, `schema_analytics`, `[analytics].refresh_interval_seconds` (required on **`Settings`**; core **`config.toml`** ships **300**), Alembic tree with `daily_fact` table (PK only), and activity source registry shell. See **`docs/platform/analytics-rollup-design.md`**.
45
+ - **Analytics rollup (Phase 1):** `analytics` domain scaffold, `schema_analytics`, `[analytics].refresh_interval_seconds` (required on **`Settings`**; core **`config.toml`** ships **300**), Alembic tree with `daily_fact` table (PK only), and activity source registry shell. See **`docs/design/analytics-rollup-design.md`**.
14
46
  - **Analytics rollup (Phase 2):** `AnalyticsService.list_refreshable_days` and `is_final_bucket_refresh` (planner inputs), `refresh_daily_fact_bucket` (single-bucket executor), optional `refresh_all_open_buckets` for tests; transactional `replace_daily_fact_bucket`; admin read helpers.
15
47
  - **Analytics rollup (Phase 3):** `post` / `created` activity source, planner (`enqueue_refresh_analytics_buckets`) and executor (`refresh_analytics_bucket`) application entrypoints, `schedule_refresh_analytics` + `process_refresh_analytics_bucket` worker (cron from `refresh_interval_seconds`).
16
48
  - **Analytics rollup (Phase 4):** `comment` / `created`, `user` / `registered`, and `post` / `viewed` activity sources with domain UTC-day count accessors and registry registration.
@@ -30,7 +62,7 @@ Transactional outbox (block, follow, restriction), post views retention, and inc
30
62
  ### Added
31
63
 
32
64
  - **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`**.
33
- - **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`**.
65
+ - **Transactional outbox (block pilot):** `user.event_outbox`, worker poller/handler for **`user.block.relationship_changed`**, durable post/comment/notification block mirror fanout. See **`docs/design/event-outbox-design.md`**.
34
66
  - **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**).
35
67
  - **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`**.
36
68
 
@@ -75,7 +107,7 @@ First production-ready **2.x** release. Hosts must run **`cf-alembic`**, configu
75
107
 
76
108
  - **Post and comment image attachments (v1):** **`POST /attachments`** compose-time ingest; worker encodes and publishes **`thumb`** / **`display`** WebP finals; **`attachment_ids`** on post/comment create and **`PATCH`** diff edit — attach is **best-effort per added asset** on create **and** edit (failing assets are skipped and burned; the post/comment write still succeeds and mention notifications proceed; malformed sets — duplicates or over-cap — fail request validation with **`422`**, with the same guards re-checked in the post/comment domain services); public and admin read **`attachments`** wrapper on post/comment responses; staging housekeeping sweeps; admin hard delete and account removal enqueue attachment finals cleanup. Tables **`post_image_attachments`**, **`comment_image_attachments`**, **`attachment_staging_registry`**. Config **`[attachment]`** and deploy vars **`ATTACHMENT_*`**. See **`docs/domains/media/post-comment-attachments-design.md`**.
77
109
 
78
- - **HTTP create idempotency (v1):** Optional **`Idempotency-Key`** on **`POST /posts`**, **`POST /comments`**, and **`POST /comments/{comment_id}/replies`**. At most one committed row per **`(author_id, key, operation)`**; replays return **`201`** with empty body and skip mention notifications, attachment attach, and stats-dirty side effects. See **`docs/platform/create-idempotency-design.md`**.
110
+ - **HTTP create idempotency (v1):** Optional **`Idempotency-Key`** on **`POST /posts`**, **`POST /comments`**, and **`POST /comments/{comment_id}/replies`**. At most one committed row per **`(author_id, key, operation)`**; replays return **`201`** with empty body and skip mention notifications, attachment attach, and stats-dirty side effects. See **`docs/design/create-idempotency-design.md`**.
79
111
 
80
112
  - **Request profiling (opt-in):** **`PROFILING_ENABLED`** and **`PROFILING_KEY`** — pyinstrument middleware gated by **`Profiling-Key`** header.
81
113
 
@@ -136,7 +168,7 @@ Run **`uv run cf-alembic`** (or host **`cf-alembic`**) before deploying **2.0.0*
136
168
 
137
169
  ### Documentation
138
170
 
139
- - **`docs/platform/client-error-visibility.md`**, **`docs/platform/create-idempotency-design.md`**, **`docs/deployments/edge-upload-limits.md`**, **`docs/deployments/deploy-playbook.md`**, deletion refactor docs under **`docs/domains/deletion/`**.
171
+ - **`docs/platform/client-error-visibility.md`**, **`docs/design/create-idempotency-design.md`**, **`docs/deployments/edge-upload-limits.md`**, **`docs/deployments/deploy-playbook.md`**, deletion refactor docs under **`docs/domains/deletion/`**.
140
172
 
141
173
  ## [1.8.1] - 2026-06-07
142
174
 
@@ -400,4 +432,7 @@ First **SemVer-stable** release per **`docs/library/package-api.md`**.
400
432
  [2.0.0]: https://github.com/NepNepFFXIV/core-framework/compare/v1.8.1...v2.0.0
401
433
  [2.1.0]: https://github.com/NepNepFFXIV/core-framework/compare/v2.0.0...v2.1.0
402
434
  [2.2.0]: https://github.com/NepNepFFXIV/core-framework/compare/v2.1.0...v2.2.0
403
- [unreleased]: https://github.com/NepNepFFXIV/core-framework/compare/v2.2.0...HEAD
435
+ [2.3.0]: https://github.com/NepNepFFXIV/core-framework/compare/v2.2.0...v2.3.0
436
+ [2.3.1]: https://github.com/NepNepFFXIV/core-framework/compare/v2.3.0...v2.3.1
437
+ [2.3.2]: https://github.com/NepNepFFXIV/core-framework/compare/v2.3.1...v2.3.2
438
+ [unreleased]: https://github.com/NepNepFFXIV/core-framework/compare/v2.3.2...HEAD
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-framework
3
- Version: 2.3.0
3
+ Version: 2.3.2
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
@@ -10,7 +10,6 @@ Requires-Python: >=3.14
10
10
  Requires-Dist: aiofiles>=25.1.0
11
11
  Requires-Dist: alembic>=1.18.4
12
12
  Requires-Dist: arq>=0.28.0
13
- Requires-Dist: async-lru>=2.1.0
14
13
  Requires-Dist: asyncer>=0.0.14
15
14
  Requires-Dist: asyncpg>=0.31.0
16
15
  Requires-Dist: asyncssh>=2.23.0
@@ -62,6 +61,8 @@ make run
62
61
 
63
62
  For **`make test`**, use the Firebase CLI (Auth emulator). Stop DB/Redis: **`docker compose -f docker-compose.dev.yaml down`**.
64
63
 
64
+ **Pre-commit:** `uv sync --dev` installs **pre-commit**. Enable hooks with **`uv run pre-commit install`** (ruff, mdformat, uv-lock, and other checks in **`.pre-commit-config.yaml`**).
65
+
65
66
  ## Hosts
66
67
 
67
68
  In your host app, load **`Settings`** or a **`Settings`** subclass from **`core_framework.core.settings`**, pass it to **`init_app`** from **`core_framework.main`**, then wire host-specific dependencies, exception handlers, and routers.
@@ -23,6 +23,8 @@ make run
23
23
 
24
24
  For **`make test`**, use the Firebase CLI (Auth emulator). Stop DB/Redis: **`docker compose -f docker-compose.dev.yaml down`**.
25
25
 
26
+ **Pre-commit:** `uv sync --dev` installs **pre-commit**. Enable hooks with **`uv run pre-commit install`** (ruff, mdformat, uv-lock, and other checks in **`.pre-commit-config.yaml`**).
27
+
26
28
  ## Hosts
27
29
 
28
30
  In your host app, load **`Settings`** or a **`Settings`** subclass from **`core_framework.core.settings`**, pass it to **`init_app`** from **`core_framework.main`**, then wire host-specific dependencies, exception handlers, and routers.
@@ -0,0 +1,38 @@
1
+ """analytics utm_events for client UTM attribution ingest
2
+
3
+ Revision ID: 585105e1149e
4
+ Revises: 7f2a9c1d4e8b
5
+ Create Date: 2026-07-05 12:00:00.000000
6
+
7
+ """
8
+
9
+ from collections.abc import Sequence
10
+
11
+ from alembic import op
12
+
13
+ revision: str = "585105e1149e"
14
+ down_revision: str | Sequence[str] | None = "7f2a9c1d4e8b"
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 utm_events (
22
+ id bigint generated always as identity primary key,
23
+ created_at timestamptz not null default now(),
24
+ token varchar(256) not null,
25
+ user_id varchar(128),
26
+ utm jsonb not null default '{}'::jsonb,
27
+ request_context jsonb not null default '{}'::jsonb
28
+ );
29
+ """)
30
+ op.execute("""
31
+ create index if not exists idx_utm_events_created_at
32
+ on utm_events (created_at);
33
+ """)
34
+
35
+
36
+ def downgrade() -> None:
37
+ op.execute("drop index if exists idx_utm_events_created_at;")
38
+ op.execute("drop table if exists utm_events;")
@@ -0,0 +1,32 @@
1
+ """add user_signup_events for registration telemetry
2
+
3
+ Revision ID: 44df70a45ba6
4
+ Revises: 9d9611e47ce2
5
+ Create Date: 2026-07-04 12:00:00.000000
6
+
7
+ """
8
+
9
+ from collections.abc import Sequence
10
+
11
+ from alembic import op
12
+
13
+ revision: str = "44df70a45ba6"
14
+ down_revision: str | Sequence[str] | None = "9d9611e47ce2"
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 user_signup_events (
22
+ id bigint generated always as identity primary key,
23
+ user_id varchar(128) not null references users(user_id) on delete cascade,
24
+ created_at timestamptz not null default now(),
25
+ request_context jsonb not null default '{}'::jsonb,
26
+ constraint user_signup_events_user_id_unique unique (user_id)
27
+ );
28
+ """)
29
+
30
+
31
+ def downgrade() -> None:
32
+ op.execute("drop table if exists user_signup_events")
@@ -80,6 +80,7 @@ allowed_headers = [
80
80
  "Content-Type",
81
81
  "Idempotency-Key",
82
82
  "Profiling-Key",
83
+ "Client-Referrer",
83
84
  ]
84
85
 
85
86
  [http_client]
@@ -64,6 +64,7 @@ allowed_headers = [
64
64
  "Content-Type",
65
65
  "Idempotency-Key",
66
66
  "Profiling-Key",
67
+ "Client-Referrer",
67
68
  ]
68
69
 
69
70
  [http_client]
@@ -2,7 +2,7 @@ from datetime import datetime
2
2
  from typing import Annotated, Any
3
3
 
4
4
  from fastapi import Path, Query
5
- from pydantic import BaseModel
5
+ from pydantic import BaseModel, ConfigDict, Field
6
6
 
7
7
  OutboxRowId = Annotated[
8
8
  int,
@@ -34,7 +34,9 @@ class OutboxOldestPendingRow(BaseModel):
34
34
 
35
35
 
36
36
  class OutboxSummaryResponse(BaseModel):
37
- schema: str
37
+ model_config = ConfigDict(populate_by_name=True)
38
+
39
+ producing_schema: str = Field(alias="schema")
38
40
  total_pending: int
39
41
  total_dead: int
40
42
  pending_by_event: list[OutboxEventCountItem]
@@ -43,8 +45,10 @@ class OutboxSummaryResponse(BaseModel):
43
45
 
44
46
 
45
47
  class OutboxDeadRowResponse(BaseModel):
48
+ model_config = ConfigDict(populate_by_name=True)
49
+
46
50
  id: int
47
- schema: str
51
+ producing_schema: str = Field(alias="schema")
48
52
  event_name: str
49
53
  aggregate_type: str
50
54
  aggregate_id: str
@@ -1,18 +1,7 @@
1
- from typing import Annotated
2
-
3
- from pydantic import BaseModel, EmailStr, Field
1
+ from pydantic import BaseModel, EmailStr
4
2
 
5
3
  from core_framework.api.users.shared.schemas import UserID, Username
6
4
 
7
- CountryCode = Annotated[
8
- str,
9
- Field(
10
- description="ISO 3166-1 alpha-2 country code",
11
- pattern="^[A-Z]{2}$",
12
- examples=["US", "GB"],
13
- ),
14
- ]
15
-
16
5
 
17
6
  class CreatedUserResponse(BaseModel):
18
7
  user_id: UserID
@@ -1,17 +1,20 @@
1
1
  from typing import Annotated
2
2
 
3
- from async_lru import alru_cache
4
3
  from fastapi import Depends, Header, Query, Security
5
4
  from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
6
5
  from pydantic import ValidationError
7
6
 
8
7
  import core_framework.domains.auth.dependencies as auth_deps
9
- from core_framework.api.auth.schemas import CountryCode, FirebaseUser
8
+ from core_framework.api.auth.schemas import FirebaseUser
10
9
  from core_framework.api.users.shared.schemas import UserID, parse_user_id
11
10
  from core_framework.application.auth.access_service import get_user_detail
12
11
  from core_framework.application.auth.models import UserDetail
13
12
  from core_framework.application.shared.exceptions import BadRequestException, ForbiddenException, UnauthorizedException
14
- from core_framework.application.shared.user_agent import parse_user_agent
13
+ from core_framework.application.shared.request_context import (
14
+ parse_cf_ipcountry,
15
+ parse_client_referrer,
16
+ parse_user_agent,
17
+ )
15
18
  from core_framework.application.users.admin_service import retrieve_admin_user_ids
16
19
  from core_framework.core.context import user_id
17
20
  from core_framework.domains.auth import VerifiedTokenClaims
@@ -21,11 +24,6 @@ from core_framework.domains.user import UserIdentity
21
24
  bearer_scheme = HTTPBearer(auto_error=False)
22
25
 
23
26
 
24
- @alru_cache(maxsize=5000, ttl=300) # ~10MB per worker, 5 minutes TTL
25
- async def _verify_id_token(token: str) -> VerifiedTokenClaims | None:
26
- return await auth_deps.auth_service.verify_id_token(token=token)
27
-
28
-
29
27
  def _build_firebase_user_from_claims(claims: VerifiedTokenClaims) -> FirebaseUser | None:
30
28
  try:
31
29
  return FirebaseUser(
@@ -54,7 +52,7 @@ async def _get_firebase_user(token: Annotated[str | None, Depends(_get_bearer_to
54
52
  if not token:
55
53
  return None
56
54
 
57
- claims = await _verify_id_token(token)
55
+ claims = await auth_deps.auth_service.verify_id_token(token=token)
58
56
  if claims is None:
59
57
  return None
60
58
 
@@ -106,18 +104,18 @@ async def check_not_banned(user_detail: Annotated[UserDetail, Depends(_get_user_
106
104
  async def _get_request_context(
107
105
  firebase_user: Annotated[FirebaseUser | None, Depends(_get_firebase_user)],
108
106
  user_agent: Annotated[str | None, Header()] = None,
109
- cf_ipcountry: Annotated[CountryCode | None, Header()] = None,
107
+ cf_ipcountry: Annotated[str | None, Header()] = None,
108
+ client_referrer: Annotated[str | None, Header()] = None,
110
109
  ) -> dict[str, str]:
111
110
  metadata: dict[str, str] = {}
112
111
 
113
112
  if firebase_user:
114
113
  metadata["viewer_id"] = firebase_user.user_id
115
114
  metadata["provider"] = firebase_user.sign_in_provider
116
- if cf_ipcountry:
117
- metadata["country_code"] = cf_ipcountry
118
115
 
119
- client_info = parse_user_agent(user_agent=user_agent)
120
- metadata.update(client_info)
116
+ metadata.update(parse_cf_ipcountry(cf_ipcountry=cf_ipcountry))
117
+ metadata.update(parse_client_referrer(client_referrer=client_referrer))
118
+ metadata.update(parse_user_agent(user_agent=user_agent))
121
119
 
122
120
  return {k: v for k, v in metadata.items() if v is not None}
123
121
 
@@ -27,6 +27,31 @@ async def retrieve_analytics_daily_range(
27
27
  }
28
28
 
29
29
 
30
+ async def retrieve_analytics_kind_totals_for_range(
31
+ *,
32
+ subject_type: str,
33
+ activity_type: str,
34
+ from_day: date,
35
+ to_day: date,
36
+ kind: str | None = None,
37
+ ) -> dict[str, Any]:
38
+ """Return per-kind rollup totals summed over an inclusive UTC day range."""
39
+ totals = await analytics_deps.analytics_service.retrieve_daily_fact_kind_totals_for_range(
40
+ subject_type=subject_type,
41
+ activity_type=activity_type,
42
+ from_day=from_day,
43
+ to_day=to_day,
44
+ kind=kind,
45
+ )
46
+ return {
47
+ "subject_type": subject_type,
48
+ "activity_type": activity_type,
49
+ "from_day": from_day,
50
+ "to_day": to_day,
51
+ "items": [{"kind": total.kind, "count": total.count} for total in totals],
52
+ }
53
+
54
+
30
55
  async def retrieve_analytics_daily_day(
31
56
  *,
32
57
  subject_type: str,