"""Configuration storage model. A single table stores both the platform default (``tenant IS NULL``) and a tenant's override (non-null ``tenant``) for the same key — the same shape as ``features.FeatureFlag`` (``PLAN.md`` §2.0). Secret values are stored as a Fernet token (a JSON string); encryption/decryption is the service's concern and the model stays dumb. """ from __future__ import annotations from django.conf import settings from django.db import models from django.db.models import Q from infrasynth.tenancy.mixins import GlobalOrTenantModel __all__ = ["ConfigValue"] class ConfigValue(GlobalOrTenantModel): """A configuration value. ``tenant IS NULL`` = platform default, non-null = tenant override.""" key = models.CharField(max_length=200, db_index=True) value = models.JSONField(default=dict) updated_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="+", ) updated_at = models.DateTimeField(auto_now=True) class Meta: db_table = "configs_value" constraints = [ models.UniqueConstraint(fields=["tenant", "key"], name="uniq_config_key_per_tenant"), models.UniqueConstraint( fields=["key"], condition=Q(tenant__isnull=True), name="uniq_global_config_key", ), ] indexes = [models.Index(fields=["tenant_id", "key"])] def __str__(self) -> str: scope = self.tenant_id if self.tenant_id is not None else "global" return f"{self.key}@{scope}"