1212from fastapi import FastAPI
1313
1414from config import AppSettings
15+ from infrastructure .cache .entitlement_cache import EntitlementCache
1516from infrastructure .cache .feature_flag_cache import FeatureFlagCache
1617from infrastructure .cache .meta_fetch_cache import MetaFetchCache
1718from infrastructure .cache .onboarding_cache import OnboardingCache
3738from repositories .blocked_url_repository import BlockedUrlRepository
3839from repositories .click_repository import ClickRepository
3940from repositories .custom_domain_repository import CustomDomainRepository
41+ from repositories .entitlement_event_repository import EntitlementEventRepository
42+ from repositories .entitlement_override_repository import (
43+ EntitlementOverrideRepository ,
44+ )
4045from repositories .feature_flag_repository import FeatureFlagRepository
4146from repositories .feed_domain_repository import FeedDomainRepository
4247from repositories .legacy .emoji_url_repository import EmojiUrlRepository
4752 ReportSubmissionRepository ,
4853)
4954from repositories .scheduled_task_repository import ScheduledTaskRepository
55+ from repositories .subscription_repository import SubscriptionRepository
5056from repositories .tag_repository import TagRepository
5157from repositories .token_repository import TokenRepository
5258from repositories .url_repository import UrlRepository
7985from services .custom_domain_service import CustomDomainService
8086from services .domain_intel_service import DomainIntelService
8187from services .edge_cache .og_writethrough import OgEdgeWritethrough
88+ from services .entitlements import EntitlementService
8289from services .events .sinks import (
8390 InlineDomainEventSink ,
8491 NullDomainEventSink ,
@@ -258,6 +265,47 @@ def build_posthog_eraser(settings: AppSettings, http_client) -> PostHogEraser:
258265 )
259266
260267
268+ def build_entitlement_store (
269+ db , redis_client
270+ ) -> tuple [
271+ EntitlementCache ,
272+ EntitlementEventRepository ,
273+ SubscriptionRepository ,
274+ EntitlementOverrideRepository ,
275+ ]:
276+ """The three entitlement repositories sharing one cache, so every write
277+ to subscriptions or overrides invalidates the same ``ent:{id}`` key."""
278+ cache = EntitlementCache (redis_client )
279+ events = EntitlementEventRepository (db ["entitlement_events" ])
280+ subscriptions = SubscriptionRepository (db ["subscriptions" ], events , cache )
281+ overrides = EntitlementOverrideRepository (
282+ db ["entitlement_overrides" ], events , cache
283+ )
284+ return cache , events , subscriptions , overrides
285+
286+
287+ def build_entitlement_service (
288+ db , settings : AppSettings , redis_client
289+ ) -> EntitlementService :
290+ cache , events , subscriptions , overrides = build_entitlement_store (db , redis_client )
291+ return EntitlementService (
292+ subscriptions ,
293+ overrides ,
294+ events ,
295+ cache ,
296+ selfhost = settings .billing .selfhost ,
297+ usage = {
298+ "custom_domains_max" : CustomDomainRepository (
299+ db ["custom_domains" ]
300+ ).count_by_owner ,
301+ "webhook_endpoints_max" : WebhookEndpointRepository (
302+ db ["webhook-endpoints" ]
303+ ).count_by_user ,
304+ "api_keys_max" : ApiKeyRepository (db ["api-keys" ]).count_by_user ,
305+ },
306+ )
307+
308+
261309def build_account_erasure_service (
262310 db ,
263311 settings : AppSettings ,
@@ -355,6 +403,9 @@ def build_account_erasure_service(
355403 redis_client = redis_client ,
356404 url_service = url_service ,
357405 )
406+ _ , ent_events , subscription_repo , override_repo = build_entitlement_store (
407+ db , redis_client
408+ )
358409
359410 return AccountErasureService (
360411 user_repo = user_repo ,
@@ -372,6 +423,9 @@ def build_account_erasure_service(
372423 report_repo = ReportRepository (db ["reports" ]),
373424 report_submission_repo = ReportSubmissionRepository (db ["report_submissions" ]),
374425 feature_flag_repo = FeatureFlagRepository (db ["feature_flags" ]),
426+ subscription_repo = subscription_repo ,
427+ override_repo = override_repo ,
428+ entitlement_event_repo = ent_events ,
375429 r2_storage = r2_storage ,
376430 posthog = build_posthog_eraser (settings , http_client ),
377431 mailer = build_erasure_mailer (settings , http_client ),
@@ -403,6 +457,12 @@ def wire_services(app: FastAPI, settings: AppSettings, redis_client) -> None:
403457 blocked_url_repo = BlockedUrlRepository (db ["blocked-urls" ])
404458 app_grant_repo = AppGrantRepository (db ["app-grants" ])
405459 feature_flag_repo = FeatureFlagRepository (db ["feature_flags" ])
460+ _ , ent_events , subscription_repo , override_repo = build_entitlement_store (
461+ db , redis_client
462+ )
463+ app .state .entitlement_service = build_entitlement_service (
464+ db , settings , redis_client
465+ )
406466
407467 # ── Infrastructure ───────────────────────────────────────────────────
408468 url_cache = UrlCache (redis_client , ttl_seconds = settings .redis .redis_ttl_seconds )
@@ -771,7 +831,9 @@ def wire_services(app: FastAPI, settings: AppSettings, redis_client) -> None:
771831 max_active_keys = settings .max_active_api_keys ,
772832 )
773833 app .state .page_layout_service = PageLayoutService (page_layout_repo )
774- token_factory = TokenFactory (settings .jwt )
834+ token_factory = TokenFactory (
835+ settings .jwt , plan_of = app .state .entitlement_service .plan_hint_for
836+ )
775837 otp_service = OtpService (token_repo )
776838
777839 app .state .user_repo = user_repo
@@ -1010,6 +1072,9 @@ def wire_services(app: FastAPI, settings: AppSettings, redis_client) -> None:
10101072 report_repo = report_repo ,
10111073 report_submission_repo = report_submission_repo ,
10121074 feature_flag_repo = feature_flag_repo ,
1075+ subscription_repo = subscription_repo ,
1076+ override_repo = override_repo ,
1077+ entitlement_event_repo = ent_events ,
10131078 r2_storage = r2_storage ,
10141079 posthog = build_posthog_eraser (settings , http_client ),
10151080 mailer = erasure_mailer ,
0 commit comments