core-framework 1.2.0__tar.gz → 1.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 (365) hide show
  1. core_framework-1.3.0/.github/workflows/publish-pypi.yml +34 -0
  2. {core_framework-1.2.0 → core_framework-1.3.0}/CHANGELOG.md +17 -1
  3. core_framework-1.3.0/PKG-INFO +115 -0
  4. core_framework-1.3.0/README.md +81 -0
  5. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/firebase.py +8 -1
  6. core_framework-1.3.0/docker-compose.dev.yaml +24 -0
  7. core_framework-1.3.0/docs/todo.md +10 -0
  8. core_framework-1.3.0/firebase_config.example.json +13 -0
  9. {core_framework-1.2.0 → core_framework-1.3.0}/pyproject.toml +1 -1
  10. {core_framework-1.2.0 → core_framework-1.3.0}/uv.lock +1 -1
  11. core_framework-1.2.0/.logfire/.gitignore +0 -1
  12. core_framework-1.2.0/.logfire/logfire_credentials.json +0 -6
  13. core_framework-1.2.0/PKG-INFO +0 -131
  14. core_framework-1.2.0/README.md +0 -97
  15. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/api-layer.mdc +0 -0
  16. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/api-reference-docs.mdc +0 -0
  17. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/api-security.mdc +0 -0
  18. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/api-validation.mdc +0 -0
  19. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/application-layer.mdc +0 -0
  20. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/constants-final.mdc +0 -0
  21. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/database-triggers.md +0 -0
  22. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/domain-caller-context.mdc +0 -0
  23. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/domain-imports.mdc +0 -0
  24. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/domain-input-guards.mdc +0 -0
  25. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/domain-repository-exceptions.mdc +0 -0
  26. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/flow-documentation.mdc +0 -0
  27. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/implementation-workflow.mdc +0 -0
  28. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/integration-test-strategy.mdc +0 -0
  29. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/layer-boundaries.mdc +0 -0
  30. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/no-code-in-docs.mdc +0 -0
  31. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/no-docstrings.mdc +0 -0
  32. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/postgres-config-conventions.mdc +0 -0
  33. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/repository-read-consistency.mdc +0 -0
  34. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/strong-read-opt-in.mdc +0 -0
  35. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/rules/tech-stack.mdc +0 -0
  36. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/skills/add-config/SKILL.md +0 -0
  37. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/skills/add-domain/SKILL.md +0 -0
  38. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/skills/code-review/SKILL.md +0 -0
  39. {core_framework-1.2.0 → core_framework-1.3.0}/.cursor/skills/recommend-features/SKILL.md +0 -0
  40. {core_framework-1.2.0 → core_framework-1.3.0}/.dockerignore +0 -0
  41. {core_framework-1.2.0 → core_framework-1.3.0}/.github/workflows/_deploy.yml +0 -0
  42. {core_framework-1.2.0 → core_framework-1.3.0}/.github/workflows/dev-ci-cd.yaml +0 -0
  43. {core_framework-1.2.0 → core_framework-1.3.0}/.github/workflows/manual-deployment.yaml +0 -0
  44. {core_framework-1.2.0 → core_framework-1.3.0}/.github/workflows/test.yaml +0 -0
  45. {core_framework-1.2.0 → core_framework-1.3.0}/.gitignore +0 -0
  46. {core_framework-1.2.0 → core_framework-1.3.0}/.pre-commit-config.yaml +0 -0
  47. {core_framework-1.2.0 → core_framework-1.3.0}/.python-version +0 -0
  48. {core_framework-1.2.0 → core_framework-1.3.0}/LICENSE +0 -0
  49. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/comment/alembic/README +0 -0
  50. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/comment/alembic/env.py +0 -0
  51. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/comment/alembic/script.py.mako +0 -0
  52. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/comment/alembic/versions/v1_comment_init_baseline.py +0 -0
  53. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/comment/alembic.ini +0 -0
  54. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/extension/alembic/README +0 -0
  55. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/extension/alembic/env.py +0 -0
  56. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/extension/alembic/script.py.mako +0 -0
  57. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/extension/alembic/versions/v1_ext_init_baseline.py +0 -0
  58. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/extension/alembic.ini +0 -0
  59. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/moderation/alembic/README +0 -0
  60. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/moderation/alembic/env.py +0 -0
  61. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/moderation/alembic/script.py.mako +0 -0
  62. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/moderation/alembic/versions/v1_mod_init_baseline.py +0 -0
  63. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/moderation/alembic.ini +0 -0
  64. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/notification/alembic/README +0 -0
  65. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/notification/alembic/env.py +0 -0
  66. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/notification/alembic/script.py.mako +0 -0
  67. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/notification/alembic/versions/v1_notif_init_baseline.py +0 -0
  68. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/notification/alembic.ini +0 -0
  69. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/post/alembic/README +0 -0
  70. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/post/alembic/env.py +0 -0
  71. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/post/alembic/script.py.mako +0 -0
  72. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/post/alembic/versions/v1_post_init_baseline.py +0 -0
  73. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/post/alembic.ini +0 -0
  74. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/user/alembic/README +0 -0
  75. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/user/alembic/env.py +0 -0
  76. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/user/alembic/script.py.mako +0 -0
  77. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/user/alembic/versions/v1_user_init_baseline.py +0 -0
  78. {core_framework-1.2.0 → core_framework-1.3.0}/alembic/user/alembic.ini +0 -0
  79. {core_framework-1.2.0 → core_framework-1.3.0}/config.toml +0 -0
  80. {core_framework-1.2.0 → core_framework-1.3.0}/config.toml.template +0 -0
  81. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/__init__.py +0 -0
  82. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/__init__.py +0 -0
  83. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/__init__.py +0 -0
  84. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/comments/router.py +0 -0
  85. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/comments/schemas.py +0 -0
  86. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/moderation/__init__.py +0 -0
  87. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/moderation/router.py +0 -0
  88. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/moderation/schemas.py +0 -0
  89. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/posts/router.py +0 -0
  90. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/posts/schemas.py +0 -0
  91. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/router.py +0 -0
  92. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/users/__init__.py +0 -0
  93. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/users/router.py +0 -0
  94. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/admin/users/schemas.py +0 -0
  95. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/auth/__init__.py +0 -0
  96. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/auth/router.py +0 -0
  97. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/auth/schemas.py +0 -0
  98. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/comments/authenticated/router.py +0 -0
  99. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/comments/authenticated/schemas.py +0 -0
  100. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/comments/public/router.py +0 -0
  101. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/comments/public/schemas.py +0 -0
  102. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/comments/router.py +0 -0
  103. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/comments/schemas.py +0 -0
  104. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/constants.py +0 -0
  105. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/dependencies.py +0 -0
  106. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/events/router.py +0 -0
  107. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/events/schemas.py +0 -0
  108. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/notifications/authenticated/router.py +0 -0
  109. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/notifications/authenticated/schemas.py +0 -0
  110. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/notifications/router.py +0 -0
  111. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/posts/authenticated/router.py +0 -0
  112. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/posts/authenticated/schemas.py +0 -0
  113. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/posts/public/router.py +0 -0
  114. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/posts/public/schemas.py +0 -0
  115. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/posts/router.py +0 -0
  116. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/posts/schemas.py +0 -0
  117. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/router.py +0 -0
  118. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/schemas.py +0 -0
  119. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/system/__init__.py +0 -0
  120. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/system/router.py +0 -0
  121. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/users/__init__.py +0 -0
  122. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/users/authenticated/__init__.py +0 -0
  123. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/users/authenticated/router.py +0 -0
  124. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/users/authenticated/schemas.py +0 -0
  125. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/users/public/__init__.py +0 -0
  126. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/users/public/router.py +0 -0
  127. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/users/public/schemas.py +0 -0
  128. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/users/router.py +0 -0
  129. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/api/users/shared/schemas.py +0 -0
  130. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/__init__.py +0 -0
  131. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/auth/__init__.py +0 -0
  132. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/auth/access_service.py +0 -0
  133. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/auth/auth_service.py +0 -0
  134. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/auth/models.py +0 -0
  135. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/bootstrap.py +0 -0
  136. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/comments/admin_service.py +0 -0
  137. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/comments/aggregation_service.py +0 -0
  138. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/comments/authenticated_service.py +0 -0
  139. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/comments/public_service.py +0 -0
  140. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/events/README.md +0 -0
  141. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/events/event_service.py +0 -0
  142. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/events/event_token.py +0 -0
  143. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/events/models.py +0 -0
  144. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/moderation/__init__.py +0 -0
  145. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/moderation/appeal_service.py +0 -0
  146. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/moderation/moderator_service.py +0 -0
  147. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/moderation/report_service.py +0 -0
  148. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/moderation/scheduled_service.py +0 -0
  149. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/moderation/user_service.py +0 -0
  150. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/notifications/README.md +0 -0
  151. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/notifications/enums.py +0 -0
  152. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/notifications/inbox_service.py +0 -0
  153. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/notifications/mute_service.py +0 -0
  154. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/notifications/notification_service.py +0 -0
  155. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/posts/admin_service.py +0 -0
  156. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/posts/aggregation_service.py +0 -0
  157. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/posts/authenticated_service.py +0 -0
  158. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/posts/public_service.py +0 -0
  159. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/shared/__init__.py +0 -0
  160. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/shared/enums.py +0 -0
  161. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/shared/exceptions.py +0 -0
  162. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/shared/user_agent.py +0 -0
  163. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/users/__init__.py +0 -0
  164. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/users/admin_service.py +0 -0
  165. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/users/aggregation_service.py +0 -0
  166. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/users/authenticated_service.py +0 -0
  167. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/users/public_service.py +0 -0
  168. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/application/users/scheduled_service.py +0 -0
  169. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/asgi.py +0 -0
  170. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/bundled_alembic.py +0 -0
  171. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/constants.py +0 -0
  172. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/__init__.py +0 -0
  173. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/cache.py +0 -0
  174. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/context.py +0 -0
  175. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/database.py +0 -0
  176. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/exception_handlers/__init__.py +0 -0
  177. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/exception_handlers/comment.py +0 -0
  178. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/exception_handlers/common.py +0 -0
  179. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/exception_handlers/moderation.py +0 -0
  180. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/exception_handlers/notification.py +0 -0
  181. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/exception_handlers/post.py +0 -0
  182. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/exception_handlers/setup.py +0 -0
  183. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/exception_handlers/user.py +0 -0
  184. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/http_client.py +0 -0
  185. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/logging.py +0 -0
  186. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/middleware.py +0 -0
  187. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/observability.py +0 -0
  188. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/pagination.py +0 -0
  189. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/redis.py +0 -0
  190. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/runtime.py +0 -0
  191. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/core/settings.py +0 -0
  192. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/__init__.py +0 -0
  193. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/comment/README.md +0 -0
  194. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/comment/__init__.py +0 -0
  195. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/comment/constants.py +0 -0
  196. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/comment/dependencies.py +0 -0
  197. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/comment/enums.py +0 -0
  198. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/comment/exceptions.py +0 -0
  199. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/comment/models.py +0 -0
  200. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/comment/repository.py +0 -0
  201. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/comment/service.py +0 -0
  202. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/exceptions.py +0 -0
  203. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/moderation/README.md +0 -0
  204. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/moderation/__init__.py +0 -0
  205. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/moderation/dependencies.py +0 -0
  206. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/moderation/enums.py +0 -0
  207. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/moderation/exceptions.py +0 -0
  208. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/moderation/models.py +0 -0
  209. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/moderation/repository.py +0 -0
  210. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/moderation/service.py +0 -0
  211. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/notification/README.md +0 -0
  212. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/notification/__init__.py +0 -0
  213. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/notification/dependencies.py +0 -0
  214. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/notification/enums.py +0 -0
  215. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/notification/exceptions.py +0 -0
  216. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/notification/models.py +0 -0
  217. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/notification/repository.py +0 -0
  218. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/notification/service.py +0 -0
  219. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/post/README.md +0 -0
  220. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/post/__init__.py +0 -0
  221. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/post/constants.py +0 -0
  222. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/post/dependencies.py +0 -0
  223. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/post/enums.py +0 -0
  224. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/post/exceptions.py +0 -0
  225. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/post/models.py +0 -0
  226. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/post/repository.py +0 -0
  227. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/post/service.py +0 -0
  228. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/user/README.md +0 -0
  229. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/user/__init__.py +0 -0
  230. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/user/constants.py +0 -0
  231. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/user/dependencies.py +0 -0
  232. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/user/enums.py +0 -0
  233. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/user/exceptions.py +0 -0
  234. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/user/models.py +0 -0
  235. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/user/repository.py +0 -0
  236. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/user/service.py +0 -0
  237. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/user/utils.py +0 -0
  238. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/domains/utils.py +0 -0
  239. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/main.py +0 -0
  240. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/migrate_cli.py +0 -0
  241. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/testing/__init__.py +0 -0
  242. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/testing/arq.py +0 -0
  243. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/testing/auth.py +0 -0
  244. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/testing/config.py +0 -0
  245. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/testing/containers.py +0 -0
  246. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/testing/firebase.py +0 -0
  247. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/testing/hookspecs.py +0 -0
  248. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/testing/httpx_test_client.py +0 -0
  249. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/testing/migrations.py +0 -0
  250. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/testing/plugin.py +0 -0
  251. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/__init__.py +0 -0
  252. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/main.py +0 -0
  253. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/schedules/__init__.py +0 -0
  254. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/schedules/schedule_aggregate_comment_stats.py +0 -0
  255. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/schedules/schedule_aggregate_post_stats.py +0 -0
  256. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/schedules/schedule_aggregate_user_stats.py +0 -0
  257. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/schedules/schedule_expired_account_deletions.py +0 -0
  258. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/schedules/schedule_expired_mute_lifts.py +0 -0
  259. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/tasks/__init__.py +0 -0
  260. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/tasks/process_account_deletion.py +0 -0
  261. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/tasks/process_aggregate_comment_stats.py +0 -0
  262. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/tasks/process_aggregate_post_stats.py +0 -0
  263. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/tasks/process_aggregate_user_stats.py +0 -0
  264. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/tasks/process_mute_lift.py +0 -0
  265. {core_framework-1.2.0 → core_framework-1.3.0}/core_framework/worker/worker_context.py +0 -0
  266. {core_framework-1.2.0 → core_framework-1.3.0}/docker-compose.yml +0 -0
  267. {core_framework-1.2.0 → core_framework-1.3.0}/dockerfile +0 -0
  268. {core_framework-1.2.0 → core_framework-1.3.0}/docs/api.md +0 -0
  269. {core_framework-1.2.0 → core_framework-1.3.0}/docs/architecture-decisions.md +0 -0
  270. {core_framework-1.2.0 → core_framework-1.3.0}/docs/architecture.md +0 -0
  271. {core_framework-1.2.0 → core_framework-1.3.0}/docs/conventions.md +0 -0
  272. {core_framework-1.2.0 → core_framework-1.3.0}/docs/core-framework-migration.md +0 -0
  273. {core_framework-1.2.0 → core_framework-1.3.0}/docs/database-triggers.md +0 -0
  274. {core_framework-1.2.0 → core_framework-1.3.0}/docs/event-outbox-design.md +0 -0
  275. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/auth/access_control.md +0 -0
  276. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/auth/registration.md +0 -0
  277. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/comments/admin_comments.md +0 -0
  278. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/comments/comment_report.md +0 -0
  279. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/comments/comment_stats_aggregation.md +0 -0
  280. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/comments/create_comment.md +0 -0
  281. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/comments/delete_comment.md +0 -0
  282. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/comments/edit_comment.md +0 -0
  283. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/comments/retrieve_comments.md +0 -0
  284. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/events/events.md +0 -0
  285. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/mentions/mentions_in_content.md +0 -0
  286. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/moderation/appeals.md +0 -0
  287. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/moderation/internal_notes.md +0 -0
  288. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/moderation/moderator_actions.md +0 -0
  289. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/moderation/reports.md +0 -0
  290. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/moderation/restrictions.md +0 -0
  291. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/notifications/notification_inbox.md +0 -0
  292. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/posts/admin_posts.md +0 -0
  293. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/posts/author_context.md +0 -0
  294. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/posts/hashtag_discovery.md +0 -0
  295. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/posts/post_like.md +0 -0
  296. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/posts/post_stats_aggregation.md +0 -0
  297. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/users/account.md +0 -0
  298. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/users/account_deletion.md +0 -0
  299. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/users/blocks.md +0 -0
  300. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/users/change_history.md +0 -0
  301. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/users/check_username_exists.md +0 -0
  302. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/users/follow.md +0 -0
  303. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/users/my_posts_and_comments.md +0 -0
  304. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/users/preferences.md +0 -0
  305. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/users/profile.md +0 -0
  306. {core_framework-1.2.0 → core_framework-1.3.0}/docs/flows/users/user_removal.md +0 -0
  307. {core_framework-1.2.0 → core_framework-1.3.0}/docs/follow-system-design.md +0 -0
  308. {core_framework-1.2.0 → core_framework-1.3.0}/docs/package-api.md +0 -0
  309. {core_framework-1.2.0 → core_framework-1.3.0}/docs/testing-plugin-design.md +0 -0
  310. {core_framework-1.2.0 → core_framework-1.3.0}/makefile +0 -0
  311. {core_framework-1.2.0 → core_framework-1.3.0}/tests/__init__.py +0 -0
  312. {core_framework-1.2.0 → core_framework-1.3.0}/tests/conftest.py +0 -0
  313. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/__init__.py +0 -0
  314. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/__init__.py +0 -0
  315. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/_http_helpers.py +0 -0
  316. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/admin/__init__.py +0 -0
  317. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/admin/comments/__init__.py +0 -0
  318. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/admin/comments/router_test.py +0 -0
  319. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/admin/moderation/__init__.py +0 -0
  320. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/admin/moderation/router_test.py +0 -0
  321. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/admin/posts/__init__.py +0 -0
  322. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/admin/posts/router_test.py +0 -0
  323. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/admin/users/__init__.py +0 -0
  324. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/admin/users/router_test.py +0 -0
  325. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/auth/__init__.py +0 -0
  326. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/auth/router_test.py +0 -0
  327. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/comments/__init__.py +0 -0
  328. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/comments/authenticated/comment_writes_integration_test.py +0 -0
  329. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/comments/public/__init__.py +0 -0
  330. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/comments/public/router_test.py +0 -0
  331. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/events/router_test.py +0 -0
  332. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/notifications/__init__.py +0 -0
  333. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/notifications/router_test.py +0 -0
  334. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/posts/__init__.py +0 -0
  335. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/posts/authenticated/post_writes_integration_test.py +0 -0
  336. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/posts/comment_count_aggregation_test.py +0 -0
  337. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/posts/followers_visibility_test.py +0 -0
  338. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/posts/post_stats_dirty_marking_test.py +0 -0
  339. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/posts/public/__init__.py +0 -0
  340. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/posts/public/router_test.py +0 -0
  341. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/system/__init__.py +0 -0
  342. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/system/router_test.py +0 -0
  343. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/users/__init__.py +0 -0
  344. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/users/authenticated/__init__.py +0 -0
  345. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/users/authenticated/router_test.py +0 -0
  346. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/users/public/__init__.py +0 -0
  347. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/api/users/public/router_test.py +0 -0
  348. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/worker/__init__.py +0 -0
  349. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/worker/account_deletion_test.py +0 -0
  350. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/worker/aggregate_comment_stats_test.py +0 -0
  351. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/worker/aggregate_post_stats_test.py +0 -0
  352. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/worker/aggregate_user_stats_test.py +0 -0
  353. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/worker/conftest.py +0 -0
  354. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/worker/mute_lift_test.py +0 -0
  355. {core_framework-1.2.0 → core_framework-1.3.0}/tests/integration/worker/utils_test.py +0 -0
  356. {core_framework-1.2.0 → core_framework-1.3.0}/tests/unit/__init__.py +0 -0
  357. {core_framework-1.2.0 → core_framework-1.3.0}/tests/unit/application/comments/__init__.py +0 -0
  358. {core_framework-1.2.0 → core_framework-1.3.0}/tests/unit/application/events/event_service_test.py +0 -0
  359. {core_framework-1.2.0 → core_framework-1.3.0}/tests/unit/application/notifications/inbox_service_test.py +0 -0
  360. {core_framework-1.2.0 → core_framework-1.3.0}/tests/unit/core/bundled_alembic_test.py +0 -0
  361. {core_framework-1.2.0 → core_framework-1.3.0}/tests/unit/core/migrate_cli_test.py +0 -0
  362. {core_framework-1.2.0 → core_framework-1.3.0}/tests/unit/core/pagination_test.py +0 -0
  363. {core_framework-1.2.0 → core_framework-1.3.0}/tests/unit/domains/__init__.py +0 -0
  364. {core_framework-1.2.0 → core_framework-1.3.0}/tests/unit/domains/comment/__init__.py +0 -0
  365. {core_framework-1.2.0 → core_framework-1.3.0}/tests/unit/domains/user/service_test.py +0 -0
@@ -0,0 +1,34 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Checkout code
14
+ uses: actions/checkout@v6
15
+
16
+ - name: Install uv
17
+ uses: astral-sh/setup-uv@v7
18
+ with:
19
+ version: "0.7.9"
20
+ enable-cache: true
21
+ cache-dependency-glob: "uv.lock"
22
+
23
+ - name: Set up Python
24
+ uses: actions/setup-python@v6
25
+ with:
26
+ python-version-file: ".python-version"
27
+
28
+ - name: Build
29
+ run: uv build
30
+
31
+ - name: Publish
32
+ run: uv publish
33
+ env:
34
+ UV_PUBLISH_TOKEN: ${{ secrets.UV_PUBLISH_TOKEN }}
@@ -4,6 +4,21 @@ Notable changes to **core-framework** (import **`core_framework`**). Format foll
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.3.0] - 2026-05-16
8
+
9
+ ### Added
10
+
11
+ - **`docker-compose.dev.yaml`** for local Postgres and Redis (aligned with repo **`config.toml`**).
12
+ - **`firebase_config.example.json`** and **`FileNotFoundError`** with next-step text when **`firebase_config.json`** is missing in **`init_firebase`**.
13
+
14
+ ### Documentation
15
+
16
+ - **`README.md`**: install (**`uv`**), local development, Firebase file copy, host / pytest integration examples.
17
+
18
+ ### Fixed
19
+
20
+ - Example Firebase JSON uses no PEM markers so **`detect-private-key`** pre-commit hooks do not false-positive.
21
+
7
22
  ## [1.2.0] - 2026-05-02
8
23
 
9
24
  ### Changed
@@ -124,4 +139,5 @@ First **SemVer-stable** release per **`docs/package-api.md`**.
124
139
  [1.1.0]: https://github.com/NepNepFFXIV/core-framework/compare/v1.0.0...v1.1.0
125
140
  [1.1.1]: https://github.com/NepNepFFXIV/core-framework/compare/v1.1.0...v1.1.1
126
141
  [1.2.0]: https://github.com/NepNepFFXIV/core-framework/compare/v1.1.1...v1.2.0
127
- [unreleased]: https://github.com/NepNepFFXIV/core-framework/compare/v1.2.0...HEAD
142
+ [1.3.0]: https://github.com/NepNepFFXIV/core-framework/compare/v1.2.0...v1.3.0
143
+ [unreleased]: https://github.com/NepNepFFXIV/core-framework/compare/v1.3.0...HEAD
@@ -0,0 +1,115 @@
1
+ Metadata-Version: 2.4
2
+ Name: core-framework
3
+ Version: 1.3.0
4
+ Summary: Core framework package (import as core_framework)
5
+ Project-URL: Homepage, https://github.com/NepNepFFXIV/core-framework
6
+ Project-URL: Repository, https://github.com/NepNepFFXIV/core-framework
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Requires-Python: >=3.14
10
+ Requires-Dist: alembic>=1.18.4
11
+ Requires-Dist: arq>=0.28.0
12
+ Requires-Dist: async-lru>=2.1.0
13
+ Requires-Dist: asyncer>=0.0.14
14
+ Requires-Dist: asyncpg>=0.31.0
15
+ Requires-Dist: brotli-asgi>=1.6.0
16
+ Requires-Dist: cashews[redis]>=7.5.0
17
+ Requires-Dist: device-detector>=6.2.0
18
+ Requires-Dist: fastapi[standard]>=0.136.1
19
+ Requires-Dist: firebase-admin>=7.4.0
20
+ Requires-Dist: httpx[http2]>=0.28.1
21
+ Requires-Dist: itsdangerous>=2.2.0
22
+ Requires-Dist: logfire[asyncpg,fastapi,httpx,redis]>=4.32.1
23
+ Requires-Dist: mashumaro[orjson]>=3.20
24
+ Requires-Dist: orjson>=3.11.7
25
+ Requires-Dist: python-ulid>=3.1.0
26
+ Requires-Dist: structlog>=25.5.0
27
+ Requires-Dist: tenacity>=9.1.4
28
+ Provides-Extra: testing
29
+ Requires-Dist: asgi-lifespan>=2.1.0; extra == 'testing'
30
+ Requires-Dist: pytest-xdist>=3.6.0; extra == 'testing'
31
+ Requires-Dist: pytest>=9.0.3; extra == 'testing'
32
+ Requires-Dist: testcontainers[postgres,redis]>=4.13.2; extra == 'testing'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # Core framework
36
+
37
+ Install from PyPI as **`core-framework`**, import **`core_framework`**. MIT — [LICENSE](LICENSE). [Repository](https://github.com/NepNepFFXIV/core-framework), [PyPI](https://pypi.org/project/core-framework/).
38
+
39
+ ## Install
40
+
41
+ ```bash
42
+ uv add core-framework
43
+ ```
44
+
45
+ ## Local development
46
+
47
+ Use **Python 3.14**. Install **uv** and **Docker**.
48
+
49
+ ```bash
50
+ docker compose -f docker-compose.dev.yaml up -d
51
+ uv sync --locked --all-extras --dev
52
+ uv run cf-alembic
53
+ make run
54
+ ```
55
+
56
+ **Firebase:** copy **`firebase_config.example.json`** to **`firebase_config.json`** at the repo root and replace with your Firebase project’s **service account** JSON from the console.
57
+
58
+ For **`make test`**, use the Firebase CLI (Auth emulator). Stop DB/Redis: **`docker compose -f docker-compose.dev.yaml down`**.
59
+
60
+ ## Hosts
61
+
62
+ 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.
63
+
64
+ ```python
65
+ from core_framework.main import init_app
66
+ from fastapi import FastAPI
67
+
68
+ from myapp.settings import HostSettings, load_default_settings
69
+
70
+
71
+ def build_app(settings: HostSettings | None = None) -> FastAPI:
72
+ resolved = settings if settings is not None else load_default_settings()
73
+ app = init_app(resolved)
74
+
75
+ from myapp.bootstrap import configure_dependencies
76
+ from myapp.exception_handlers import setup_exception_handlers
77
+
78
+ configure_dependencies(runtime=app.state.core_runtime)
79
+ setup_exception_handlers(app)
80
+
81
+ from myapp.api.router import router
82
+
83
+ app.include_router(router)
84
+ return app
85
+ ```
86
+
87
+ From the host repository root, run **`uv run cf-alembic`**. See [core-framework-migration](docs/core-framework-migration.md).
88
+
89
+ ## Host pytest
90
+
91
+ In your host repository, add the **`core-framework[testing]`** extra to dev or test dependencies. In **`tests/conftest.py`**, register **`pytest_core_framework_config`** (returns **`TestConfig`**) and a session-scoped **`anyio_backend`** fixture that returns **`"asyncio"`**.
92
+
93
+ ```python
94
+ import pytest
95
+
96
+ from core_framework.testing import TestConfig
97
+
98
+ from myapp.settings import load_default_settings
99
+
100
+
101
+ def pytest_core_framework_config() -> TestConfig:
102
+ from myapp.main import build_app
103
+
104
+ return TestConfig(
105
+ settings_loader=load_default_settings,
106
+ app_factory=build_app,
107
+ )
108
+
109
+
110
+ @pytest.fixture(scope="session")
111
+ def anyio_backend() -> str:
112
+ return "asyncio"
113
+ ```
114
+
115
+ See [Package API — Testing](docs/package-api.md#testing-pytest-plugin) and [testing plugin design](docs/testing-plugin-design.md).
@@ -0,0 +1,81 @@
1
+ # Core framework
2
+
3
+ Install from PyPI as **`core-framework`**, import **`core_framework`**. MIT — [LICENSE](LICENSE). [Repository](https://github.com/NepNepFFXIV/core-framework), [PyPI](https://pypi.org/project/core-framework/).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ uv add core-framework
9
+ ```
10
+
11
+ ## Local development
12
+
13
+ Use **Python 3.14**. Install **uv** and **Docker**.
14
+
15
+ ```bash
16
+ docker compose -f docker-compose.dev.yaml up -d
17
+ uv sync --locked --all-extras --dev
18
+ uv run cf-alembic
19
+ make run
20
+ ```
21
+
22
+ **Firebase:** copy **`firebase_config.example.json`** to **`firebase_config.json`** at the repo root and replace with your Firebase project’s **service account** JSON from the console.
23
+
24
+ For **`make test`**, use the Firebase CLI (Auth emulator). Stop DB/Redis: **`docker compose -f docker-compose.dev.yaml down`**.
25
+
26
+ ## Hosts
27
+
28
+ 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.
29
+
30
+ ```python
31
+ from core_framework.main import init_app
32
+ from fastapi import FastAPI
33
+
34
+ from myapp.settings import HostSettings, load_default_settings
35
+
36
+
37
+ def build_app(settings: HostSettings | None = None) -> FastAPI:
38
+ resolved = settings if settings is not None else load_default_settings()
39
+ app = init_app(resolved)
40
+
41
+ from myapp.bootstrap import configure_dependencies
42
+ from myapp.exception_handlers import setup_exception_handlers
43
+
44
+ configure_dependencies(runtime=app.state.core_runtime)
45
+ setup_exception_handlers(app)
46
+
47
+ from myapp.api.router import router
48
+
49
+ app.include_router(router)
50
+ return app
51
+ ```
52
+
53
+ From the host repository root, run **`uv run cf-alembic`**. See [core-framework-migration](docs/core-framework-migration.md).
54
+
55
+ ## Host pytest
56
+
57
+ In your host repository, add the **`core-framework[testing]`** extra to dev or test dependencies. In **`tests/conftest.py`**, register **`pytest_core_framework_config`** (returns **`TestConfig`**) and a session-scoped **`anyio_backend`** fixture that returns **`"asyncio"`**.
58
+
59
+ ```python
60
+ import pytest
61
+
62
+ from core_framework.testing import TestConfig
63
+
64
+ from myapp.settings import load_default_settings
65
+
66
+
67
+ def pytest_core_framework_config() -> TestConfig:
68
+ from myapp.main import build_app
69
+
70
+ return TestConfig(
71
+ settings_loader=load_default_settings,
72
+ app_factory=build_app,
73
+ )
74
+
75
+
76
+ @pytest.fixture(scope="session")
77
+ def anyio_backend() -> str:
78
+ return "asyncio"
79
+ ```
80
+
81
+ See [Package API — Testing](docs/package-api.md#testing-pytest-plugin) and [testing plugin design](docs/testing-plugin-design.md).
@@ -1,4 +1,5 @@
1
1
  import os
2
+ from pathlib import Path
2
3
  from typing import Any
3
4
 
4
5
  from firebase_admin import credentials, get_app, initialize_app
@@ -16,6 +17,12 @@ def init_firebase(settings: Settings) -> None:
16
17
  cred: credentials.Base | None = None
17
18
  options: dict[str, Any] | None = {"projectId": "test"}
18
19
  if not os.getenv("FIREBASE_AUTH_EMULATOR_HOST"):
19
- cred = credentials.Certificate(settings.PROJECT_ROOT / "firebase_config.json")
20
+ path = Path(settings.PROJECT_ROOT) / "firebase_config.json"
21
+ if not path.is_file():
22
+ raise FileNotFoundError(
23
+ f"Missing Firebase service account file: {path}. "
24
+ "Copy firebase_config.example.json to firebase_config.json and paste your project's service account JSON."
25
+ )
26
+ cred = credentials.Certificate(path)
20
27
  options = None
21
28
  initialize_app(cred, options)
@@ -0,0 +1,24 @@
1
+ services:
2
+ postgres:
3
+ image: postgres:18
4
+ environment:
5
+ POSTGRES_USER: postgres
6
+ POSTGRES_PASSWORD: postgres
7
+ POSTGRES_DB: postgres
8
+ ports:
9
+ - "6969:5432"
10
+ healthcheck:
11
+ test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
12
+ interval: 5s
13
+ timeout: 3s
14
+ retries: 10
15
+
16
+ redis:
17
+ image: redis:8
18
+ ports:
19
+ - "6379:6379"
20
+ healthcheck:
21
+ test: ["CMD", "redis-cli", "ping"]
22
+ interval: 5s
23
+ timeout: 3s
24
+ retries: 10
@@ -0,0 +1,10 @@
1
+ # Backlog
2
+
3
+ - ETag
4
+ - py-spy
5
+ - Stale-while-revalidate
6
+ - Backpressure — uvicorn settings (https://uvicorn.dev/settings/)
7
+ - Backpressure — route level with semaphore
8
+ - https://github.com/rennf93/fastapi-guard
9
+ - https://github.com/TypeError/secure
10
+ - Outbox pattern
@@ -0,0 +1,13 @@
1
+ {
2
+ "type": "service_account",
3
+ "project_id": "your-firebase-project-id",
4
+ "private_key_id": "replace-me",
5
+ "private_key": "<paste the full private_key string from the service account JSON Firebase downloads (PEM, not shown here)>",
6
+ "client_email": "firebase-adminsdk-example@your-firebase-project-id.iam.gserviceaccount.com",
7
+ "client_id": "000000000000000000000",
8
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
9
+ "token_uri": "https://oauth2.googleapis.com/token",
10
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-example%40your-firebase-project-id.iam.gserviceaccount.com",
12
+ "universe_domain": "googleapis.com"
13
+ }
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "core-framework"
7
- version = "1.2.0"
7
+ version = "1.3.0"
8
8
  description = "Core framework package (import as core_framework)"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -309,7 +309,7 @@ wheels = [
309
309
 
310
310
  [[package]]
311
311
  name = "core-framework"
312
- version = "1.2.0"
312
+ version = "1.3.0"
313
313
  source = { editable = "." }
314
314
  dependencies = [
315
315
  { name = "alembic" },
@@ -1 +0,0 @@
1
- *
@@ -1,6 +0,0 @@
1
- {
2
- "token": "pylf_v1_us_GpHqCK5YWg6mWH9N4j6hLf2Fkvsq23sjGvk9Lvxq7LJP",
3
- "project_name": "manga-dev",
4
- "project_url": "https://logfire-us.pydantic.dev/nepnep/manga-dev",
5
- "logfire_api_url": "https://logfire-us.pydantic.dev"
6
- }
@@ -1,131 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: core-framework
3
- Version: 1.2.0
4
- Summary: Core framework package (import as core_framework)
5
- Project-URL: Homepage, https://github.com/NepNepFFXIV/core-framework
6
- Project-URL: Repository, https://github.com/NepNepFFXIV/core-framework
7
- License-Expression: MIT
8
- License-File: LICENSE
9
- Requires-Python: >=3.14
10
- Requires-Dist: alembic>=1.18.4
11
- Requires-Dist: arq>=0.28.0
12
- Requires-Dist: async-lru>=2.1.0
13
- Requires-Dist: asyncer>=0.0.14
14
- Requires-Dist: asyncpg>=0.31.0
15
- Requires-Dist: brotli-asgi>=1.6.0
16
- Requires-Dist: cashews[redis]>=7.5.0
17
- Requires-Dist: device-detector>=6.2.0
18
- Requires-Dist: fastapi[standard]>=0.136.1
19
- Requires-Dist: firebase-admin>=7.4.0
20
- Requires-Dist: httpx[http2]>=0.28.1
21
- Requires-Dist: itsdangerous>=2.2.0
22
- Requires-Dist: logfire[asyncpg,fastapi,httpx,redis]>=4.32.1
23
- Requires-Dist: mashumaro[orjson]>=3.20
24
- Requires-Dist: orjson>=3.11.7
25
- Requires-Dist: python-ulid>=3.1.0
26
- Requires-Dist: structlog>=25.5.0
27
- Requires-Dist: tenacity>=9.1.4
28
- Provides-Extra: testing
29
- Requires-Dist: asgi-lifespan>=2.1.0; extra == 'testing'
30
- Requires-Dist: pytest-xdist>=3.6.0; extra == 'testing'
31
- Requires-Dist: pytest>=9.0.3; extra == 'testing'
32
- Requires-Dist: testcontainers[postgres,redis]>=4.13.2; extra == 'testing'
33
- Description-Content-Type: text/markdown
34
-
35
- # Core framework
36
-
37
- Reusable backend core published as the Python distribution **`core-framework`** (`pyproject.toml`). Import the implementation as **`core_framework`** (see [Core framework migration](docs/core-framework-migration.md), [Package API](docs/package-api.md), and [CHANGELOG](CHANGELOG.md) for version history).
38
-
39
- **Repository:** [github.com/NepNepFFXIV/core-framework](https://github.com/NepNepFFXIV/core-framework)
40
-
41
- **License:** MIT — see [LICENSE](LICENSE).
42
-
43
- ## Install
44
-
45
- Pin **`core-framework`** from **Git** (use a **tag** or commit for reproducible builds):
46
-
47
- ```bash
48
- uv add "core-framework @ git+https://github.com/NepNepFFXIV/core-framework.git@v1.2.0"
49
- ```
50
-
51
- ```bash
52
- pip install "core-framework @ git+https://github.com/NepNepFFXIV/core-framework.git@v1.2.0"
53
- ```
54
-
55
- After it resolves, load **`Settings`**, call **`init_app(settings)`** from **`core_framework.main`** in your app factory, and apply bundled core schema from the host project root with **`uv run cf-alembic`** (see [Host integration](#host-integration) and [Package API](docs/package-api.md)).
56
-
57
- To **hack on this repo**: clone it, run **`uv sync`** (or **`pip install -e .`**), keep a local **`config.toml`**, run **`uv run cf-alembic`**, then **`make run`** or serve **`core_framework.asgi:app`**.
58
-
59
- ## Host integration
60
-
61
- Hosts depend on **`core-framework`**, own config and the DB, and import **`core_framework`**. Details: [Core framework migration](docs/core-framework-migration.md).
62
-
63
- 1. **Dependency** — Pin **`core-framework`** (path, Git tag, or index) and lock deploys (**`uv.lock`**, etc.).
64
- 1. **Settings** — Use **`Settings`** from **`core_framework.core.settings`**. Default loading uses **`config.toml`** and **environment variables**; **env wins** over TOML for the same field (see [Architecture decisions](docs/architecture-decisions.md#configuration-toml-primary-environment-overrides)). Subclass **only** if you need extra host-only fields; otherwise **`Settings()`** / **`model_validate`** is enough. Subclasses may need **`model_config`** tweaks (e.g. **`toml_file`**) if paths differ.
65
- 1. **App** — Call **`init_app(settings)`** from **`core_framework.main`** inside the host’s own **`main.py`** (or app factory). Importing **`core_framework.main`** has no side effects; only **`init_app(settings)`** runs the bootstrap. Do **not** import **`core_framework.asgi`** — that module exists so **`fastapi dev`** / **`uvicorn`** can serve the library’s own default-settings app standalone, and it eagerly loads **`core-framework`**’s own **`config.toml`** at import time. Do not mount **`router`** alone without the same bootstrap — see [Package API](docs/package-api.md).
66
- 1. **Database** — Apply core schema from the host root (where **`config.toml`** loads): **`uv run cf-alembic`**. Host-only tables: host migrations; order with core ([Database and Alembic](docs/core-framework-migration.md#database-and-alembic)).
67
- 1. **Worker** — **`WorkerSettings`** class in **`core_framework.worker.main`** (run with **`arq core_framework.worker.main.WorkerSettings`**). Bootstrap (**`configure_application_dependencies`**, pool connects, **`init_cashews_backend`**) runs in **`on_startup`**, not at import time. ARQ exposes **`ctx["redis"]`** for enqueue in cron handlers; **`CoreRuntime.redis_queue`** is a separate connected pool for runtime parity with the API — see **[Architecture — ARQ and CoreRuntime queue clients](docs/architecture.md#arq-and-coreruntime-queue-clients)**.
68
- 1. **API surface** — Only [Package API](docs/package-api.md) imports are stable; see [CHANGELOG](CHANGELOG.md).
69
- 1. **Upgrading / new `Settings` fields** — When you bump **`core-framework`**, read **[CHANGELOG](CHANGELOG.md)** for that release (and any required migration notes). New **`Settings`** keys are announced there: **required** keys must be added to the host’s **`config.toml`** / env before deploy; **optional** keys list defaults. Version bumps follow SemVer in **`pyproject.toml`** so hosts can judge impact.
70
-
71
- ## Testing in host projects
72
-
73
- Use the **`core-framework[testing]`** optional extra in the host’s **dev** or **test** dependency group so pytest gets **`testcontainers`**, **`pytest-xdist`**, **`asgi-lifespan`**, and a compatible **`pytest`**. The package registers a pytest plugin automatically; you do **not** need **`pytest_plugins = (...)`** for **`core_framework.testing`**.
74
-
75
- 1. Add the extra (example with **`uv`**): in **`pyproject.toml`**, e.g. **`core-framework = { path = "…", extras = ["testing"] }`** or **`core-framework[testing]`** in **`[dependency-groups].dev`**.
76
- 1. In the host’s **root** **`tests/conftest.py`**, implement **`pytest_core_framework_config()`** returning **`TestConfig`** from **`core_framework.testing`** — pass **`settings_loader`** and **`app_factory`** (usually your **`load_default_settings`** and **`init_app`**). Optionally set **`alembic_root`**, **`firebase_project_id`**, **`include_arq_fixtures`**, etc.
77
- 1. In the same **`conftest.py`**, define a **session-scoped** **`anyio_backend`** fixture that returns **`"asyncio"`** (required so session-scoped async fixtures work with anyio’s pytest integration).
78
-
79
- Minimal shape (adjust paths and flags to your host):
80
-
81
- ```python
82
- from pathlib import Path
83
-
84
- import pytest
85
-
86
- from core_framework.testing import TestConfig
87
- from my_host.settings import load_default_settings
88
- from my_host.main import init_app
89
-
90
-
91
- def pytest_core_framework_config() -> TestConfig:
92
- return TestConfig(
93
- settings_loader=load_default_settings,
94
- app_factory=init_app,
95
- # alembic_root=Path(__file__).resolve().parent.parent / "alembic",
96
- # firebase_project_id="test",
97
- # include_arq_fixtures=False,
98
- )
99
-
100
-
101
- @pytest.fixture(scope="session")
102
- def anyio_backend() -> str:
103
- return "asyncio"
104
- ```
105
-
106
- **Stable API and fixture list:** **[Package API — Testing](docs/package-api.md#testing-pytest-plugin)**. **Design notes (xdist, Firebase hybrid, risks):** **[Testing plugin design](docs/testing-plugin-design.md)**.
107
-
108
- ## Commands
109
-
110
- - `make run` — run the standalone core app locally.
111
- - `make alembic` — run bundled core migrations via `cf-alembic`.
112
- - `make ruff` — lint and format.
113
- - `make ty` — type check.
114
- - `make vulture` — scan for unused code.
115
- - `make test` — run tests with the Firebase auth emulator.
116
-
117
- ## Adding Domains
118
-
119
- For a new core domain with its own schema name, use `.cursor/skills/add-domain/SKILL.md`.
120
- The initial scaffold creates settings, an empty Alembic tree, domain class shells, and bootstrap wiring; migration revisions and `ALEMBIC_DOMAINS` are added later with real DDL.
121
-
122
- ## TODO
123
-
124
- - ETag
125
- - py-spy
126
- - Stale-while-revalidate
127
- - Backpressure - uvicorn settings https://uvicorn.dev/settings/
128
- - Backpressure - route level with semaphore
129
- - https://github.com/rennf93/fastapi-guard
130
- - https://github.com/TypeError/secure
131
- - Outbox pattern
@@ -1,97 +0,0 @@
1
- # Core framework
2
-
3
- Reusable backend core published as the Python distribution **`core-framework`** (`pyproject.toml`). Import the implementation as **`core_framework`** (see [Core framework migration](docs/core-framework-migration.md), [Package API](docs/package-api.md), and [CHANGELOG](CHANGELOG.md) for version history).
4
-
5
- **Repository:** [github.com/NepNepFFXIV/core-framework](https://github.com/NepNepFFXIV/core-framework)
6
-
7
- **License:** MIT — see [LICENSE](LICENSE).
8
-
9
- ## Install
10
-
11
- Pin **`core-framework`** from **Git** (use a **tag** or commit for reproducible builds):
12
-
13
- ```bash
14
- uv add "core-framework @ git+https://github.com/NepNepFFXIV/core-framework.git@v1.2.0"
15
- ```
16
-
17
- ```bash
18
- pip install "core-framework @ git+https://github.com/NepNepFFXIV/core-framework.git@v1.2.0"
19
- ```
20
-
21
- After it resolves, load **`Settings`**, call **`init_app(settings)`** from **`core_framework.main`** in your app factory, and apply bundled core schema from the host project root with **`uv run cf-alembic`** (see [Host integration](#host-integration) and [Package API](docs/package-api.md)).
22
-
23
- To **hack on this repo**: clone it, run **`uv sync`** (or **`pip install -e .`**), keep a local **`config.toml`**, run **`uv run cf-alembic`**, then **`make run`** or serve **`core_framework.asgi:app`**.
24
-
25
- ## Host integration
26
-
27
- Hosts depend on **`core-framework`**, own config and the DB, and import **`core_framework`**. Details: [Core framework migration](docs/core-framework-migration.md).
28
-
29
- 1. **Dependency** — Pin **`core-framework`** (path, Git tag, or index) and lock deploys (**`uv.lock`**, etc.).
30
- 1. **Settings** — Use **`Settings`** from **`core_framework.core.settings`**. Default loading uses **`config.toml`** and **environment variables**; **env wins** over TOML for the same field (see [Architecture decisions](docs/architecture-decisions.md#configuration-toml-primary-environment-overrides)). Subclass **only** if you need extra host-only fields; otherwise **`Settings()`** / **`model_validate`** is enough. Subclasses may need **`model_config`** tweaks (e.g. **`toml_file`**) if paths differ.
31
- 1. **App** — Call **`init_app(settings)`** from **`core_framework.main`** inside the host’s own **`main.py`** (or app factory). Importing **`core_framework.main`** has no side effects; only **`init_app(settings)`** runs the bootstrap. Do **not** import **`core_framework.asgi`** — that module exists so **`fastapi dev`** / **`uvicorn`** can serve the library’s own default-settings app standalone, and it eagerly loads **`core-framework`**’s own **`config.toml`** at import time. Do not mount **`router`** alone without the same bootstrap — see [Package API](docs/package-api.md).
32
- 1. **Database** — Apply core schema from the host root (where **`config.toml`** loads): **`uv run cf-alembic`**. Host-only tables: host migrations; order with core ([Database and Alembic](docs/core-framework-migration.md#database-and-alembic)).
33
- 1. **Worker** — **`WorkerSettings`** class in **`core_framework.worker.main`** (run with **`arq core_framework.worker.main.WorkerSettings`**). Bootstrap (**`configure_application_dependencies`**, pool connects, **`init_cashews_backend`**) runs in **`on_startup`**, not at import time. ARQ exposes **`ctx["redis"]`** for enqueue in cron handlers; **`CoreRuntime.redis_queue`** is a separate connected pool for runtime parity with the API — see **[Architecture — ARQ and CoreRuntime queue clients](docs/architecture.md#arq-and-coreruntime-queue-clients)**.
34
- 1. **API surface** — Only [Package API](docs/package-api.md) imports are stable; see [CHANGELOG](CHANGELOG.md).
35
- 1. **Upgrading / new `Settings` fields** — When you bump **`core-framework`**, read **[CHANGELOG](CHANGELOG.md)** for that release (and any required migration notes). New **`Settings`** keys are announced there: **required** keys must be added to the host’s **`config.toml`** / env before deploy; **optional** keys list defaults. Version bumps follow SemVer in **`pyproject.toml`** so hosts can judge impact.
36
-
37
- ## Testing in host projects
38
-
39
- Use the **`core-framework[testing]`** optional extra in the host’s **dev** or **test** dependency group so pytest gets **`testcontainers`**, **`pytest-xdist`**, **`asgi-lifespan`**, and a compatible **`pytest`**. The package registers a pytest plugin automatically; you do **not** need **`pytest_plugins = (...)`** for **`core_framework.testing`**.
40
-
41
- 1. Add the extra (example with **`uv`**): in **`pyproject.toml`**, e.g. **`core-framework = { path = "…", extras = ["testing"] }`** or **`core-framework[testing]`** in **`[dependency-groups].dev`**.
42
- 1. In the host’s **root** **`tests/conftest.py`**, implement **`pytest_core_framework_config()`** returning **`TestConfig`** from **`core_framework.testing`** — pass **`settings_loader`** and **`app_factory`** (usually your **`load_default_settings`** and **`init_app`**). Optionally set **`alembic_root`**, **`firebase_project_id`**, **`include_arq_fixtures`**, etc.
43
- 1. In the same **`conftest.py`**, define a **session-scoped** **`anyio_backend`** fixture that returns **`"asyncio"`** (required so session-scoped async fixtures work with anyio’s pytest integration).
44
-
45
- Minimal shape (adjust paths and flags to your host):
46
-
47
- ```python
48
- from pathlib import Path
49
-
50
- import pytest
51
-
52
- from core_framework.testing import TestConfig
53
- from my_host.settings import load_default_settings
54
- from my_host.main import init_app
55
-
56
-
57
- def pytest_core_framework_config() -> TestConfig:
58
- return TestConfig(
59
- settings_loader=load_default_settings,
60
- app_factory=init_app,
61
- # alembic_root=Path(__file__).resolve().parent.parent / "alembic",
62
- # firebase_project_id="test",
63
- # include_arq_fixtures=False,
64
- )
65
-
66
-
67
- @pytest.fixture(scope="session")
68
- def anyio_backend() -> str:
69
- return "asyncio"
70
- ```
71
-
72
- **Stable API and fixture list:** **[Package API — Testing](docs/package-api.md#testing-pytest-plugin)**. **Design notes (xdist, Firebase hybrid, risks):** **[Testing plugin design](docs/testing-plugin-design.md)**.
73
-
74
- ## Commands
75
-
76
- - `make run` — run the standalone core app locally.
77
- - `make alembic` — run bundled core migrations via `cf-alembic`.
78
- - `make ruff` — lint and format.
79
- - `make ty` — type check.
80
- - `make vulture` — scan for unused code.
81
- - `make test` — run tests with the Firebase auth emulator.
82
-
83
- ## Adding Domains
84
-
85
- For a new core domain with its own schema name, use `.cursor/skills/add-domain/SKILL.md`.
86
- The initial scaffold creates settings, an empty Alembic tree, domain class shells, and bootstrap wiring; migration revisions and `ALEMBIC_DOMAINS` are added later with real DDL.
87
-
88
- ## TODO
89
-
90
- - ETag
91
- - py-spy
92
- - Stale-while-revalidate
93
- - Backpressure - uvicorn settings https://uvicorn.dev/settings/
94
- - Backpressure - route level with semaphore
95
- - https://github.com/rennf93/fastapi-guard
96
- - https://github.com/TypeError/secure
97
- - Outbox pattern