core-framework 2.3.2__tar.gz → 2.3.3__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.
- {core_framework-2.3.2 → core_framework-2.3.3}/CHANGELOG.md +29 -1
- {core_framework-2.3.2 → core_framework-2.3.3}/PKG-INFO +1 -1
- core_framework-2.3.3/alembic/analytics/alembic/versions/2d61a5e88d76_analytics_utm_events_add_kind.py +36 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/bootstrap.py +2 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/events/README.md +3 -1
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/events/event_service.py +16 -1
- core_framework-2.3.3/core_framework/application/events/utm_capture_kinds.py +30 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/analytics/README.md +3 -2
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/analytics/__init__.py +4 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/analytics/constants.py +4 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/analytics/repository.py +5 -3
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/analytics/service.py +17 -3
- core_framework-2.3.3/docs/deployments/guides/app-server-deploy-ssh.md +78 -0
- core_framework-2.3.3/docs/deployments/guides/image-server-ssh.md +93 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/deployments/guides/ubuntu-server-setup.md +1 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/design/README.md +10 -10
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/design/events-ingest-design.md +34 -10
- core_framework-2.3.3/docs/design/utm-events-design.md +272 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/events/events.md +31 -20
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/library/core-framework-migration.md +1 -1
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/library/package-api.md +29 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/pyproject.toml +1 -1
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/events/router_test.py +224 -8
- {core_framework-2.3.2 → core_framework-2.3.3}/uv.lock +1 -1
- core_framework-2.3.2/docs/deployments/guides/app-server-deploy-ssh.md +0 -55
- core_framework-2.3.2/docs/deployments/guides/image-server-ssh.md +0 -62
- core_framework-2.3.2/docs/design/utm-events-design.md +0 -233
- {core_framework-2.3.2 → core_framework-2.3.3}/.agents/skills/fastapi +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.agents/skills/library-skills/.library-skills.json +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.agents/skills/library-skills/SKILL.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/alembic-migrations.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/api-layer.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/api-reference-docs.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/api-validation.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/application-layer.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/constants-final.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/constitution.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/database-triggers.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/docstrings.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/domain-caller-context.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/domain-imports.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/domain-input-guards.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/domain-repository-exceptions.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/domain-services-and-adapters.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/error-boundary.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/flow-documentation.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/inline-raise-messages.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/integration-test-strategy.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/layer-boundaries.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/no-code-in-docs.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/postgres-config-conventions.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/repository-schema-isolation.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/strong-reads.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/rules/structured-logging.mdc +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/skills/add-config/SKILL.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/skills/add-domain/SKILL.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/skills/code-review/SKILL.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/skills/fastapi +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/skills/implement-feature/SKILL.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/skills/recommend-features/SKILL.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/skills/sync-host-rules/SKILL.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.cursor/skills/write-flow-doc/SKILL.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.dockerignore +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.github/workflows/_deploy.yml +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.github/workflows/dev-ci-cd.yaml +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.github/workflows/manual-deployment.yaml +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.github/workflows/publish-pypi.yml +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.github/workflows/test.yaml +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.gitignore +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.pre-commit-config.yaml +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/.python-version +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/LICENSE +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/analytics/alembic/README +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/analytics/alembic/env.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/analytics/alembic/script.py.mako +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/analytics/alembic/versions/585105e1149e_analytics_add_utm_events.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/analytics/alembic/versions/5b9ac98bb150_analytics_daily_fact.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/analytics/alembic/versions/7f2a9c1d4e8b_analytics_daily_fact_day_index.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/analytics/alembic.ini +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/comment/alembic/README +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/comment/alembic/env.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/comment/alembic/script.py.mako +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/comment/alembic/versions/comment_add_comment_attachments.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/comment/alembic/versions/comment_add_comment_create_idempotency.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/comment/alembic/versions/comment_add_comment_create_idempotency_created_at_index.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/comment/alembic/versions/comment_add_comment_mentions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/comment/alembic/versions/comment_tombstone_status_model.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/comment/alembic/versions/v1_comment_init_baseline.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/comment/alembic.ini +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/extension/alembic/README +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/extension/alembic/env.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/extension/alembic/script.py.mako +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/extension/alembic/versions/v1_ext_init_baseline.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/extension/alembic.ini +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/media/alembic/README +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/media/alembic/env.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/media/alembic/script.py.mako +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/media/alembic/versions/media_add_attachment_staging_registry.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/media/alembic/versions/media_add_banner_staging_and_lease.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/media/alembic/versions/media_attachment_staging_registry_published_at.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/media/alembic/versions/v1_media_init_baseline.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/media/alembic.ini +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/moderation/alembic/README +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/moderation/alembic/env.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/moderation/alembic/script.py.mako +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/moderation/alembic/versions/moderation_add_event_outbox.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/moderation/alembic/versions/moderation_add_event_outbox_dead_indexes.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/moderation/alembic/versions/moderation_add_event_outbox_pending_created_at_index.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/moderation/alembic/versions/v1_mod_init_baseline.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/moderation/alembic.ini +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/notification/alembic/README +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/notification/alembic/env.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/notification/alembic/script.py.mako +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/notification/alembic/versions/v1_notif_init_baseline.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/notification/alembic.ini +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic/README +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic/env.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic/script.py.mako +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic/versions/post_add_post_attachments.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic/versions/post_add_post_create_idempotency.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic/versions/post_add_post_create_idempotency_created_at_index.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic/versions/post_add_post_mentions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic/versions/post_post_views_retention_high_water_mark.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic/versions/post_tombstone_status_model.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic/versions/v1_post_init_baseline.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/post/alembic.ini +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/README +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/env.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/script.py.mako +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/versions/44df70a45ba6_user_add_signup_events.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/versions/user_add_avatar_ingest_sequences.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/versions/user_add_banner_ingest_sequences.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/versions/user_add_date_of_birth_to_profiles.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/versions/user_add_event_outbox.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/versions/user_add_event_outbox_dead_indexes.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/versions/user_add_event_outbox_pending_created_at_index.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/versions/user_reserve_sentinel_user_ids.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic/versions/v1_user_init_baseline.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/alembic/user/alembic.ini +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/config.toml +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/config.toml.template +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/analytics/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/analytics/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/cache/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/cache/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/comments/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/comments/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/moderation/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/moderation/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/moderation/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/outbox/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/outbox/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/posts/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/posts/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/users/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/users/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/admin/users/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/attachments/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/attachments/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/auth/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/auth/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/auth/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/comments/authenticated/mappers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/comments/authenticated/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/comments/authenticated/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/comments/public/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/comments/public/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/comments/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/comments/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/constants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/events/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/events/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/idempotency/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/idempotency/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/notifications/authenticated/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/notifications/authenticated/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/notifications/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/posts/authenticated/mappers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/posts/authenticated/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/posts/authenticated/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/posts/public/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/posts/public/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/posts/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/posts/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/system/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/system/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/authenticated/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/authenticated/mappers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/authenticated/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/authenticated/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/mappers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/public/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/public/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/public/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/router.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/api/users/shared/schemas.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/analytics/bucket_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/analytics/prune_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/analytics/read_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/analytics/refresh_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/analytics/registry.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/analytics/sources/comment_created.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/analytics/sources/post_created.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/analytics/sources/post_viewed.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/analytics/sources/user_registered.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/auth/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/auth/access_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/auth/auth_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/auth/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/cache/invalidate_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/cache/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/comments/admin_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/comments/aggregation_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/comments/authenticated_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/comments/cleanup_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/comments/public_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/events/event_token.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/events/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/media/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/media/attachment_read.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/media/attachment_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/media/avatar_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/media/banner_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/media/ingest_guards.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/media/read_url_config.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/moderation/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/moderation/appeal_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/moderation/moderator_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/moderation/report_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/moderation/scheduled_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/moderation/user_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/notifications/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/notifications/enums.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/notifications/inbox_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/notifications/mute_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/notifications/notification_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/outbox/block_mirrors.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/outbox/events.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/outbox/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/outbox/follow_mirrors.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/outbox/handlers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/outbox/ops_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/outbox/polling_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/outbox/processing_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/outbox/restriction_mirrors.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/posts/admin_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/posts/aggregation_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/posts/authenticated_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/posts/cleanup_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/posts/public_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/shared/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/shared/enums.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/shared/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/shared/request_context.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/shared/worker_jobs.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/users/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/users/admin_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/users/aggregation_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/users/authenticated_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/users/deletion_audit.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/users/enums.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/users/public_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/users/scheduled_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/users/user_deletion_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/asgi.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/bundled_alembic.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/constants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/cache.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/context.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/database.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/exception_handlers/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/exception_handlers/application.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/exception_handlers/common.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/exception_handlers/setup.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/firebase.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/http_client.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/logging.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/middleware.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/observability.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/pagination.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/redis.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/runtime.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/core/settings.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/analytics/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/analytics/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/analytics/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/analytics/ports/activity_source.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/auth/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/auth/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/auth/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/auth/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/auth/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/auth/ports/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/auth/ports/auth.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/auth/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/comment/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/comment/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/comment/constants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/comment/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/comment/enums.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/comment/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/comment/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/comment/outcomes.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/comment/repository.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/comment/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/attachment/components/finals_publisher.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/attachment/components/staging.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/attachment/components/variant_encoder.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/attachment/constants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/attachment/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/attachment/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/attachment/ports/finals_publisher.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/attachment/ports/staging.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/attachment/ports/variant_encoder.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/attachment/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/components/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/components/finals_publisher.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/components/staging.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/components/variant_encoder.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/constants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/ports/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/ports/finals_publisher.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/ports/staging.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/ports/variant_encoder.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/avatar/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/banner/components/finals_publisher.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/banner/components/staging.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/banner/components/variant_encoder.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/banner/constants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/banner/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/banner/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/banner/ports/finals_publisher.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/banner/ports/staging.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/banner/ports/variant_encoder.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/banner/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/shared/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/shared/constants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/shared/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/shared/outcomes.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/shared/repository.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/shared/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/media/shared/utils.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/enums.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/outbox_repository.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/outbox_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/outcomes.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/repository.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/moderation/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/notification/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/notification/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/notification/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/notification/enums.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/notification/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/notification/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/notification/repository.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/notification/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/outbox/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/outbox/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/outbox/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/outbox/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/outbox/ports/admin.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/outbox/ports/consumer.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/outbox/ports/producer.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/outbox/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/post/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/post/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/post/constants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/post/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/post/enums.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/post/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/post/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/post/outcomes.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/post/repository.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/post/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/constants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/dependencies.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/enums.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/exceptions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/models.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/outbox_repository.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/outbox_service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/outcomes.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/repository.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/service.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/user/utils.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/utils.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/firebase/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/firebase/firebase_auth_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/attachment_staging_display_geometry.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/local_attachment_staging_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/local_banner_staging_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/local_staging_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/pillow_attachment_variant_encoder_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/pillow_avatar_variant_encoder_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/pillow_banner_variant_encoder_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/pillow_staging_image.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/ssh_attachment_finals_publisher_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/ssh_banner_finals_publisher_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/media/ssh_finals_publisher_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/outbox/outbox_consumer_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/infrastructure/outbox/outbox_producer_adapter.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/main.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/migrate_cli.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/arq.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/auth.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/config.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/containers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/firebase.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/firebase_identity_toolkit.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/hookspecs.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/httpx_test_client.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/media.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/migrations.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/testing/plugin.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/main.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/analytics_refresh_cron.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_aggregate_comment_stats.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_aggregate_post_stats.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_aggregate_user_stats.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_expired_account_deletions.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_expired_mute_lifts.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_poll_outbox.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_prune_analytics_daily_facts.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_prune_post_views.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_purge_expired_create_idempotency_keys.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_refresh_analytics.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_sweep_stale_attachment_staging.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_sweep_stale_avatar_staging.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/schedules/schedule_sweep_stale_banner_staging.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/delete_attachment_finals.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/delete_superseded_avatar_finals.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/delete_superseded_banner_finals.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_account_deletion.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_admin_user_deletion.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_aggregate_comment_stats.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_aggregate_post_stats.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_aggregate_user_stats.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_attachment_asset_variants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_banner_asset_variants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_cache_pattern_invalidation.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_destructive_comment_delete.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_destructive_post_delete.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_media_asset_variants.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_mute_lift.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_outbox_row.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_refresh_analytics_bucket.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/tasks/process_user_content_deletion.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/core_framework/worker/worker_context.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docker-compose.dev.yaml +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docker-compose.yml +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/dockerfile +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/deployments/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/deployments/deploy-playbook.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/deployments/e2e-smoke-tests-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/deployments/edge-upload-limits.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/deployments/examples/Caddyfile.example +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/deployments/examples/image-server-known-hosts.example +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/deployments/guides/postgres-setup.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/deployments/guides/redis-setup.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/deployments/release-playbook.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/design/analytics-rollup-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/design/cache-invalidation-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/design/create-idempotency-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/design/event-outbox-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/design/media-storage-topology.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/design/outbox-admin-ops-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/analytics/admin_analytics_reads.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/auth/access_control.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/auth/registration.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/cache/admin_cache_invalidation.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/comments/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/comments/admin_comments.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/comments/comment_like.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/comments/comment_report.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/comments/comment_stats_aggregation.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/comments/create_comment.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/comments/delete_comment.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/comments/edit_comment.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/comments/retrieve_comments.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/deletion/comments.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/deletion/overview.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/deletion/posts.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/deletion/users.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/media/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/media/attachment_upload.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/media/avatar-upload-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/media/banner-upload-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/media/post-comment-attachments-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/media/upload-pipeline-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/media/upload_pipeline.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/mentions/mentions_in_content.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/moderation/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/moderation/appeals.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/moderation/internal_notes.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/moderation/moderator_actions.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/moderation/reports.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/moderation/restrictions.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/notifications/notification_inbox.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/outbox/admin_outbox_ops.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/admin_posts.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/author_context.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/create_post.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/edit_post.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/hashtag_discovery.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/post_like.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/post_report.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/post_stats_aggregation.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/post_visibility.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/posts/retrieve_posts.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/account.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/account_deletion.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/admin_users.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/avatar.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/banner.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/blocks.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/change_history.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/check_username_exists.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/follow-system-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/follow.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/my_posts_and_comments.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/preferences.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/profile.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/public_profile.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/user_removal.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/domains/users/user_stats_aggregation.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/library/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/library/api.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/library/capability-wiring.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/library/overview.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/library/testing-plugin-design.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/library/workers.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/platform/README.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/platform/architecture-decisions.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/platform/client-error-visibility.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/platform/conventions.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/platform/database-triggers.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/platform/domain-services-and-adapters.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/platform/layers-and-boundaries.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/platform/patch-update-typed-payload.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/testing.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/docs/todo.md +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/firebase_config.example.json +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/makefile +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/conftest.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/_auth.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/_canaries.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/_media.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/_settings.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/_upload_payloads.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/conftest.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/media/pipeline_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/smoke/canary_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/smoke/media_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/smoke/system_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/e2e/smoke/tls_host_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/_http_error_details.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/analytics/_helpers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/_auth_helpers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/_destructive_delete_helpers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/_http_helpers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/_outbox_helpers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/_user_deletion_helpers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/_user_helpers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/_auth_cases.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/analytics/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/analytics/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/cache/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/cache/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/comments/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/comments/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/moderation/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/moderation/_auth_cases.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/moderation/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/outbox/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/outbox/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/posts/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/posts/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/users/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/admin/users/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/attachments/_helpers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/attachments/attachment_upload_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/auth/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/auth/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/comments/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/comments/authenticated/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/comments/authenticated/comment_writes_integration_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/comments/comment_attachments_integration_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/comments/public/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/comments/public/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/create_idempotency_integration_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/media/ingest_contract_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/mentions/mentions_integration_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/notifications/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/notifications/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/posts/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/posts/authenticated/post_writes_integration_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/posts/comment_count_aggregation_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/posts/followers_visibility_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/posts/post_attachments_integration_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/posts/post_deletion_integration_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/posts/post_stats_dirty_marking_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/posts/public/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/posts/public/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/public_read_by_id_unavailable_detail_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/system/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/system/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/users/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/users/authenticated/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/users/authenticated/avatar_upload_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/users/authenticated/banner_upload_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/users/authenticated/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/users/deletion_audit_integration_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/users/public/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/users/public/router_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/api/users/user_deletion_integration_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/_media_upload_helpers.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/account_deletion_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/aggregate_comment_stats_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/aggregate_post_stats_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/aggregate_user_stats_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/analytics_prune_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/analytics_refresh_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/attachment_upload_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/avatar_upload_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/banner_upload_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/conftest.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/create_idempotency_retention_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/moderation_outbox_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/mute_lift_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/stale_staging_sweep_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/user_outbox_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/integration/worker/utils_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/api/comments/authenticated/comment_request_schemas_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/api/dedupe_preserving_order_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/api/posts/authenticated/post_update_mapper_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/api/users/profile_update_mapper_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/application/comments/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/application/events/event_service_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/application/notifications/inbox_service_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/application/shared/request_context_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/application/users/deletion_audit_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/core/bundled_alembic_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/core/migrate_cli_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/core/pagination_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/docs/_api_reference.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/docs/api_routes_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/domains/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/domains/comment/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/domains/post/models_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/domains/user/service_test.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/infrastructure/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/infrastructure/media/__init__.py +0 -0
- {core_framework-2.3.2 → core_framework-2.3.3}/tests/unit/infrastructure/media/ssh_finals_publisher_adapter_test.py +0 -0
|
@@ -4,6 +4,33 @@ Notable changes to **core-framework** (import **`core_framework`**). Format foll
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.3.3] - 2026-07-05
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **UTM capture `kind`:** `POST /events` with `type: "utm_data"` requires a `kind`
|
|
12
|
+
item in `events[]` (`subject_type` `kind`, `subject` the capture context). Core
|
|
13
|
+
ships `registration`; hosts register additional kinds via
|
|
14
|
+
`register_utm_capture_kind`. See **`docs/design/utm-events-design.md`** and
|
|
15
|
+
**`docs/domains/events/events.md`**.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **`analytics` schema:** **`2d61a5e88d76_analytics_utm_events_add_kind`** — `utm_events.kind`
|
|
20
|
+
column and `idx_utm_events_kind_created_at`. **Deletes all existing `utm_events` rows**
|
|
21
|
+
before adding the column (legacy UTM-only rows are not backfilled). Run **`cf-alembic`**
|
|
22
|
+
when upgrading.
|
|
23
|
+
|
|
24
|
+
### Breaking
|
|
25
|
+
|
|
26
|
+
- **Breaking (clients — `utm_data`):** Batches without a valid `kind` item and at
|
|
27
|
+
least one allowlisted UTM key no longer persist. UTM-only payloads from 2.3.2
|
|
28
|
+
stop writing rows.
|
|
29
|
+
|
|
30
|
+
- **Breaking (operators — `utm_events` data):** Upgrading through
|
|
31
|
+
**`2d61a5e88d76_analytics_utm_events_add_kind`** clears **`analytics.utm_events`**
|
|
32
|
+
before the **`kind`** column is added.
|
|
33
|
+
|
|
7
34
|
## [2.3.2] - 2026-07-05
|
|
8
35
|
|
|
9
36
|
### Added
|
|
@@ -435,4 +462,5 @@ First **SemVer-stable** release per **`docs/library/package-api.md`**.
|
|
|
435
462
|
[2.3.0]: https://github.com/NepNepFFXIV/core-framework/compare/v2.2.0...v2.3.0
|
|
436
463
|
[2.3.1]: https://github.com/NepNepFFXIV/core-framework/compare/v2.3.0...v2.3.1
|
|
437
464
|
[2.3.2]: https://github.com/NepNepFFXIV/core-framework/compare/v2.3.1...v2.3.2
|
|
438
|
-
[
|
|
465
|
+
[2.3.3]: https://github.com/NepNepFFXIV/core-framework/compare/v2.3.2...v2.3.3
|
|
466
|
+
[unreleased]: https://github.com/NepNepFFXIV/core-framework/compare/v2.3.3...HEAD
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: core-framework
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.3
|
|
4
4
|
Summary: Core framework package (import as core_framework)
|
|
5
5
|
Project-URL: Homepage, https://github.com/NepNepFFXIV/core-framework
|
|
6
6
|
Project-URL: Repository, https://github.com/NepNepFFXIV/core-framework
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""analytics utm_events add capture kind column
|
|
2
|
+
|
|
3
|
+
Revision ID: 2d61a5e88d76
|
|
4
|
+
Revises: 585105e1149e
|
|
5
|
+
Create Date: 2026-07-05 13:30:00.000000
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from collections.abc import Sequence
|
|
10
|
+
|
|
11
|
+
from alembic import op
|
|
12
|
+
|
|
13
|
+
revision: str = "2d61a5e88d76"
|
|
14
|
+
down_revision: str | Sequence[str] | None = "585105e1149e"
|
|
15
|
+
branch_labels: str | Sequence[str] | None = None
|
|
16
|
+
depends_on: str | Sequence[str] | None = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade() -> None:
|
|
20
|
+
op.execute("delete from utm_events;")
|
|
21
|
+
op.execute("""
|
|
22
|
+
alter table utm_events
|
|
23
|
+
add column kind varchar(64) not null;
|
|
24
|
+
""")
|
|
25
|
+
op.execute("""
|
|
26
|
+
create index if not exists idx_utm_events_kind_created_at
|
|
27
|
+
on utm_events (kind, created_at);
|
|
28
|
+
""")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def downgrade() -> None:
|
|
32
|
+
op.execute("drop index if exists idx_utm_events_kind_created_at;")
|
|
33
|
+
op.execute("""
|
|
34
|
+
alter table utm_events
|
|
35
|
+
drop column if exists kind;
|
|
36
|
+
""")
|
|
@@ -2,6 +2,7 @@ import core_framework.domains.moderation.dependencies as moderation_deps
|
|
|
2
2
|
import core_framework.domains.user.dependencies as user_deps
|
|
3
3
|
from core_framework.application.analytics.registry import configure_activity_sources
|
|
4
4
|
from core_framework.application.events.event_service import configure_event_handlers
|
|
5
|
+
from core_framework.application.events.utm_capture_kinds import configure_utm_capture_kinds
|
|
5
6
|
from core_framework.application.shared.worker_jobs import configure_worker_jobs
|
|
6
7
|
from core_framework.core.cache import configure_cashews_backend
|
|
7
8
|
from core_framework.core.runtime import CoreRuntime
|
|
@@ -19,6 +20,7 @@ from core_framework.domains.user.dependencies import configure_user_dependencies
|
|
|
19
20
|
def configure_application_dependencies(*, runtime: CoreRuntime) -> None:
|
|
20
21
|
"""Wire application-level dependencies from the shared runtime."""
|
|
21
22
|
configure_event_handlers()
|
|
23
|
+
configure_utm_capture_kinds()
|
|
22
24
|
configure_activity_sources()
|
|
23
25
|
configure_worker_jobs(runtime=runtime)
|
|
24
26
|
configure_cashews_backend(redis_cache_url=runtime.settings.redis.redis_cache_url)
|
|
@@ -16,7 +16,9 @@ Platform design and host extension: `docs/design/events-ingest-design.md`.
|
|
|
16
16
|
## Host extension
|
|
17
17
|
|
|
18
18
|
- `register_event_handler(event_type, handler)` — append a handler after `configure_application_dependencies`
|
|
19
|
-
- `
|
|
19
|
+
- `register_utm_capture_kind(kind)` — append a `utm_data` capture kind after `configure_application_dependencies`
|
|
20
|
+
- `configure_event_handlers()` — reset handler registry and register core built-ins
|
|
21
|
+
- `configure_utm_capture_kinds()` — reset capture-kind registry and seed core kinds (`registration`)
|
|
20
22
|
- `type` and `subject_type` are plain strings at the schema boundary
|
|
21
23
|
- Each handler receives the full batch and filters its own `subject_type` values
|
|
22
24
|
|
{core_framework-2.3.2 → core_framework-2.3.3}/core_framework/application/events/event_service.py
RENAMED
|
@@ -6,9 +6,10 @@ import core_framework.domains.analytics.dependencies as analytics_deps
|
|
|
6
6
|
import core_framework.domains.post.dependencies as post_deps
|
|
7
7
|
import core_framework.domains.user.dependencies as user_deps
|
|
8
8
|
from core_framework.application.events.models import Event
|
|
9
|
+
from core_framework.application.events.utm_capture_kinds import get_utm_capture_kinds
|
|
9
10
|
from core_framework.application.posts.aggregation_service import mark_post_stats_dirty
|
|
10
11
|
from core_framework.application.shared.enums import EventType, SubjectType
|
|
11
|
-
from core_framework.domains.analytics import UTM_ALLOWLISTED_KEYS
|
|
12
|
+
from core_framework.domains.analytics import MAX_UTM_KIND_LENGTH, UTM_ALLOWLISTED_KEYS, UTM_KIND_SUBJECT_TYPE
|
|
12
13
|
|
|
13
14
|
logger = get_logger(__name__)
|
|
14
15
|
|
|
@@ -76,8 +77,12 @@ async def record_signup_events(*, events: list[Event], token: str, request_conte
|
|
|
76
77
|
|
|
77
78
|
async def record_utm_events(*, events: list[Event], token: str, request_context: dict[str, str]) -> None:
|
|
78
79
|
"""Persist UTM attribution from batched client events."""
|
|
80
|
+
capture_kind: str | None = None
|
|
79
81
|
utm: dict[str, str] = {}
|
|
80
82
|
for event in events:
|
|
83
|
+
if event.subject_type == UTM_KIND_SUBJECT_TYPE:
|
|
84
|
+
capture_kind = event.subject
|
|
85
|
+
continue
|
|
81
86
|
if event.subject_type in UTM_ALLOWLISTED_KEYS:
|
|
82
87
|
utm[event.subject_type] = event.subject
|
|
83
88
|
continue
|
|
@@ -85,9 +90,19 @@ async def record_utm_events(*, events: list[Event], token: str, request_context:
|
|
|
85
90
|
"UTM event item ignored: unknown subject_type",
|
|
86
91
|
subject_type=event.subject_type,
|
|
87
92
|
)
|
|
93
|
+
normalized_kind: str | None = None
|
|
94
|
+
if capture_kind is not None:
|
|
95
|
+
trimmed_kind = capture_kind.strip()
|
|
96
|
+
if trimmed_kind:
|
|
97
|
+
normalized_kind = trimmed_kind[:MAX_UTM_KIND_LENGTH]
|
|
98
|
+
if normalized_kind is None or normalized_kind not in get_utm_capture_kinds():
|
|
99
|
+
return
|
|
100
|
+
if not any(value.strip() for value in utm.values()):
|
|
101
|
+
return
|
|
88
102
|
try:
|
|
89
103
|
await analytics_deps.analytics_service.add_utm_event(
|
|
90
104
|
token=token,
|
|
105
|
+
kind=normalized_kind,
|
|
91
106
|
utm=utm,
|
|
92
107
|
user_id=request_context.get("viewer_id"),
|
|
93
108
|
client_context=request_context,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from typing import Final
|
|
2
|
+
|
|
3
|
+
from core_framework.domains.analytics import MAX_UTM_KIND_LENGTH
|
|
4
|
+
|
|
5
|
+
CORE_UTM_CAPTURE_KIND_REGISTRATION: Final[str] = "registration"
|
|
6
|
+
|
|
7
|
+
_utm_capture_kinds: set[str] = set()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def configure_utm_capture_kinds() -> None:
|
|
11
|
+
"""Reset the capture-kind registry and register core built-in kinds."""
|
|
12
|
+
global _utm_capture_kinds
|
|
13
|
+
_utm_capture_kinds = {CORE_UTM_CAPTURE_KIND_REGISTRATION}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def register_utm_capture_kind(kind: str) -> None:
|
|
17
|
+
"""Register one ``utm_data`` capture kind (host extension point)."""
|
|
18
|
+
trimmed = kind.strip()
|
|
19
|
+
if not trimmed:
|
|
20
|
+
raise ValueError("utm capture kind must not be empty or whitespace-only")
|
|
21
|
+
if len(trimmed) > MAX_UTM_KIND_LENGTH:
|
|
22
|
+
raise ValueError(f"utm capture kind exceeds max length ({MAX_UTM_KIND_LENGTH})")
|
|
23
|
+
if trimmed in _utm_capture_kinds:
|
|
24
|
+
raise ValueError(f"duplicate utm capture kind: {trimmed!r}")
|
|
25
|
+
_utm_capture_kinds.add(trimmed)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_utm_capture_kinds() -> frozenset[str]:
|
|
29
|
+
"""Return registered capture kinds for ``utm_data`` ingest."""
|
|
30
|
+
return frozenset(_utm_capture_kinds)
|
|
@@ -35,7 +35,8 @@ Host registration (Phase 8) is documented in the design doc for consuming applic
|
|
|
35
35
|
#### utm_events
|
|
36
36
|
|
|
37
37
|
- Append-only UTM attribution captures from `POST /events` with `type: "utm_data"`
|
|
38
|
-
- Columns: `id`, `created_at`, `token`, optional `user_id`, `utm` jsonb, `request_context` jsonb
|
|
39
|
-
- `
|
|
38
|
+
- Columns: `id`, `created_at`, `token`, optional `user_id`, `kind`, `utm` jsonb, `request_context` jsonb
|
|
39
|
+
- `kind` names the capture context (for example `registration`); distinct from `daily_fact.kind`
|
|
40
|
+
- `utm` holds folded client UTM key/value pairs only; `request_context` holds server-derived metadata (same shape as login telemetry)
|
|
40
41
|
- No dedup on `token` — each accepted ingest may append a row
|
|
41
42
|
- Design: `docs/design/utm-events-design.md`
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from core_framework.domains.analytics.constants import (
|
|
2
2
|
DAILY_FACT_RETENTION_DAYS,
|
|
3
|
+
MAX_UTM_KIND_LENGTH,
|
|
3
4
|
UTM_ALLOWLISTED_KEYS,
|
|
5
|
+
UTM_KIND_SUBJECT_TYPE,
|
|
4
6
|
)
|
|
5
7
|
from core_framework.domains.analytics.exceptions import BaseAnalyticsException
|
|
6
8
|
from core_framework.domains.analytics.models import DailyFactBucket, DailyFactDayTotal, DailyFactKindTotal
|
|
@@ -14,5 +16,7 @@ __all__ = [
|
|
|
14
16
|
"DailyFactBucket",
|
|
15
17
|
"DailyFactDayTotal",
|
|
16
18
|
"DailyFactKindTotal",
|
|
19
|
+
"MAX_UTM_KIND_LENGTH",
|
|
17
20
|
"UTM_ALLOWLISTED_KEYS",
|
|
21
|
+
"UTM_KIND_SUBJECT_TYPE",
|
|
18
22
|
]
|
{core_framework-2.3.2 → core_framework-2.3.3}/core_framework/domains/analytics/repository.py
RENAMED
|
@@ -235,6 +235,7 @@ class AnalyticsRepository:
|
|
|
235
235
|
*,
|
|
236
236
|
token: str,
|
|
237
237
|
user_id: str | None,
|
|
238
|
+
kind: str,
|
|
238
239
|
utm: dict[str, str],
|
|
239
240
|
client_context: dict[str, str],
|
|
240
241
|
) -> None:
|
|
@@ -244,6 +245,7 @@ class AnalyticsRepository:
|
|
|
244
245
|
Args:
|
|
245
246
|
token: Event ingest token from the client request.
|
|
246
247
|
user_id: Authenticated user id when present; otherwise ``None``.
|
|
248
|
+
kind: Capture context for this attribution row.
|
|
247
249
|
utm: Normalized UTM key/value pairs for jsonb storage.
|
|
248
250
|
client_context: Server-derived request metadata.
|
|
249
251
|
|
|
@@ -251,8 +253,8 @@ class AnalyticsRepository:
|
|
|
251
253
|
None.
|
|
252
254
|
"""
|
|
253
255
|
query = f"""
|
|
254
|
-
insert into {self.schema_sql}.utm_events (token, user_id, utm, request_context)
|
|
255
|
-
values ($1, $2, $3::jsonb, $
|
|
256
|
+
insert into {self.schema_sql}.utm_events (token, user_id, kind, utm, request_context)
|
|
257
|
+
values ($1, $2, $3, $4::jsonb, $5::jsonb)
|
|
256
258
|
"""
|
|
257
259
|
async with self.write_database.get_connection() as connection:
|
|
258
|
-
await connection.execute(query, token, user_id, utm, client_context)
|
|
260
|
+
await connection.execute(query, token, user_id, kind, utm, client_context)
|
|
@@ -5,6 +5,7 @@ from structlog import get_logger
|
|
|
5
5
|
|
|
6
6
|
from core_framework.domains.analytics.constants import (
|
|
7
7
|
DAILY_FACT_RETENTION_DAYS,
|
|
8
|
+
MAX_UTM_KIND_LENGTH,
|
|
8
9
|
MAX_UTM_VALUE_LENGTH,
|
|
9
10
|
UTM_ALLOWLISTED_KEYS,
|
|
10
11
|
)
|
|
@@ -229,30 +230,36 @@ class AnalyticsService:
|
|
|
229
230
|
self,
|
|
230
231
|
*,
|
|
231
232
|
token: str,
|
|
233
|
+
kind: str,
|
|
232
234
|
utm: dict[str, str],
|
|
233
235
|
user_id: str | None,
|
|
234
236
|
client_context: dict[str, str],
|
|
235
237
|
) -> bool:
|
|
236
238
|
"""
|
|
237
|
-
Persist one UTM attribution capture when normalized payload is
|
|
239
|
+
Persist one UTM attribution capture when normalized payload is valid.
|
|
238
240
|
|
|
239
241
|
Args:
|
|
240
242
|
token: Event ingest token from the client request.
|
|
243
|
+
kind: Capture context from the ingest batch.
|
|
241
244
|
utm: Folded UTM key/value pairs from the ingest batch.
|
|
242
245
|
user_id: Authenticated user id when present; otherwise ``None``.
|
|
243
246
|
client_context: Server-derived request metadata.
|
|
244
247
|
|
|
245
248
|
Returns:
|
|
246
|
-
``True`` when a row was inserted; ``False`` when validation
|
|
249
|
+
``True`` when a row was inserted; ``False`` when validation fails.
|
|
247
250
|
"""
|
|
248
|
-
require_non_blank_kwargs(token=token)
|
|
251
|
+
require_non_blank_kwargs(token=token, kind=kind)
|
|
249
252
|
require_non_blank_if_not_none(user_id=user_id)
|
|
253
|
+
normalized_kind = _normalize_capture_kind(kind)
|
|
254
|
+
if not normalized_kind:
|
|
255
|
+
return False
|
|
250
256
|
normalized_utm = _normalize_utm_payload(utm)
|
|
251
257
|
if not normalized_utm:
|
|
252
258
|
return False
|
|
253
259
|
await self.repository.insert_utm_event(
|
|
254
260
|
token=token,
|
|
255
261
|
user_id=user_id,
|
|
262
|
+
kind=normalized_kind,
|
|
256
263
|
utm=normalized_utm,
|
|
257
264
|
client_context=client_context,
|
|
258
265
|
)
|
|
@@ -263,6 +270,13 @@ def _start_of_utc_day(day: date) -> datetime:
|
|
|
263
270
|
return datetime.combine(day, time.min, tzinfo=timezone.utc)
|
|
264
271
|
|
|
265
272
|
|
|
273
|
+
def _normalize_capture_kind(kind: str) -> str | None:
|
|
274
|
+
trimmed = kind.strip()
|
|
275
|
+
if not trimmed:
|
|
276
|
+
return None
|
|
277
|
+
return trimmed[:MAX_UTM_KIND_LENGTH]
|
|
278
|
+
|
|
279
|
+
|
|
266
280
|
def _normalize_utm_payload(utm: dict[str, str]) -> dict[str, str]:
|
|
267
281
|
normalized: dict[str, str] = {}
|
|
268
282
|
for key, value in utm.items():
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# App server deploy SSH
|
|
2
|
+
|
|
3
|
+
Wire GitHub Actions SSH deploy to the **app server** deploy user. This guide generates
|
|
4
|
+
the key on your **laptop** (`deploy-to-app-server`). For server-side generation during
|
|
5
|
+
[ubuntu-server-setup.md](ubuntu-server-setup.md) section 5 (`~/.ssh/id_ed25519` on the
|
|
6
|
+
deploy user), paste `cat ~/.ssh/id_ed25519` into the same GitHub secret instead — there
|
|
7
|
+
is no `deploy-to-app-server` file in that path.
|
|
8
|
+
|
|
9
|
+
| Machine | Role in this guide |
|
|
10
|
+
| -------------- | ------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| **Laptop** | Generate keys, install public key via SSH, verify, paste GitHub secrets |
|
|
12
|
+
| **App server** | Receives the public key in `/home/{USER}/.ssh/authorized_keys` — no manual shell commands in this guide |
|
|
13
|
+
|
|
14
|
+
GitHub → Environments → **`development`** / **`production`**:
|
|
15
|
+
|
|
16
|
+
**Variables**
|
|
17
|
+
|
|
18
|
+
- **`DEPLOY_SERVER_HOST`**
|
|
19
|
+
- **`DEPLOY_SERVER_PORT`**
|
|
20
|
+
- **`DEPLOY_SERVER_USER`** — deploy user; must be in **`docker`** group
|
|
21
|
+
|
|
22
|
+
**Secrets**
|
|
23
|
+
|
|
24
|
+
- **`DEPLOY_SERVER_SSH_KEY`** — contents of **`deploy-to-app-server`** (laptop path) or **`~/.ssh/id_ed25519`** (ubuntu-server-setup path)
|
|
25
|
+
|
|
26
|
+
______________________________________________________________________
|
|
27
|
+
|
|
28
|
+
## 1. Generate key pair
|
|
29
|
+
|
|
30
|
+
**Where:** your **laptop** (creates `deploy-to-app-server` and `deploy-to-app-server.pub` in the current directory).
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
ssh-keygen -t ed25519 -f deploy-to-app-server -N ""
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
______________________________________________________________________
|
|
37
|
+
|
|
38
|
+
## 2. Install public key on app server
|
|
39
|
+
|
|
40
|
+
**Where:** your **laptop** — SSHs into the **app server** as `root` and configures the deploy user.
|
|
41
|
+
|
|
42
|
+
Install the public key:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
ssh -p {PORT} root@{HOST} "mkdir -p /home/{USER}/.ssh && chmod 700 /home/{USER}/.ssh && cat >> /home/{USER}/.ssh/authorized_keys && chmod 600 /home/{USER}/.ssh/authorized_keys && chown -R {USER}:{USER} /home/{USER}/.ssh" < deploy-to-app-server.pub
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Add the deploy user to the **`docker`** group (required for deploy):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
ssh -p {PORT} root@{HOST} "usermod -aG docker {USER}"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
______________________________________________________________________
|
|
55
|
+
|
|
56
|
+
## 3. Add config to GitHub
|
|
57
|
+
|
|
58
|
+
**Where:** your **laptop** — copy the private key, then paste in the GitHub UI.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
cat deploy-to-app-server
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Paste into **`DEPLOY_SERVER_SSH_KEY`** (environment **secret**). Set **`DEPLOY_SERVER_HOST`**, **`DEPLOY_SERVER_PORT`**, and **`DEPLOY_SERVER_USER`** as environment **variables** (same **`{HOST}`** / **`{PORT}`** / **`{USER}`** as above).
|
|
65
|
+
|
|
66
|
+
______________________________________________________________________
|
|
67
|
+
|
|
68
|
+
## 4. Verify
|
|
69
|
+
|
|
70
|
+
**Where:** your **laptop**.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
ssh -i deploy-to-app-server -p {PORT} {USER}@{HOST}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A shell on the app server as the deploy user means the setup is correct.
|
|
77
|
+
|
|
78
|
+
______________________________________________________________________
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Image server SSH
|
|
2
|
+
|
|
3
|
+
Wire SSH from the **app server** (worker) to the **image server** (`root`). Keys are
|
|
4
|
+
generated on your **laptop**; the public key is installed on the image server; the
|
|
5
|
+
private key and host fingerprint go to GitHub for deploy.
|
|
6
|
+
|
|
7
|
+
| Machine | Role in this guide |
|
|
8
|
+
| ---------------- | ---------------------------------------------------------------------------- |
|
|
9
|
+
| **Laptop** | Generate keys, `ssh-keyscan`, paste GitHub secrets |
|
|
10
|
+
| **Image server** | Receives the public key in `/root/.ssh/authorized_keys` — no manual commands |
|
|
11
|
+
| **App server** | Optional verify step (step 5) |
|
|
12
|
+
|
|
13
|
+
GitHub → Environments → **`development`** / **`production`**:
|
|
14
|
+
|
|
15
|
+
**Variables**
|
|
16
|
+
|
|
17
|
+
- **`IMAGE_SERVER_HOST`**
|
|
18
|
+
- **`IMAGE_SERVER_PORT`**
|
|
19
|
+
- **`IMAGE_SERVER_USER`** — **`root`**
|
|
20
|
+
|
|
21
|
+
**Secrets**
|
|
22
|
+
|
|
23
|
+
- **`IMAGE_SERVER_SSH_PRIVATE_KEY`** — contents of **`worker-to-image-server`**
|
|
24
|
+
- **`IMAGE_SERVER_KNOWN_HOSTS`** — output of **`ssh-keyscan`** (step 3); trust anchor, not a credential
|
|
25
|
+
|
|
26
|
+
______________________________________________________________________
|
|
27
|
+
|
|
28
|
+
## 1. Generate key pair
|
|
29
|
+
|
|
30
|
+
**Where:** your **laptop** (creates `worker-to-image-server` and `worker-to-image-server.pub` in the current directory).
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
ssh-keygen -t ed25519 -f worker-to-image-server -N ""
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
______________________________________________________________________
|
|
37
|
+
|
|
38
|
+
## 2. Install public key on image server
|
|
39
|
+
|
|
40
|
+
**Where:** your **laptop** — SSHs into the **image server** and appends the public key to `authorized_keys`.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
ssh -p {PORT} root@{HOST} "mkdir -p /root/.ssh && chmod 700 /root/.ssh && cat >> /root/.ssh/authorized_keys && chmod 600 /root/.ssh/authorized_keys" < worker-to-image-server.pub
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
______________________________________________________________________
|
|
47
|
+
|
|
48
|
+
## 3. Get `IMAGE_SERVER_KNOWN_HOSTS`
|
|
49
|
+
|
|
50
|
+
**Where:** your **laptop**.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
ssh-keyscan -p {PORT} {HOST}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Paste all output into GitHub environment secret **`IMAGE_SERVER_KNOWN_HOSTS`**. Use the same **`{HOST}`** / **`{PORT}`** as the other image-server settings.
|
|
57
|
+
|
|
58
|
+
______________________________________________________________________
|
|
59
|
+
|
|
60
|
+
## 4. Add secrets to GitHub
|
|
61
|
+
|
|
62
|
+
**Where:** your **laptop** — copy the private key, then paste in the GitHub UI (step 3 output → **`IMAGE_SERVER_KNOWN_HOSTS`**, below → **`IMAGE_SERVER_SSH_PRIVATE_KEY`**).
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cat worker-to-image-server
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Paste into **`IMAGE_SERVER_SSH_PRIVATE_KEY`**.
|
|
69
|
+
|
|
70
|
+
______________________________________________________________________
|
|
71
|
+
|
|
72
|
+
## 5. Verify
|
|
73
|
+
|
|
74
|
+
**Where:** **app server** — confirms the worker host can reach the image server with this key.
|
|
75
|
+
|
|
76
|
+
Copy the private key from your laptop to the app server:
|
|
77
|
+
|
|
78
|
+
**Laptop:**
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
scp -P {DEPLOY_SERVER_PORT} worker-to-image-server {DEPLOY_SERVER_USER}@{APP_SERVER_HOST}:~/
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**App server:**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
chmod 600 ~/worker-to-image-server
|
|
88
|
+
ssh -i ~/worker-to-image-server -p {PORT} root@{HOST}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
A shell on the image server means the setup is correct. You can delete `~/worker-to-image-server` on the app server after testing — deploy uses the GitHub secret, not this file.
|
|
92
|
+
|
|
93
|
+
______________________________________________________________________
|
|
@@ -7,16 +7,16 @@ a capability is built, not day-to-day coding rules.
|
|
|
7
7
|
**Rules** (conventions, layering, ADRs) live in [`../platform/`](../platform/).
|
|
8
8
|
**Product flows** and per-domain feature design live in [`../domains/`](../domains/).
|
|
9
9
|
|
|
10
|
-
| Doc | Purpose
|
|
11
|
-
| -------------------------------------------------------------- |
|
|
12
|
-
| [`event-outbox-design.md`](event-outbox-design.md) | Transactional outbox (mirror fanout)
|
|
13
|
-
| [`events-ingest-design.md`](events-ingest-design.md) | Client events ingest — host-extensible handler dispatch
|
|
14
|
-
| [`analytics-rollup-design.md`](analytics-rollup-design.md) | Analytics rollup domain — time-bucketed activity rollups
|
|
15
|
-
| [`utm-events-design.md`](utm-events-design.md) | UTM attribution ingest — `utm_data` on `POST /events`, `analytics.utm_events` |
|
|
16
|
-
| [`outbox-admin-ops-design.md`](outbox-admin-ops-design.md) | Admin API: list dead outbox rows, replay one row
|
|
17
|
-
| [`create-idempotency-design.md`](create-idempotency-design.md) | HTTP create idempotency for post/comment create
|
|
18
|
-
| [`cache-invalidation-design.md`](cache-invalidation-design.md) | Cache invalidation — write-path, admin API, planned events hints
|
|
19
|
-
| [`media-storage-topology.md`](media-storage-topology.md) | Rack media layout: staging vs finals; no S3/R2
|
|
10
|
+
| Doc | Purpose |
|
|
11
|
+
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
12
|
+
| [`event-outbox-design.md`](event-outbox-design.md) | Transactional outbox (mirror fanout) |
|
|
13
|
+
| [`events-ingest-design.md`](events-ingest-design.md) | Client events ingest — host-extensible handler dispatch |
|
|
14
|
+
| [`analytics-rollup-design.md`](analytics-rollup-design.md) | Analytics rollup domain — time-bucketed activity rollups |
|
|
15
|
+
| [`utm-events-design.md`](utm-events-design.md) | UTM attribution ingest — `utm_data` on `POST /events`, `analytics.utm_events`, capture `kind` |
|
|
16
|
+
| [`outbox-admin-ops-design.md`](outbox-admin-ops-design.md) | Admin API: list dead outbox rows, replay one row |
|
|
17
|
+
| [`create-idempotency-design.md`](create-idempotency-design.md) | HTTP create idempotency for post/comment create |
|
|
18
|
+
| [`cache-invalidation-design.md`](cache-invalidation-design.md) | Cache invalidation — write-path, admin API, planned events hints |
|
|
19
|
+
| [`media-storage-topology.md`](media-storage-topology.md) | Rack media layout: staging vs finals; no S3/R2 |
|
|
20
20
|
|
|
21
21
|
When adding a new cross-cutting mechanism, add a `*-design.md` here and a client
|
|
22
22
|
flow doc under `docs/domains/` when the HTTP surface is ready.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Client Events Ingest — Host-Extensible Design
|
|
2
2
|
|
|
3
|
-
**Status:** **Shipped
|
|
3
|
+
**Status:** **Shipped** for core event types **`impression`**, **`login`**, **`signup`**, and
|
|
4
|
+
**`utm_data`** (including capture **`kind`** on UTM rows). Hosts may register additional
|
|
5
|
+
event types and `utm_data` capture kinds at bootstrap. Application-level rate limiting
|
|
6
|
+
is **not** implemented — use edge limits and client-side batching (see
|
|
7
|
+
[`events.md`](../domains/events/events.md)).
|
|
4
8
|
|
|
5
9
|
Core provides a generic, token-gated, client-initiated channel for **eventually
|
|
6
10
|
consistent side effects**. Clients fetch a signed token and post a batch; the
|
|
@@ -108,21 +112,22 @@ ______________________________________________________________________
|
|
|
108
112
|
| Built-in `impression` | Filters `subject_type == "post"`; dedup by `(post_id, token)`; marks post dirty on new row |
|
|
109
113
|
| Built-in `login` | Uses `viewer_id` from request context (not the payload); auto-provisions application user row when missing |
|
|
110
114
|
| Built-in `signup` | Uses `viewer_id` from request context (not the payload) |
|
|
111
|
-
| Built-in `utm_data` |
|
|
115
|
+
| Built-in `utm_data` | Extracts `kind`, folds allowlisted UTM items into `analytics.utm_events`; append-all; optional auth — see [utm-events-design.md](utm-events-design.md) |
|
|
112
116
|
|
|
113
117
|
`EventType` / `SubjectType` StrEnums in `core_framework/application/shared/enums.py`
|
|
114
118
|
are **internal constants** for core handler registration only — not schema validators.
|
|
115
119
|
|
|
116
120
|
### Code locations
|
|
117
121
|
|
|
118
|
-
| Piece
|
|
119
|
-
|
|
|
120
|
-
| Schema
|
|
121
|
-
| Model
|
|
122
|
-
| Token
|
|
123
|
-
| Handler registry
|
|
124
|
-
|
|
|
125
|
-
|
|
|
122
|
+
| Piece | Location |
|
|
123
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
124
|
+
| Schema | `core_framework/api/events/schemas.py` |
|
|
125
|
+
| Model | `core_framework/application/events/models.py` |
|
|
126
|
+
| Token | `core_framework/application/events/event_token.py` |
|
|
127
|
+
| Handler registry | `core_framework/application/events/event_service.py` |
|
|
128
|
+
| UTM capture-kind registry | `core_framework/application/events/utm_capture_kinds.py` |
|
|
129
|
+
| Route | `core_framework/api/events/router.py` |
|
|
130
|
+
| Bootstrap | `configure_event_handlers()` and `configure_utm_capture_kinds()` in `core_framework/application/bootstrap.py` |
|
|
126
131
|
|
|
127
132
|
______________________________________________________________________
|
|
128
133
|
|
|
@@ -163,6 +168,24 @@ A host **impression** handler should:
|
|
|
163
168
|
Core never imports host code. The host owns its `type` and `subject_type` string
|
|
164
169
|
literals.
|
|
165
170
|
|
|
171
|
+
### `utm_data` capture kinds
|
|
172
|
+
|
|
173
|
+
Hosts extend the **`utm_data`** capture-kind allowlist without a core release:
|
|
174
|
+
|
|
175
|
+
1. Call `register_utm_capture_kind(kind)` after `configure_application_dependencies`
|
|
176
|
+
(same bootstrap timing as `register_event_handler`).
|
|
177
|
+
1. Document the new `kind` string in host flow docs — core documents `registration`
|
|
178
|
+
only in [events.md](../domains/events/events.md).
|
|
179
|
+
1. Clients send the `kind` as an `events[]` item with `subject_type` `kind` and
|
|
180
|
+
`subject` set to the registered string, plus at least one allowlisted UTM item.
|
|
181
|
+
|
|
182
|
+
Core resets and seeds `registration` in `configure_utm_capture_kinds()` during
|
|
183
|
+
application bootstrap. The single core `utm_data` handler enforces the merged
|
|
184
|
+
allowlist; hosts do not register a second handler for additional kinds.
|
|
185
|
+
|
|
186
|
+
See [utm-events-design.md](utm-events-design.md) for persistence rules (`kind` and
|
|
187
|
+
non-empty `utm` both required).
|
|
188
|
+
|
|
166
189
|
### Dispatch semantics
|
|
167
190
|
|
|
168
191
|
- All handlers for the event type are scheduled as separate `BackgroundTasks` entries; they run **one after another** after the response (not concurrently).
|
|
@@ -194,6 +217,7 @@ ______________________________________________________________________
|
|
|
194
217
|
| `EventType` / `SubjectType` as internal constants only | Core handlers use named constants; schema does not gate hosts |
|
|
195
218
|
| Single global token max-age | Token is type-agnostic; one expiry for all event types |
|
|
196
219
|
| Multi-handler registry keyed by string | Hosts attach to existing or new event types without core imports |
|
|
220
|
+
| `register_utm_capture_kind` for `utm_data` | Hosts add funnel capture kinds without core releases; single handler and `analytics.utm_events` table |
|
|
197
221
|
| Each handler filters its own subject types | Post and host handlers coexist on `impression` |
|
|
198
222
|
| Unknown types accepted as 202, no-op | Typos do not 422; safe for fire-and-forget |
|
|
199
223
|
| `(subject, token)` dedup for impression handlers | Same semantics as post views |
|