core-framework 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. core_framework-0.3.0/.cursor/rules/api-layer.mdc +27 -0
  2. core_framework-0.3.0/.cursor/rules/api-reference-docs.mdc +31 -0
  3. core_framework-0.3.0/.cursor/rules/api-security.mdc +29 -0
  4. core_framework-0.3.0/.cursor/rules/api-validation.mdc +107 -0
  5. core_framework-0.3.0/.cursor/rules/application-layer.mdc +74 -0
  6. core_framework-0.3.0/.cursor/rules/database-triggers.md +207 -0
  7. core_framework-0.3.0/.cursor/rules/domain-caller-context.mdc +44 -0
  8. core_framework-0.3.0/.cursor/rules/domain-imports.mdc +81 -0
  9. core_framework-0.3.0/.cursor/rules/flow-documentation.mdc +325 -0
  10. core_framework-0.3.0/.cursor/rules/implementation-workflow.mdc +68 -0
  11. core_framework-0.3.0/.cursor/rules/integration-test-strategy.mdc +29 -0
  12. core_framework-0.3.0/.cursor/rules/layer-boundaries.mdc +35 -0
  13. core_framework-0.3.0/.cursor/rules/postgres-config-conventions.mdc +41 -0
  14. core_framework-0.3.0/.cursor/rules/repository-read-consistency.mdc +53 -0
  15. core_framework-0.3.0/.cursor/rules/tech-stack.mdc +12 -0
  16. core_framework-0.3.0/.cursor/skills/add-config/SKILL.md +57 -0
  17. core_framework-0.3.0/.cursor/skills/code-review/SKILL.md +92 -0
  18. core_framework-0.3.0/.cursor/skills/recommend-features/SKILL.md +136 -0
  19. core_framework-0.3.0/.dockerignore +39 -0
  20. core_framework-0.3.0/.github/workflows/_deploy.yml +169 -0
  21. core_framework-0.3.0/.github/workflows/dev-ci-cd.yaml +119 -0
  22. core_framework-0.3.0/.github/workflows/manual-deployment.yaml +36 -0
  23. core_framework-0.3.0/.github/workflows/test.yaml +108 -0
  24. core_framework-0.3.0/.gitignore +22 -0
  25. core_framework-0.3.0/.logfire/.gitignore +1 -0
  26. core_framework-0.3.0/.logfire/logfire_credentials.json +6 -0
  27. core_framework-0.3.0/.pre-commit-config.yaml +51 -0
  28. core_framework-0.3.0/.python-version +1 -0
  29. core_framework-0.3.0/CHANGELOG.md +64 -0
  30. core_framework-0.3.0/PKG-INFO +22 -0
  31. core_framework-0.3.0/README.md +18 -0
  32. core_framework-0.3.0/alembic/comment/alembic/README +1 -0
  33. core_framework-0.3.0/alembic/comment/alembic/env.py +72 -0
  34. core_framework-0.3.0/alembic/comment/alembic/script.py.mako +28 -0
  35. core_framework-0.3.0/alembic/comment/alembic/versions/30334fd1347b_init.py +59 -0
  36. core_framework-0.3.0/alembic/comment/alembic/versions/a2b3c4d5e6f7_improve_comment_indexes.py +54 -0
  37. core_framework-0.3.0/alembic/comment/alembic/versions/bcc8e00cfc8b_add_extra_tables.py +64 -0
  38. core_framework-0.3.0/alembic/comment/alembic/versions/d1e2f3a4b5c6_add_comment_stats_dirty_table.py +29 -0
  39. core_framework-0.3.0/alembic/comment/alembic/versions/e3f4a5b6c7d8_cascade_delete_comment_descendants.py +49 -0
  40. core_framework-0.3.0/alembic/comment/alembic/versions/f7e6d5c4b3a2_comments_path_to_ltree.py +60 -0
  41. core_framework-0.3.0/alembic/comment/alembic.ini +52 -0
  42. core_framework-0.3.0/alembic/extension/alembic/README +1 -0
  43. core_framework-0.3.0/alembic/extension/alembic/env.py +98 -0
  44. core_framework-0.3.0/alembic/extension/alembic/script.py.mako +28 -0
  45. core_framework-0.3.0/alembic/extension/alembic/versions/0389226049cb_add_pg_trgm_extension.py +25 -0
  46. core_framework-0.3.0/alembic/extension/alembic/versions/5dc58b016cf5_add_citext_extension.py +25 -0
  47. core_framework-0.3.0/alembic/extension/alembic/versions/b0ba0d8a284e_add_pg_stat_statements_extension.py +25 -0
  48. core_framework-0.3.0/alembic/extension/alembic/versions/c9d0e1f2a3b4_add_ltree_extension.py +25 -0
  49. core_framework-0.3.0/alembic/extension/alembic.ini +147 -0
  50. core_framework-0.3.0/alembic/moderation/alembic/README +1 -0
  51. core_framework-0.3.0/alembic/moderation/alembic/env.py +98 -0
  52. core_framework-0.3.0/alembic/moderation/alembic/script.py.mako +28 -0
  53. core_framework-0.3.0/alembic/moderation/alembic/versions/085ba9021850_add_category_to_user_restrictions.py +93 -0
  54. core_framework-0.3.0/alembic/moderation/alembic/versions/5f9e4fc14a41_create_moderation_appeals_table.py +69 -0
  55. core_framework-0.3.0/alembic/moderation/alembic/versions/63e37381e73b_add_user_reports_table.py +33 -0
  56. core_framework-0.3.0/alembic/moderation/alembic/versions/6a2ae31b7ac6_add_moderation_actions_table.py +34 -0
  57. core_framework-0.3.0/alembic/moderation/alembic/versions/716aa1735c03_improve_indexes.py +36 -0
  58. core_framework-0.3.0/alembic/moderation/alembic/versions/7d243ddbfde1_add_post_reports_table.py +35 -0
  59. core_framework-0.3.0/alembic/moderation/alembic/versions/8fba1f72dd46_add_indexes.py +64 -0
  60. core_framework-0.3.0/alembic/moderation/alembic/versions/95cc35a51984_update_restriction_history.py +91 -0
  61. core_framework-0.3.0/alembic/moderation/alembic/versions/9ad79d0af730_add_unique_constraint_user_reports_.py +28 -0
  62. core_framework-0.3.0/alembic/moderation/alembic/versions/a5e569f5df1a_create_user_restrictions_table.py +38 -0
  63. core_framework-0.3.0/alembic/moderation/alembic/versions/b2c3d4e5f6a7_add_indexes.py +42 -0
  64. core_framework-0.3.0/alembic/moderation/alembic/versions/c3d4e5f6a7b8_improve_report_indexes.py +48 -0
  65. core_framework-0.3.0/alembic/moderation/alembic/versions/d4af74643ff5_add_internal_notes_table.py +38 -0
  66. core_framework-0.3.0/alembic/moderation/alembic/versions/db20f2fb7390_add_comment_reports_table.py +35 -0
  67. core_framework-0.3.0/alembic/moderation/alembic/versions/e66226952ea6_add_report_category_to_user_reports_.py +54 -0
  68. core_framework-0.3.0/alembic/moderation/alembic/versions/f5e8cb275c30_enforce_1_pending_appeal.py +29 -0
  69. core_framework-0.3.0/alembic/moderation/alembic/versions/fe1faad2832d_create_restriction_history_table.py +69 -0
  70. core_framework-0.3.0/alembic/moderation/alembic.ini +147 -0
  71. core_framework-0.3.0/alembic/post/alembic/README +1 -0
  72. core_framework-0.3.0/alembic/post/alembic/env.py +97 -0
  73. core_framework-0.3.0/alembic/post/alembic/script.py.mako +28 -0
  74. core_framework-0.3.0/alembic/post/alembic/versions/51542673f5c8_add_tables_for_muted_banned_users.py +41 -0
  75. core_framework-0.3.0/alembic/post/alembic/versions/5beeeae40a4a_add_post_views_table.py +45 -0
  76. core_framework-0.3.0/alembic/post/alembic/versions/620971509a8b_init.py +55 -0
  77. core_framework-0.3.0/alembic/post/alembic/versions/a1b2c3d4e5f6_add_indexes.py +44 -0
  78. core_framework-0.3.0/alembic/post/alembic/versions/c1d2e3f4a5b6_add_post_hashtags_table.py +36 -0
  79. core_framework-0.3.0/alembic/post/alembic/versions/e56723f2afff_add_post_stats_table.py +39 -0
  80. core_framework-0.3.0/alembic/post/alembic/versions/fbc723ac58cc_add_post_likes_table.py +32 -0
  81. core_framework-0.3.0/alembic/post/alembic.ini +149 -0
  82. core_framework-0.3.0/alembic/user/alembic/README +1 -0
  83. core_framework-0.3.0/alembic/user/alembic/env.py +98 -0
  84. core_framework-0.3.0/alembic/user/alembic/script.py.mako +28 -0
  85. core_framework-0.3.0/alembic/user/alembic/versions/1a8bb99726ed_remove_avatar_id_from_users.py +81 -0
  86. core_framework-0.3.0/alembic/user/alembic/versions/2ccacf455941_improve_indexes.py +34 -0
  87. core_framework-0.3.0/alembic/user/alembic/versions/47f47ce2110e_create_user_deletions_table.py +31 -0
  88. core_framework-0.3.0/alembic/user/alembic/versions/5976db3f0175_drop_user_states.py +26 -0
  89. core_framework-0.3.0/alembic/user/alembic/versions/62417002cf32_add_indexes.py +46 -0
  90. core_framework-0.3.0/alembic/user/alembic/versions/6f7ccf3c226b_refactor_user_login_events.py +66 -0
  91. core_framework-0.3.0/alembic/user/alembic/versions/73432817015b_add_user_preferences_table.py +33 -0
  92. core_framework-0.3.0/alembic/user/alembic/versions/765bc01a7a59_create_user_blocks_table.py +33 -0
  93. core_framework-0.3.0/alembic/user/alembic/versions/7a56631f9927_create_user_login_events_table.py +49 -0
  94. core_framework-0.3.0/alembic/user/alembic/versions/831611e589bc_create_user_state.py +31 -0
  95. core_framework-0.3.0/alembic/user/alembic/versions/83c98ab2a779_add_user_profiles_table.py +88 -0
  96. core_framework-0.3.0/alembic/user/alembic/versions/8a94362cad6d_create_user_role.py +31 -0
  97. core_framework-0.3.0/alembic/user/alembic/versions/94b973923895_add_user_change_history_table.py +97 -0
  98. core_framework-0.3.0/alembic/user/alembic/versions/cbc0f4efe84f_add_avatar_id_column_to_users_table.py +31 -0
  99. core_framework-0.3.0/alembic/user/alembic/versions/d8b98ac6b073_add_index_for_get_admin_user_ids_query.py +29 -0
  100. core_framework-0.3.0/alembic/user/alembic/versions/ddb70cc09d16_create_user_states_table.py +34 -0
  101. core_framework-0.3.0/alembic/user/alembic/versions/f9ba10815ecd_add_users_table.py +33 -0
  102. core_framework-0.3.0/alembic/user/alembic.ini +147 -0
  103. core_framework-0.3.0/config.toml +80 -0
  104. core_framework-0.3.0/config.toml.template +73 -0
  105. core_framework-0.3.0/core_framework/__init__.py +0 -0
  106. core_framework-0.3.0/core_framework/api/__init__.py +0 -0
  107. core_framework-0.3.0/core_framework/api/admin/__init__.py +0 -0
  108. core_framework-0.3.0/core_framework/api/admin/comments/router.py +69 -0
  109. core_framework-0.3.0/core_framework/api/admin/comments/schemas.py +53 -0
  110. core_framework-0.3.0/core_framework/api/admin/moderation/__init__.py +0 -0
  111. core_framework-0.3.0/core_framework/api/admin/moderation/router.py +205 -0
  112. core_framework-0.3.0/core_framework/api/admin/moderation/schemas.py +110 -0
  113. core_framework-0.3.0/core_framework/api/admin/posts/router.py +62 -0
  114. core_framework-0.3.0/core_framework/api/admin/posts/schemas.py +29 -0
  115. core_framework-0.3.0/core_framework/api/admin/router.py +17 -0
  116. core_framework-0.3.0/core_framework/api/admin/users/__init__.py +0 -0
  117. core_framework-0.3.0/core_framework/api/admin/users/router.py +181 -0
  118. core_framework-0.3.0/core_framework/api/admin/users/schemas.py +137 -0
  119. core_framework-0.3.0/core_framework/api/auth/__init__.py +0 -0
  120. core_framework-0.3.0/core_framework/api/auth/router.py +21 -0
  121. core_framework-0.3.0/core_framework/api/auth/schemas.py +28 -0
  122. core_framework-0.3.0/core_framework/api/comments/authenticated/router.py +126 -0
  123. core_framework-0.3.0/core_framework/api/comments/authenticated/schemas.py +27 -0
  124. core_framework-0.3.0/core_framework/api/comments/public/router.py +103 -0
  125. core_framework-0.3.0/core_framework/api/comments/public/schemas.py +36 -0
  126. core_framework-0.3.0/core_framework/api/comments/router.py +9 -0
  127. core_framework-0.3.0/core_framework/api/comments/schemas.py +17 -0
  128. core_framework-0.3.0/core_framework/api/dependencies.py +168 -0
  129. core_framework-0.3.0/core_framework/api/events/router.py +39 -0
  130. core_framework-0.3.0/core_framework/api/events/schemas.py +20 -0
  131. core_framework-0.3.0/core_framework/api/posts/authenticated/router.py +83 -0
  132. core_framework-0.3.0/core_framework/api/posts/authenticated/schemas.py +37 -0
  133. core_framework-0.3.0/core_framework/api/posts/public/router.py +100 -0
  134. core_framework-0.3.0/core_framework/api/posts/public/schemas.py +39 -0
  135. core_framework-0.3.0/core_framework/api/posts/router.py +9 -0
  136. core_framework-0.3.0/core_framework/api/posts/schemas.py +39 -0
  137. core_framework-0.3.0/core_framework/api/router.py +19 -0
  138. core_framework-0.3.0/core_framework/api/schemas.py +9 -0
  139. core_framework-0.3.0/core_framework/api/system/__init__.py +0 -0
  140. core_framework-0.3.0/core_framework/api/system/router.py +108 -0
  141. core_framework-0.3.0/core_framework/api/users/__init__.py +0 -0
  142. core_framework-0.3.0/core_framework/api/users/authenticated/__init__.py +0 -0
  143. core_framework-0.3.0/core_framework/api/users/authenticated/router.py +244 -0
  144. core_framework-0.3.0/core_framework/api/users/authenticated/schemas.py +81 -0
  145. core_framework-0.3.0/core_framework/api/users/public/__init__.py +0 -0
  146. core_framework-0.3.0/core_framework/api/users/public/router.py +25 -0
  147. core_framework-0.3.0/core_framework/api/users/public/schemas.py +7 -0
  148. core_framework-0.3.0/core_framework/api/users/router.py +9 -0
  149. core_framework-0.3.0/core_framework/api/users/shared/schemas.py +174 -0
  150. core_framework-0.3.0/core_framework/application/__init__.py +0 -0
  151. core_framework-0.3.0/core_framework/application/auth/__init__.py +0 -0
  152. core_framework-0.3.0/core_framework/application/auth/access_service.py +26 -0
  153. core_framework-0.3.0/core_framework/application/auth/auth_service.py +10 -0
  154. core_framework-0.3.0/core_framework/application/auth/models.py +10 -0
  155. core_framework-0.3.0/core_framework/application/bootstrap.py +19 -0
  156. core_framework-0.3.0/core_framework/application/comments/admin_service.py +236 -0
  157. core_framework-0.3.0/core_framework/application/comments/aggregation_service.py +28 -0
  158. core_framework-0.3.0/core_framework/application/comments/authenticated_service.py +89 -0
  159. core_framework-0.3.0/core_framework/application/comments/public_service.py +218 -0
  160. core_framework-0.3.0/core_framework/application/events/README.md +26 -0
  161. core_framework-0.3.0/core_framework/application/events/event_service.py +51 -0
  162. core_framework-0.3.0/core_framework/application/events/event_token.py +46 -0
  163. core_framework-0.3.0/core_framework/application/events/models.py +9 -0
  164. core_framework-0.3.0/core_framework/application/moderation/__init__.py +0 -0
  165. core_framework-0.3.0/core_framework/application/moderation/appeal_service.py +98 -0
  166. core_framework-0.3.0/core_framework/application/moderation/moderator_service.py +46 -0
  167. core_framework-0.3.0/core_framework/application/moderation/report_service.py +180 -0
  168. core_framework-0.3.0/core_framework/application/moderation/scheduled_service.py +5 -0
  169. core_framework-0.3.0/core_framework/application/moderation/user_service.py +180 -0
  170. core_framework-0.3.0/core_framework/application/posts/admin_service.py +104 -0
  171. core_framework-0.3.0/core_framework/application/posts/aggregation_service.py +28 -0
  172. core_framework-0.3.0/core_framework/application/posts/authenticated_service.py +72 -0
  173. core_framework-0.3.0/core_framework/application/posts/public_service.py +197 -0
  174. core_framework-0.3.0/core_framework/application/shared/__init__.py +0 -0
  175. core_framework-0.3.0/core_framework/application/shared/enums.py +16 -0
  176. core_framework-0.3.0/core_framework/application/shared/exceptions.py +16 -0
  177. core_framework-0.3.0/core_framework/application/shared/user_agent.py +24 -0
  178. core_framework-0.3.0/core_framework/application/users/__init__.py +0 -0
  179. core_framework-0.3.0/core_framework/application/users/admin_service.py +298 -0
  180. core_framework-0.3.0/core_framework/application/users/authenticated_service.py +179 -0
  181. core_framework-0.3.0/core_framework/application/users/public_service.py +7 -0
  182. core_framework-0.3.0/core_framework/application/users/scheduled_service.py +5 -0
  183. core_framework-0.3.0/core_framework/bundled_alembic.py +57 -0
  184. core_framework-0.3.0/core_framework/core/__init__.py +37 -0
  185. core_framework-0.3.0/core_framework/core/cache.py +234 -0
  186. core_framework-0.3.0/core_framework/core/context.py +14 -0
  187. core_framework-0.3.0/core_framework/core/database.py +111 -0
  188. core_framework-0.3.0/core_framework/core/exception_handlers/__init__.py +3 -0
  189. core_framework-0.3.0/core_framework/core/exception_handlers/comment.py +99 -0
  190. core_framework-0.3.0/core_framework/core/exception_handlers/common.py +5 -0
  191. core_framework-0.3.0/core_framework/core/exception_handlers/moderation.py +104 -0
  192. core_framework-0.3.0/core_framework/core/exception_handlers/post.py +54 -0
  193. core_framework-0.3.0/core_framework/core/exception_handlers/setup.py +80 -0
  194. core_framework-0.3.0/core_framework/core/exception_handlers/user.py +72 -0
  195. core_framework-0.3.0/core_framework/core/http_client.py +64 -0
  196. core_framework-0.3.0/core_framework/core/logging.py +99 -0
  197. core_framework-0.3.0/core_framework/core/middleware.py +64 -0
  198. core_framework-0.3.0/core_framework/core/observability.py +36 -0
  199. core_framework-0.3.0/core_framework/core/pagination.py +203 -0
  200. core_framework-0.3.0/core_framework/core/redis.py +135 -0
  201. core_framework-0.3.0/core_framework/core/runtime.py +66 -0
  202. core_framework-0.3.0/core_framework/core/settings.py +189 -0
  203. core_framework-0.3.0/core_framework/domains/__init__.py +0 -0
  204. core_framework-0.3.0/core_framework/domains/comment/README.md +243 -0
  205. core_framework-0.3.0/core_framework/domains/comment/__init__.py +25 -0
  206. core_framework-0.3.0/core_framework/domains/comment/constants.py +3 -0
  207. core_framework-0.3.0/core_framework/domains/comment/dependencies.py +29 -0
  208. core_framework-0.3.0/core_framework/domains/comment/enums.py +11 -0
  209. core_framework-0.3.0/core_framework/domains/comment/exceptions.py +31 -0
  210. core_framework-0.3.0/core_framework/domains/comment/models.py +54 -0
  211. core_framework-0.3.0/core_framework/domains/comment/repository.py +947 -0
  212. core_framework-0.3.0/core_framework/domains/comment/service.py +259 -0
  213. core_framework-0.3.0/core_framework/domains/moderation/README.md +138 -0
  214. core_framework-0.3.0/core_framework/domains/moderation/__init__.py +47 -0
  215. core_framework-0.3.0/core_framework/domains/moderation/dependencies.py +29 -0
  216. core_framework-0.3.0/core_framework/domains/moderation/enums.py +62 -0
  217. core_framework-0.3.0/core_framework/domains/moderation/exceptions.py +31 -0
  218. core_framework-0.3.0/core_framework/domains/moderation/models.py +94 -0
  219. core_framework-0.3.0/core_framework/domains/moderation/repository.py +828 -0
  220. core_framework-0.3.0/core_framework/domains/moderation/service.py +334 -0
  221. core_framework-0.3.0/core_framework/domains/post/README.md +182 -0
  222. core_framework-0.3.0/core_framework/domains/post/__init__.py +22 -0
  223. core_framework-0.3.0/core_framework/domains/post/constants.py +3 -0
  224. core_framework-0.3.0/core_framework/domains/post/dependencies.py +29 -0
  225. core_framework-0.3.0/core_framework/domains/post/enums.py +18 -0
  226. core_framework-0.3.0/core_framework/domains/post/exceptions.py +21 -0
  227. core_framework-0.3.0/core_framework/domains/post/models.py +53 -0
  228. core_framework-0.3.0/core_framework/domains/post/repository.py +791 -0
  229. core_framework-0.3.0/core_framework/domains/post/service.py +204 -0
  230. core_framework-0.3.0/core_framework/domains/user/README.md +74 -0
  231. core_framework-0.3.0/core_framework/domains/user/__init__.py +39 -0
  232. core_framework-0.3.0/core_framework/domains/user/constants.py +8 -0
  233. core_framework-0.3.0/core_framework/domains/user/dependencies.py +29 -0
  234. core_framework-0.3.0/core_framework/domains/user/enums.py +19 -0
  235. core_framework-0.3.0/core_framework/domains/user/exceptions.py +31 -0
  236. core_framework-0.3.0/core_framework/domains/user/models.py +124 -0
  237. core_framework-0.3.0/core_framework/domains/user/repository.py +612 -0
  238. core_framework-0.3.0/core_framework/domains/user/service.py +257 -0
  239. core_framework-0.3.0/core_framework/domains/user/utils.py +182 -0
  240. core_framework-0.3.0/core_framework/main.py +104 -0
  241. core_framework-0.3.0/core_framework/worker/__init__.py +0 -0
  242. core_framework-0.3.0/core_framework/worker/main.py +56 -0
  243. core_framework-0.3.0/core_framework/worker/schedules/__init__.py +35 -0
  244. core_framework-0.3.0/core_framework/worker/schedules/schedule_aggregate_comment_stats.py +32 -0
  245. core_framework-0.3.0/core_framework/worker/schedules/schedule_aggregate_post_view_counts.py +28 -0
  246. core_framework-0.3.0/core_framework/worker/schedules/schedule_expired_account_deletions.py +24 -0
  247. core_framework-0.3.0/core_framework/worker/schedules/schedule_expired_mute_lifts.py +24 -0
  248. core_framework-0.3.0/core_framework/worker/tasks/__init__.py +11 -0
  249. core_framework-0.3.0/core_framework/worker/tasks/process_account_deletion.py +13 -0
  250. core_framework-0.3.0/core_framework/worker/tasks/process_aggregate_comment_stats.py +19 -0
  251. core_framework-0.3.0/core_framework/worker/tasks/process_aggregate_post_stats.py +12 -0
  252. core_framework-0.3.0/core_framework/worker/tasks/process_mute_lift.py +13 -0
  253. core_framework-0.3.0/docker-compose.yml +39 -0
  254. core_framework-0.3.0/dockerfile +55 -0
  255. core_framework-0.3.0/dockerfile.worker +42 -0
  256. core_framework-0.3.0/docs/api.md +160 -0
  257. core_framework-0.3.0/docs/architecture-decisions.md +349 -0
  258. core_framework-0.3.0/docs/architecture.md +115 -0
  259. core_framework-0.3.0/docs/conventions.md +144 -0
  260. core_framework-0.3.0/docs/core-framework-migration.md +298 -0
  261. core_framework-0.3.0/docs/database-triggers.md +112 -0
  262. core_framework-0.3.0/docs/flows/auth/access_control.md +58 -0
  263. core_framework-0.3.0/docs/flows/auth/registration.md +58 -0
  264. core_framework-0.3.0/docs/flows/comments/admin_comments.md +244 -0
  265. core_framework-0.3.0/docs/flows/comments/comment_report.md +117 -0
  266. core_framework-0.3.0/docs/flows/comments/comment_stats_aggregation.md +134 -0
  267. core_framework-0.3.0/docs/flows/comments/create_comment.md +120 -0
  268. core_framework-0.3.0/docs/flows/comments/delete_comment.md +60 -0
  269. core_framework-0.3.0/docs/flows/comments/edit_comment.md +67 -0
  270. core_framework-0.3.0/docs/flows/comments/retrieve_comments.md +214 -0
  271. core_framework-0.3.0/docs/flows/events/events.md +111 -0
  272. core_framework-0.3.0/docs/flows/moderation/appeals.md +215 -0
  273. core_framework-0.3.0/docs/flows/moderation/internal_notes.md +158 -0
  274. core_framework-0.3.0/docs/flows/moderation/moderator_actions.md +69 -0
  275. core_framework-0.3.0/docs/flows/moderation/reports.md +183 -0
  276. core_framework-0.3.0/docs/flows/moderation/restrictions.md +207 -0
  277. core_framework-0.3.0/docs/flows/posts/admin_posts.md +246 -0
  278. core_framework-0.3.0/docs/flows/posts/author_context.md +75 -0
  279. core_framework-0.3.0/docs/flows/posts/hashtag_discovery.md +56 -0
  280. core_framework-0.3.0/docs/flows/posts/post_like.md +94 -0
  281. core_framework-0.3.0/docs/flows/posts/post_stats_aggregation.md +63 -0
  282. core_framework-0.3.0/docs/flows/users/account.md +50 -0
  283. core_framework-0.3.0/docs/flows/users/account_deletion.md +108 -0
  284. core_framework-0.3.0/docs/flows/users/blocks.md +115 -0
  285. core_framework-0.3.0/docs/flows/users/change_history.md +131 -0
  286. core_framework-0.3.0/docs/flows/users/check_username_exists.md +56 -0
  287. core_framework-0.3.0/docs/flows/users/preferences.md +87 -0
  288. core_framework-0.3.0/docs/flows/users/profile.md +90 -0
  289. core_framework-0.3.0/docs/flows/users/user_removal.md +88 -0
  290. core_framework-0.3.0/docs/package-api.md +100 -0
  291. core_framework-0.3.0/makefile +54 -0
  292. core_framework-0.3.0/pyproject.toml +80 -0
  293. core_framework-0.3.0/tests/__init__.py +0 -0
  294. core_framework-0.3.0/tests/conftest.py +268 -0
  295. core_framework-0.3.0/tests/fixtures/__init__.py +0 -0
  296. core_framework-0.3.0/tests/fixtures/auth.py +193 -0
  297. core_framework-0.3.0/tests/integration/__init__.py +0 -0
  298. core_framework-0.3.0/tests/integration/api/__init__.py +0 -0
  299. core_framework-0.3.0/tests/integration/api/admin/__init__.py +0 -0
  300. core_framework-0.3.0/tests/integration/api/admin/comments/__init__.py +0 -0
  301. core_framework-0.3.0/tests/integration/api/admin/comments/router_test.py +700 -0
  302. core_framework-0.3.0/tests/integration/api/admin/moderation/__init__.py +0 -0
  303. core_framework-0.3.0/tests/integration/api/admin/moderation/router_test.py +2498 -0
  304. core_framework-0.3.0/tests/integration/api/admin/posts/__init__.py +0 -0
  305. core_framework-0.3.0/tests/integration/api/admin/posts/router_test.py +585 -0
  306. core_framework-0.3.0/tests/integration/api/admin/users/__init__.py +0 -0
  307. core_framework-0.3.0/tests/integration/api/admin/users/router_test.py +1738 -0
  308. core_framework-0.3.0/tests/integration/api/auth/__init__.py +0 -0
  309. core_framework-0.3.0/tests/integration/api/auth/router_test.py +52 -0
  310. core_framework-0.3.0/tests/integration/api/comments/__init__.py +0 -0
  311. core_framework-0.3.0/tests/integration/api/comments/authenticated/comment_writes_integration_test.py +513 -0
  312. core_framework-0.3.0/tests/integration/api/comments/public/__init__.py +0 -0
  313. core_framework-0.3.0/tests/integration/api/comments/public/router_test.py +313 -0
  314. core_framework-0.3.0/tests/integration/api/events/router_test.py +201 -0
  315. core_framework-0.3.0/tests/integration/api/posts/__init__.py +0 -0
  316. core_framework-0.3.0/tests/integration/api/posts/authenticated/post_writes_integration_test.py +340 -0
  317. core_framework-0.3.0/tests/integration/api/posts/comment_count_aggregation_test.py +142 -0
  318. core_framework-0.3.0/tests/integration/api/posts/public/__init__.py +0 -0
  319. core_framework-0.3.0/tests/integration/api/posts/public/router_test.py +998 -0
  320. core_framework-0.3.0/tests/integration/api/system/__init__.py +0 -0
  321. core_framework-0.3.0/tests/integration/api/system/router_test.py +52 -0
  322. core_framework-0.3.0/tests/integration/api/users/__init__.py +0 -0
  323. core_framework-0.3.0/tests/integration/api/users/authenticated/__init__.py +0 -0
  324. core_framework-0.3.0/tests/integration/api/users/authenticated/router_test.py +808 -0
  325. core_framework-0.3.0/tests/integration/api/users/public/__init__.py +0 -0
  326. core_framework-0.3.0/tests/integration/api/users/public/router_test.py +49 -0
  327. core_framework-0.3.0/tests/integration/worker/__init__.py +0 -0
  328. core_framework-0.3.0/tests/integration/worker/account_deletion_test.py +277 -0
  329. core_framework-0.3.0/tests/integration/worker/aggregate_comment_stats_test.py +334 -0
  330. core_framework-0.3.0/tests/integration/worker/aggregate_post_view_test.py +160 -0
  331. core_framework-0.3.0/tests/integration/worker/conftest.py +25 -0
  332. core_framework-0.3.0/tests/integration/worker/mute_lift_test.py +151 -0
  333. core_framework-0.3.0/tests/integration/worker/utils_test.py +54 -0
  334. core_framework-0.3.0/tests/unit/__init__.py +0 -0
  335. core_framework-0.3.0/tests/unit/application/comments/__init__.py +0 -0
  336. core_framework-0.3.0/tests/unit/application/events/event_service_test.py +103 -0
  337. core_framework-0.3.0/tests/unit/core/cache_test.py +692 -0
  338. core_framework-0.3.0/tests/unit/core/pagination_test.py +589 -0
  339. core_framework-0.3.0/tests/unit/domains/__init__.py +0 -0
  340. core_framework-0.3.0/tests/unit/domains/comment/__init__.py +0 -0
  341. core_framework-0.3.0/tests/unit/domains/user/service_test.py +182 -0
  342. core_framework-0.3.0/uv.lock +2104 -0
@@ -0,0 +1,27 @@
1
+ ---
2
+ description: API layer should contain HTTP adapters only
3
+ globs:
4
+ - core_framework/api/**/*.py
5
+ ---
6
+
7
+ # API Layer Conventions
8
+
9
+ The API layer is an HTTP adapter, not a business-logic layer.
10
+
11
+ ## Scope
12
+
13
+ - Keep API files focused on routers, schemas, and HTTP dependencies.
14
+ - API code may call application services in `core_framework/application/...`.
15
+ - API code must not contain orchestration shared with workers.
16
+
17
+ ## Router Responsibilities
18
+
19
+ - Routers own HTTP concerns: status codes, `HTTPException`, `response_model`, request parsing.
20
+ - Routers call `validate_*` schema helpers before invoking application services.
21
+ - Routers should remain thin and delegate business decisions to application/domain layers.
22
+
23
+ ## What to Avoid
24
+
25
+ - Do NOT implement reusable business workflows in API modules.
26
+ - Do NOT import domain internals directly; follow domain public API and dependencies rules.
27
+ - Do NOT place worker-only logic (scheduling/task orchestration) in API modules.
@@ -0,0 +1,31 @@
1
+ ---
2
+ description: docs/api.md is a minimal API index only
3
+ globs:
4
+ - docs/api.md
5
+ ---
6
+
7
+ # API Reference (docs/api.md)
8
+
9
+ `docs/api.md` is strictly for **quick viewing** of available APIs. It is an index, not detailed documentation.
10
+
11
+ ## Format
12
+
13
+ - One line per endpoint: `METHOD path # Short description`
14
+ - Group by domain/section (Auth, Users, Posts, etc.)
15
+ - No additional content below the endpoint list
16
+
17
+ ## What to INCLUDE
18
+
19
+ - Endpoint method and path
20
+ - Brief description in the comment (one short phrase)
21
+
22
+ ## What to EXCLUDE
23
+
24
+ - Request/response body formats
25
+ - Header documentation
26
+ - Error codes
27
+ - Links to other docs
28
+ - Any prose or bullet lists
29
+ - Detailed behavior notes
30
+
31
+ For detailed API behavior, create or update flow documentation in `docs/flows/` instead.
@@ -0,0 +1,29 @@
1
+ ---
2
+ description: Public and authenticated routes must not reveal user existence; only admin routes may return 404 for user not found
3
+ globs:
4
+ - core_framework/api/**/router.py
5
+ - core_framework/application/**/*_service.py
6
+ ---
7
+
8
+ # API Security: User Existence
9
+
10
+ **User existence visibility**: Public and authenticated (non-admin) endpoints must NOT reveal whether a `user_id` exists. This prevents user enumeration attacks.
11
+ Apply the rule by **response shape**, not HTTP method:
12
+ - **List responses** (`list[...]`, paginated list items): returning an empty list for nonexistent users is acceptable.
13
+ - **Non-list responses** (detail/object/single resource): apply default/non-enumerating behavior for public/authenticated routes and 404 behavior for admin detail routes.
14
+
15
+ - **Public/authenticated non-list routes**: Do NOT return 404 for missing resources tied to user existence. Prefer a safe default payload/value; if no safe default exists, return a success for idempotent operations or a generic error (e.g. 400, 403) that does not disclose existence.
16
+ - **Public/authenticated list routes**: returning empty lists is acceptable.
17
+ - **Admin non-list routes**: Return 404 for missing single-resource lookups/details (user, profile, note, etc.).
18
+ - **Admin list endpoints**: Returning an empty list for missing/nonexistent target users is acceptable.
19
+ - **Admin DELETE endpoints**: Prefer idempotent behavior. Returning 204 when the target is already missing is acceptable.
20
+
21
+ **Examples:**
22
+ - Block non-existent user → 204 (silent success)
23
+ - Unblock non-existent user → 204 (idempotent)
24
+ - Report non-existent user → 204 or generic error, never 404
25
+ - GET `/users/me/profile` with missing profile row → 200 with default profile payload
26
+ - Admin GET /admin/users/{user_id} → 404 when user does not exist ✓
27
+ - Admin profile lookup with missing profile → 404 ✓
28
+ - Admin GET `/admin/users/{user_id}/change-history` for nonexistent user → 200 with `[]` is acceptable
29
+ - Admin DELETE `/admin/users/{user_id}` when already missing → 204 is acceptable
@@ -0,0 +1,107 @@
1
+ ---
2
+ description: API layer must validate all fields that have database constraints
3
+ globs: ["core_framework/api/**/*.py"]
4
+ ---
5
+
6
+ # API Validation Rule
7
+
8
+ ## Principle: Fail Fast at the API Layer
9
+
10
+ Any field that has a database constraint (CHECK, NOT NULL, UNIQUE, foreign key, etc.) MUST be validated at the API layer before reaching the database.
11
+
12
+ ## Why
13
+
14
+ 1. **Better User Experience**: Return clear 422 Validation Error instead of 500 Internal Server Error
15
+ 2. **Clearer Error Messages**: Pydantic validation errors are more user-friendly than database constraint violation errors
16
+ 3. **Fail Fast**: Catch invalid data early in the request lifecycle
17
+ 4. **Better Monitoring**: API validation failures are easier to track than database errors
18
+ 5. **Reduced Database Load**: Invalid requests don't reach the database
19
+
20
+ ## Examples
21
+
22
+ ### ✅ Good: Validate at API Layer
23
+
24
+ Database constraint:
25
+ ```sql
26
+ country_code varchar(2) not null,
27
+ constraint country_code_format check (country_code ~ '^[A-Z]{2}$')
28
+ ```
29
+
30
+ API validation:
31
+ ```python
32
+ import re
33
+ from typing import Annotated
34
+
35
+ from pydantic import BaseModel, Field, field_validator
36
+
37
+ # Using Field with pattern
38
+ class LoginRequest(BaseModel):
39
+ country_code: Annotated[
40
+ str,
41
+ Field(
42
+ default="XX",
43
+ pattern="^[A-Z]{2}$",
44
+ description="ISO 3166-1 alpha-2 country code",
45
+ )
46
+ ]
47
+
48
+ # Or using field_validator for complex validation
49
+ @field_validator("country_code")
50
+ @classmethod
51
+ def validate_country_code(cls, v: str) -> str:
52
+ if not re.match(r"^[A-Z]{2}$", v):
53
+ raise ValueError("country_code must be 2 uppercase letters")
54
+ return v
55
+ ```
56
+
57
+ ### ❌ Bad: No API Validation
58
+
59
+ ```python
60
+ class LoginRequest(BaseModel):
61
+ # This will cause a database constraint violation
62
+ country_code: str = "invalid" # No validation!
63
+ ```
64
+
65
+ ## Common Database Constraints to Validate
66
+
67
+ ### 1. **CHECK Constraints**
68
+ - Length limits: `varchar(50)` → `Field(max_length=50)`
69
+ - Format patterns: `check (email ~ '^[^@]+@[^@]+$')` → `EmailStr` or `Field(pattern="...")`
70
+ - Value ranges: `check (age >= 0)` → `Field(ge=0)`
71
+ - Enum values: `check (status in ('active', 'inactive'))` → Python `Enum`
72
+
73
+ ### 2. **NOT NULL Constraints**
74
+ - Required fields: `not null` → Don't use `| None`, or use `Field(..., required=True)`
75
+
76
+ ### 3. **UNIQUE Constraints**
77
+ - Validate uniqueness where possible (e.g., check username availability before insert)
78
+ - Consider caching frequently checked unique values (like usernames)
79
+
80
+ ### 4. **Foreign Key Constraints**
81
+ - Validate referenced entities exist before insert/update
82
+ - Use proper error messages: "User not found" instead of "Foreign key violation"
83
+
84
+ ### 5. **Length Constraints**
85
+ - String lengths: `varchar(255)` → `Field(max_length=255)`
86
+ - Array sizes: `text[] check (array_length(...) <= 5)` → validate list length
87
+
88
+ ## When NOT to Validate
89
+
90
+ - **Free-form text fields** with no constraints (e.g., `text` columns with no CHECK)
91
+ - **System-generated values** (e.g., timestamps, auto-increment IDs)
92
+ - **Internal fields** not exposed in the API
93
+
94
+ ## Implementation Guidelines
95
+
96
+ 1. **Review migrations** when creating API endpoints to identify all constraints
97
+ 2. **Use Pydantic validators** for complex validation logic
98
+ 3. **Use Field constraints** for simple validations (pattern, min/max, length)
99
+ 4. **Add descriptive error messages** to help API consumers understand requirements
100
+ 5. **Document validation rules** in OpenAPI schema (automatically done by FastAPI/Pydantic)
101
+
102
+ ## Related Files
103
+
104
+ - Database migrations: `alembic/*/alembic/versions/*.py`
105
+ - API schemas: `core_framework/api/*/schemas.py`
106
+ - User shared schemas: `core_framework/api/users/shared/schemas.py`
107
+ - Auth schemas: `core_framework/api/auth/schemas.py`
@@ -0,0 +1,74 @@
1
+ ---
2
+ description: Application services must be transport-agnostic and return plain Python types
3
+ globs:
4
+ - core_framework/application/**/*_service.py
5
+ ---
6
+
7
+ # Application Layer Service Conventions
8
+
9
+ Services in the application layer (`core_framework/application/**/*_service.py`) are used by both HTTP routers and workers. They must remain transport-agnostic.
10
+
11
+ ## No HTTP Handling
12
+
13
+ Services must NOT handle HTTP concerns. They are shared by both API and worker code.
14
+
15
+ - **Do NOT** raise `HTTPException` or any FastAPI/Starlette HTTP types
16
+ - **Do NOT** import from `fastapi` for HTTP-specific logic (status codes, responses)
17
+ - **Do NOT** assume the caller is an HTTP request
18
+
19
+ **Signal "not found"** by returning `None` or `Optional`, not by raising HTTP exceptions. How callers map "not found" depends on response shape and endpoint type:
20
+ - **Admin non-list routes (detail/single-resource)**: convert missing resources to 404 (typically via `UserNotFoundException`).
21
+ - **Admin list routes**: returning an empty list for nonexistent target users is acceptable.
22
+ - **Admin DELETE routes**: idempotent 204 for already-missing resources is acceptable.
23
+ - **Public/authenticated non-list routes**: return a safe default or non-enumerating response, not 404.
24
+ - **Public/authenticated list routes**: returning an empty list is acceptable.
25
+ - **Workers**: handle `None` according to their own logic.
26
+
27
+ **Admin routes only**: For user lookups, admin services may raise `UserNotFoundException` (from `application.shared.exceptions`). The global exception handler converts it to 404. Do NOT use this in public or authenticated (non-admin) routes—see api-security rule.
28
+
29
+ ```python
30
+ # ✅ Admin service: raise UserNotFoundException for user not found
31
+ async def retrieve_user_detail(*, user_id: UserID) -> dict[str, Any]:
32
+ if user_data is None:
33
+ raise UserNotFoundException()
34
+ return {"identity": ..., "moderation": ...}
35
+
36
+ # ✅ Other routes: return None when resource not found
37
+ async def get_some_resource(*, resource_id: str) -> dict | None:
38
+ if not found:
39
+ return None
40
+ return {...}
41
+
42
+ # ❌ WRONG: HTTP in service layer
43
+ async def retrieve_user_detail(*, user_id: UserID) -> dict[str, Any]:
44
+ if not found:
45
+ raise HTTPException(status_code=404, detail="User not found") # ❌
46
+ ```
47
+
48
+ ## No Pydantic Models as Return Types
49
+
50
+ Services must return plain Python types—not Pydantic models. Routers use `response_model`; FastAPI converts the return value to the Pydantic model automatically.
51
+
52
+ - **Do NOT** return Pydantic `BaseModel` subclasses from service functions
53
+ - **Return** `dict`, `list[dict]`, dataclasses, or other JSON-serializable types
54
+ - **Routers** declare `response_model`; FastAPI validates and serializes the service return value
55
+
56
+ ```python
57
+ # ✅ CORRECT: Return dict or dataclass
58
+ async def retrieve_users(...) -> list[dict[str, Any]]:
59
+ ...
60
+
61
+ async def get_profile(...) -> Profile: # dataclass
62
+ ...
63
+ ```
64
+
65
+ ## Keyword-only arguments
66
+
67
+ - Application service functions (and private helpers in `*_service.py` modules) must use **keyword-only** parameters after a `*` separator, matching the domain layer convention.
68
+ - Exception: zero-argument functions (e.g. `retrieve_admin_user_ids()`).
69
+
70
+ ## Validation in Schemas, Not Services
71
+
72
+ - Input validation (`validate_user_id`, `validate_report_id`, etc.) belongs in schemas
73
+ - Services do NOT raise `RequestValidationError` or import from `fastapi.exceptions`
74
+ - Routers call `validate_*` from schemas before invoking services
@@ -0,0 +1,207 @@
1
+ # Database Triggers Rule
2
+
3
+ ## Core Principle
4
+
5
+ **Database triggers MUST ONLY be used for audit/history tracking. Business logic MUST NEVER be implemented in triggers.**
6
+
7
+ ## When to Use Triggers
8
+
9
+ ✅ **ACCEPTABLE USE CASES:**
10
+
11
+ 1. **Audit Logging**
12
+
13
+ - Tracking who changed what and when
14
+ - Recording old and new values for compliance
15
+ - Capturing actor information (who made the change)
16
+
17
+ 1. **Change History**
18
+
19
+ - Building immutable audit trails
20
+ - Tracking modifications for regulatory compliance
21
+ - Recording metadata about changes
22
+
23
+ 1. **Read-Only Operations**
24
+
25
+ - Operations that don't affect business outcomes
26
+ - Recording timestamps of state changes
27
+ - Logging events for analytics (non-critical)
28
+
29
+ ## When NOT to Use Triggers
30
+
31
+ ❌ **NEVER USE TRIGGERS FOR:**
32
+
33
+ 1. **Business Logic**
34
+
35
+ - Validation rules (e.g., "users can only change username once per week")
36
+ - State transitions (e.g., "muted users cannot be warned")
37
+ - Conditional workflows (e.g., "send notification if X happens")
38
+ - Data transformations (e.g., "normalize phone numbers on insert")
39
+
40
+ 1. **Side Effects**
41
+
42
+ - Sending notifications
43
+ - Calling external APIs
44
+ - Updating related records based on business rules
45
+ - Enforcing complex constraints
46
+
47
+ 1. **Calculations**
48
+
49
+ - Computing derived values
50
+ - Aggregating data
51
+ - Updating summary tables
52
+
53
+ ## Why This Rule Exists
54
+
55
+ 1. **Testability**: Triggers are difficult to test in isolation and require database setup
56
+ 1. **Visibility**: Logic hidden in triggers is invisible during code review
57
+ 1. **Debugging**: Trigger failures are harder to diagnose than application errors
58
+ 1. **Maintainability**: Changing triggers requires database migrations and coordination
59
+ 1. **Performance**: Triggers add overhead to every write operation, affecting all callers
60
+ 1. **Complexity**: Trigger interactions can create subtle bugs and unexpected behavior
61
+
62
+ ## Examples
63
+
64
+ ### ✅ Good: Audit Logging
65
+
66
+ ```sql
67
+ -- ACCEPTABLE: Audit trail for username changes
68
+ create or replace function log_user_update_change()
69
+ returns trigger as $$
70
+ begin
71
+ if new.username is distinct from old.username then
72
+ insert into "user".user_change_history (
73
+ user_id, actor_id, entity_type, field, old_value, new_value
74
+ )
75
+ values (
76
+ new.user_id,
77
+ current_setting('app.actor_id', true),
78
+ 'users',
79
+ 'username',
80
+ old.username,
81
+ new.username
82
+ );
83
+ end if;
84
+ return new;
85
+ end;
86
+ $$ language plpgsql;
87
+ ```
88
+
89
+ **Why this is acceptable:**
90
+
91
+ - Records historical information without affecting business logic
92
+ - Doesn't prevent or modify the original operation
93
+ - Fails silently if logging fails (doesn't block the transaction)
94
+ - Pure audit trail - no business decisions are made
95
+
96
+ ### ❌ Bad: Business Logic in Trigger
97
+
98
+ ```sql
99
+ -- DON'T DO THIS: Username change cooldown validation
100
+ create or replace function enforce_username_cooldown()
101
+ returns trigger as $$
102
+ begin
103
+ if new.username != old.username then
104
+ if exists (
105
+ select 1 from user_change_history
106
+ where user_id = new.user_id
107
+ and field = 'username'
108
+ and created_at > now() - interval '7 days'
109
+ ) then
110
+ raise exception 'Username can only be changed once per week';
111
+ end if;
112
+ end if;
113
+ return new;
114
+ end;
115
+ $$ language plpgsql;
116
+ ```
117
+
118
+ **Why this is bad:**
119
+
120
+ - Implements business rule (cooldown period)
121
+ - Prevents operation from completing
122
+ - Validation should be in service layer
123
+ - Can't be easily tested or modified
124
+ - Error message isn't localized
125
+ - Makes assumptions about business rules
126
+
127
+ **Correct approach:**
128
+
129
+ ```python
130
+ # In service layer
131
+ async def change_profile(
132
+ self,
133
+ *,
134
+ actor_id: str,
135
+ user_id: str,
136
+ validated_update_request: dict[str, Any],
137
+ ) -> None:
138
+ if "username" in validated_update_request:
139
+ recent_changes = await self.repository.select_recent_username_changes(
140
+ user_id=user_id, since=datetime.now(timezone.utc) - timedelta(days=7)
141
+ )
142
+ if recent_changes:
143
+ raise UsernameCooldownException()
144
+
145
+ await self.repository.update_profile(
146
+ user_id=user_id,
147
+ validated_update_request=validated_update_request,
148
+ actor_id=actor_id,
149
+ )
150
+ ```
151
+
152
+ ### ❌ Bad: Automatic State Transitions
153
+
154
+ ```sql
155
+ -- DON'T DO THIS: Auto-approve appeals from first-time offenders
156
+ create or replace function auto_approve_first_offense()
157
+ returns trigger as $$
158
+ begin
159
+ if tg_op = 'INSERT' then
160
+ if (select count(*) from restriction_history where user_id = new.user_id) = 1 then
161
+ update moderation_appeals
162
+ set status = 'approved', decided_at = now()
163
+ where user_id = new.user_id and status = 'pending';
164
+ end if;
165
+ end if;
166
+ return new;
167
+ end;
168
+ $$ language plpgsql;
169
+ ```
170
+
171
+ **Why this is bad:**
172
+
173
+ - Implements business policy (auto-approval rules)
174
+ - Makes decisions that should be explicit in application code
175
+ - Side effect (updating appeals table) is invisible to callers
176
+ - Business rule changes require database migration
177
+ - Can't be A/B tested or feature-flagged
178
+
179
+ ## When in Doubt
180
+
181
+ **Ask yourself:**
182
+
183
+ 1. "Does this trigger make a business decision?" → If yes, move to application layer
184
+ 1. "Would I need to change this if business requirements change?" → If yes, move to application layer
185
+ 1. "Does this trigger prevent or modify the operation?" → If yes, move to application layer
186
+ 1. "Is this purely recording what happened?" → If yes, trigger is acceptable
187
+
188
+ ## Enforcement
189
+
190
+ If an AI assistant (like me) suggests using a trigger for business logic, I should:
191
+
192
+ 1. **Stop and remind you** of this rule
193
+ 1. **Suggest the application-layer alternative**
194
+ 1. **Only proceed with trigger** if you explicitly confirm it's for audit/history only
195
+
196
+ If you ask for a trigger for business logic, I should:
197
+
198
+ 1. **Flag the violation** of this rule
199
+ 1. **Explain why it's problematic**
200
+ 1. **Propose an application-layer implementation instead**
201
+
202
+ ## Related Documentation
203
+
204
+ - `docs/database-triggers.md` - **Catalog of all triggers** (update when adding new triggers)
205
+ - `docs/conventions.md` - Database Triggers section
206
+ - `docs/architecture-decisions.md` - Triggers Only for Audit/History
207
+ - `docs/flows/users/change_history.md` - Example of proper trigger usage
@@ -0,0 +1,44 @@
1
+ ---
2
+ description: Prevent caller-context leakage in domain layer naming
3
+ globs:
4
+ - core_framework/domains/**/*.py
5
+ - core_framework/domains/**/README.md
6
+ alwaysApply: false
7
+ ---
8
+
9
+ # Domain Caller-Context Boundary
10
+
11
+ Domain layer names must describe domain concepts and data semantics, not who calls them.
12
+
13
+ ## Do Not Encode Caller Context
14
+
15
+ - Avoid role/channel/adapter names in domain symbols: `Admin*`, `Public*`, `Authenticated*`, `Api*`, `Worker*`, `Http*`.
16
+ - Avoid method names like `*_for_admin`, `*_for_public`, `*_for_api`, `*_for_worker`.
17
+ - Avoid transport words in domain interfaces: `request`, `response`, `router`, `endpoint`, `status_code`.
18
+
19
+ ## Allowed Domain Semantics
20
+
21
+ - Domain names may still use role/status/visibility words when they describe the entity or filter itself, not the caller.
22
+ - Examples:
23
+ - `UserRole.ADMIN` ✅
24
+ - `select_admin_user_ids` when it means "users whose role is admin" ✅
25
+ - `PostVisibility.PUBLIC` ✅
26
+
27
+ ## Preferred Naming
28
+
29
+ - Use policy/data-shape naming:
30
+ - `select_posts_unfiltered` ✅
31
+ - `PostWithMetadata` ✅
32
+ - Use constraint-oriented naming for variants:
33
+ - `update_post_status_by_id` ✅
34
+ - `update_post_status_by_id_and_author` ✅
35
+ - `set_post_status_for_author` ✅
36
+ - Prefer naming by data shape or business rule, not persona:
37
+ - `select_post_with_metadata_by_id` ✅
38
+ - `retrieve_user_for_detail` ✅
39
+ - Keep caller-specific naming in API/application layers only.
40
+
41
+ ## Review Checklist
42
+
43
+ - If a domain model or method name implies caller identity, flag it as boundary leakage.
44
+ - Suggest neutral alternatives based on behavior, constraint, or data shape (not caller type).
@@ -0,0 +1,81 @@
1
+ ---
2
+ description: Enforce importing from domain __init__.py in API/application layers
3
+ globs:
4
+ - core_framework/api/**/*.py
5
+ - core_framework/application/**/*.py
6
+ ---
7
+
8
+ # Domain Import Rules
9
+
10
+ When importing from domain layers (`core_framework/domains/*`) into the API/application layers (`core_framework/api/*`, `core_framework/application/*`), you MUST follow these rules:
11
+
12
+ ## ✅ Allowed Imports
13
+
14
+ ### 1. Import from domain `__init__.py` (Public API)
15
+ ```python
16
+ # CORRECT: Import enums, models, exceptions from __init__.py
17
+ from core_framework.domains.moderation import AppealDecision, RestrictionType
18
+ from core_framework.domains.moderation import UserModeration, UserRestriction
19
+ from core_framework.domains.moderation import BaseModerationException, AppealNotFoundException
20
+
21
+ from core_framework.domains.user import UserRole, BlockedUser, Profile
22
+ from core_framework.domains.user import BaseUserException, UserIdConflictException
23
+ ```
24
+
25
+ **Domain exception boundary**: Some domain exceptions (e.g. `DomainUserNotFoundException`) are internal—not exported in `__init__.py` and must not be imported or raised outside their domain. Use `None` or `Optional` return values instead; callers map missing values by endpoint policy and response shape (admin non-list -> 404, list responses may return empty lists, admin DELETE may return idempotent 204, public/authenticated non-list -> default or non-enumerating response).
26
+
27
+ ### 2. Import from `dependencies.py` (Dependency Injection)
28
+ ```python
29
+ # CORRECT: Import services from dependencies
30
+ from core_framework.domains.moderation.dependencies import moderation_service
31
+ from core_framework.domains.user.dependencies import user_service
32
+ ```
33
+
34
+ ## ❌ Prohibited Imports
35
+
36
+ ### DO NOT import directly from internal domain modules
37
+ ```python
38
+ # WRONG: Don't import from internal modules
39
+ from core_framework.domains.moderation.models import UserModeration # ❌
40
+ from core_framework.domains.moderation.enums import AppealDecision # ❌
41
+ from core_framework.domains.moderation.exceptions import AppealNotFoundException # ❌
42
+ from core_framework.domains.moderation.repository import ModerationRepository # ❌
43
+ from core_framework.domains.moderation.service import ModerationService # ❌
44
+
45
+ from core_framework.domains.user.models import BlockedUser # ❌
46
+ from core_framework.domains.user.enums import UserRole # ❌
47
+ from core_framework.domains.user.exceptions import DomainUserNotFoundException # ❌
48
+ from core_framework.domains.user.repository import UserRepository # ❌
49
+ from core_framework.domains.user.service import UserService # ❌
50
+ ```
51
+
52
+ ## Why This Rule Exists
53
+
54
+ 1. **Encapsulation**: The `__init__.py` defines the public API of each domain
55
+ 2. **Maintainability**: Internal refactoring doesn't break the API layer
56
+ 3. **Clear boundaries**: API layer only accesses what the domain explicitly exports
57
+ 4. **Consistency across adapters**: API and application layers follow the same domain import contract
58
+ 5. **Dependency direction**: Prevents tight coupling to internal implementation details
59
+
60
+ ## Available Domain Exports
61
+
62
+ ### Moderation Domain (`from core_framework.domains.moderation import ...`)
63
+ - **Enums**: `RestrictionType`, `AppealDecision`, `ReportType`
64
+ - **Models**: `Report`, `UserModeration`, `UserRestriction`
65
+ - **Exceptions**: `BaseModerationException`, `AppealNotFoundException`, `AppealAlreadyDecidedException`, `SelfReportException`, `ExistingPendingAppealException`, `AppealRequirementException`
66
+ - **Service**: Use `moderation_service` from `dependencies.py`
67
+
68
+ ### User Domain (`from core_framework.domains.user import ...`)
69
+ - **Enums**: `UserRole`
70
+ - **Models**: `CreatedUser`, `BlockedUser`, `Profile`, `UserIdentity`
71
+ - **Exceptions**: `BaseUserException`, `SelfBlockException`, `UserIdConflictException`, `UsernameConflictException`, `UserCreationException`
72
+ - **Service**: Use `user_service` from `dependencies.py`
73
+ - **Internal** (do not import from API layer): `DomainUserNotFoundException` — handled within domain; API uses `None` return values
74
+
75
+ ## How to Fix Violations
76
+
77
+ If you need something that's not exported in `__init__.py`:
78
+
79
+ 1. **Check if it should be public**: If it's needed by the API layer, add it to the domain's `__init__.py`
80
+ 2. **Reconsider the design**: If it's internal implementation, maybe the API layer shouldn't access it directly
81
+ 3. **Use the service**: Most domain logic should be accessed through `{domain}_service` from `dependencies.py`