from django.conf import settings from django.db import models from django.db.models import Q from infrasynth.tenancy.mixins import GlobalOrTenantModel, TenantOwnedModel class FeatureFlag(GlobalOrTenantModel): """An operational toggle. ``tenant IS NULL`` is the global default; a tenant row overrides it.""" slug = models.SlugField(max_length=100) name = models.CharField(max_length=200) description = models.TextField(blank=True) is_active = models.BooleanField(default=False) rollout_percentage = models.PositiveSmallIntegerField(default=100, help_text="0-100. 100 = all users") environments = models.JSONField(default=list, help_text='["production", "staging"] or [] = all') category = models.CharField(max_length=50, blank=True, help_text="Grouping for UI") metadata = models.JSONField(default=dict) class Meta: db_table = "features_flag" constraints = [ models.UniqueConstraint(fields=["tenant", "slug"], name="uniq_feature_flag_slug_per_tenant"), models.UniqueConstraint( fields=["slug"], condition=Q(tenant__isnull=True), name="uniq_global_feature_flag_slug", ), ] class FeatureFlagOverride(TenantOwnedModel): flag = models.ForeignKey(FeatureFlag, on_delete=models.CASCADE, related_name="overrides") user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True, related_name="+", ) group = models.ForeignKey( "auth.Group", on_delete=models.CASCADE, null=True, blank=True, related_name="+", ) is_enabled = models.BooleanField() class Meta: db_table = "features_override" constraints = [ models.UniqueConstraint(fields=["flag", "user"], name="uniq_override_flag_user"), models.UniqueConstraint(fields=["flag", "group"], name="uniq_override_flag_group"), ]