diff --git a/internal/integration/subscription_is_free_test.go b/internal/integration/subscription_is_free_test.go index 2a8f49d..5d42c3c 100644 --- a/internal/integration/subscription_is_free_test.go +++ b/internal/integration/subscription_is_free_test.go @@ -171,6 +171,11 @@ func (app *SubscriptionTestApp) makeAuthenticatedRequest(t *testing.T, method, p // TestIntegration_IsFreeBypassesLimitations tests that users with IsFree=true // see limitations_enabled=false regardless of global settings func TestIntegration_IsFreeBypassesLimitations(t *testing.T) { + // TEMPORARILY DISABLED — Subscriptions: GetSubscriptionStatus now returns + // a limitations_enabled=false stub for everyone, so the assertion that a + // normal user sees limitations_enabled=true (per EnableLimitations setting) + // no longer holds. Remove this skip when GetSubscriptionStatus is restored. + t.Skip("subscription feature disabled — see subscription_service.go TEMPORARILY DISABLED") app := setupSubscriptionTest(t) // Register and login a user @@ -289,6 +294,10 @@ func TestIntegration_IsFreeBypassesCheckLimit(t *testing.T) { // TestIntegration_IsFreeIndependentOfTier tests that IsFree works regardless of // the user's subscription tier func TestIntegration_IsFreeIndependentOfTier(t *testing.T) { + // TEMPORARILY DISABLED — Subscriptions: GetSubscriptionStatus is stubbed, + // so the Pro+!IsFree case (which would normally return limitations_enabled=true) + // is no longer reachable. Remove this skip when the feature is restored. + t.Skip("subscription feature disabled — see subscription_service.go TEMPORARILY DISABLED") app := setupSubscriptionTest(t) // Register and login a user diff --git a/internal/services/subscription_service.go b/internal/services/subscription_service.go index b679a90..e791c66 100644 --- a/internal/services/subscription_service.go +++ b/internal/services/subscription_service.go @@ -121,7 +121,51 @@ func (s *SubscriptionService) GetSubscription(ctx context.Context, userID uint) // 5-minute TTL; mutation paths (residence/task/contractor/document/sub CRUD) // invalidate via cache.InvalidateSubscriptionStatusForUsers, fanning out to // every member of a shared residence. -func (s *SubscriptionService) GetSubscriptionStatus(ctx context.Context, userID uint) (*SubscriptionStatusResponse, error) { +// +// TEMPORARILY DISABLED — Subscriptions feature off. +// +// Returns a "limitations disabled" / pro-tier stub without any DB or Redis +// work. The KMM client (SubscriptionHelper.kt) treats limitations_enabled=false +// as a master kill switch — every canCreate* check short-circuits to true +// without ever consulting tier or limits. tier="pro" is belt-and-suspenders in +// case a future client path inspects tier directly. +// +// To re-enable: change this body to call s.getSubscriptionStatusFromDB(ctx, userID). +// The original implementation is preserved verbatim below as an unexported +// method so this is a one-line revert. +// +// Findable by searching: "TEMPORARILY DISABLED — Subscriptions" +func (s *SubscriptionService) GetSubscriptionStatus(ctx context.Context, _ uint) (*SubscriptionStatusResponse, error) { + _ = ctx + return &SubscriptionStatusResponse{ + Tier: "pro", + IsActive: true, + AutoRenew: false, + LimitationsEnabled: false, + Usage: &UsageResponse{ + PropertiesCount: 0, + TasksCount: 0, + ContractorsCount: 0, + DocumentsCount: 0, + }, + Limits: map[string]*TierLimitsClientResponse{ + // Empty TierLimitsClientResponse → all fields nil → "unlimited" + // per the KMM model's `null = unlimited` convention. Keys present + // so client Map[tier] lookups don't NPE if they ever run. + "free": {}, + "pro": {}, + }, + SubscriptionSource: "none", + TrialActive: false, + }, nil +} + +// getSubscriptionStatusFromDB is the original implementation, preserved verbatim +// while the subscription feature is disabled. See the TEMPORARILY DISABLED note +// on GetSubscriptionStatus above for the re-enable procedure. +// +//nolint:unused // intentional — re-enabled by switching GetSubscriptionStatus to call this. +func (s *SubscriptionService) getSubscriptionStatusFromDB(ctx context.Context, userID uint) (*SubscriptionStatusResponse, error) { // Cache fast path — only used on warm reads. Cold reads, trial-start // branch, and the actual mutation paths below all populate fresh. if s.cache != nil {