{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://ufarms.ru/calc/project-schema-v1.json",
  "title": "Ссылка на проект модульной фермы UFARMS",
  "description": "Добавьте параметры к https://ufarms.ru/calc/ во фрагменте URL после #. Фрагмент не отправляется серверу. Конструктор принимает только перечисленные переменные, запрещает повторные/неизвестные ключи и проверяет тип, диапазон, структуру и общий размер ссылки.",
  "canonicalBaseUrl": "https://ufarms.ru/calc/",
  "example": "https://ufarms.ru/calc/#v=1&l=12&w=8&h=3&t=4&o=auto&a=0.6&ta=1&te=0&c=0.45&se=1&dm=dosatron&ws=tank200",
  "fragmentEncoding": "application/x-www-form-urlencoded",
  "maxUrlLength": 32000,
  "variables": {
    "v": {"type": "integer", "const": 1, "required": true, "description": "Версия формата ссылки."},
    "l": {"type": "number", "minimum": 1, "maximum": 120, "default": 12, "unit": "м", "description": "Длина помещения."},
    "w": {"type": "number", "minimum": 1, "maximum": 120, "default": 8, "unit": "м", "description": "Ширина помещения."},
    "h": {"type": "number", "minimum": 1.5, "maximum": 20, "default": 3, "unit": "м", "description": "Высота помещения."},
    "t": {"type": "integer", "enum": [3, 4], "default": 4, "description": "Количество ярусов стеллажей."},
    "o": {"type": "string", "enum": ["auto", "length", "width"], "default": "auto", "description": "Направление рядов: автоматически, вдоль длины или вдоль ширины."},
    "a": {"type": "number", "minimum": 0.6, "maximum": 1.6, "default": 0.6, "unit": "м", "description": "Проход между соседними рядами."},
    "ta": {"type": "number", "minimum": 1, "maximum": 3, "default": 1, "unit": "м", "description": "Ширина центрального технологического прохода."},
    "te": {"type": "boolean", "encoding": "1 или 0", "default": false, "description": "Обязательно зарезервировать реальный сквозной технологический проход."},
    "c": {"type": "number", "minimum": 0.3, "maximum": 1.2, "default": 0.45, "unit": "м", "description": "Рабочий отступ от стен."},
    "se": {"type": "boolean", "acceptedValues": ["1", "0", "true", "false"], "default": true, "description": "Включить растворный узел."},
    "dm": {"type": "string", "enum": ["dosatron", "zmk"], "default": "dosatron", "description": "Модель двух дозаторов растворного узла."},
    "mt": {"type": "number", "minimum": 0, "maximum": 100000000, "default": 6000, "unit": "₽/шт.", "description": "Цена одного маточного бака 50 л."},
    "rt": {"type": "number", "minimum": 0, "maximum": 100000000, "default": 12000, "unit": "₽/шт.", "description": "Цена основного бака осмоса 200 л."},
    "ws": {"type": "string", "enum": ["tank200", "eurocube1000"], "default": "tank200", "description": "Накопитель воды: бак 200 л или еврокуб 1000 л."},
    "ep": {"type": "number", "minimum": 0, "maximum": 100000000, "default": 25000, "unit": "₽/шт.", "description": "Цена еврокуба 1000 л."},
    "op": {"type": "number", "minimum": 0, "maximum": 100000000, "default": 75000, "unit": "₽/узел", "description": "Цена установки обратного осмоса."},
    "mf": {"type": "number", "minimum": 0, "maximum": 100000000, "default": 18500, "unit": "₽/узел", "description": "Цена коллектора растворного узла."},
    "cr": {"type": "number", "minimum": 0, "maximum": 30, "default": 5, "unit": "%", "description": "Запас кубиков минеральной ваты."},
    "cs": {"type": "integer", "minimum": 1, "maximum": 1000000, "default": 360, "unit": "шт.", "description": "Количество кубиков в упаковке."},
    "cp": {"type": "number", "minimum": 0, "maximum": 100000000, "default": 6050, "unit": "₽/уп.", "description": "Цена упаковки кубиков."},
    "ms": {"type": "integer", "minimum": 1, "maximum": 1000000, "default": 12, "unit": "шт.", "description": "Количество матов в упаковке для расчёта повторной закупки."},
    "mp": {"type": "number", "minimum": 0, "maximum": 100000000, "default": 3300, "unit": "₽/уп.", "description": "Цена упаковки матов для расчёта повторной закупки."},
    "lh": {"type": "number", "minimum": 1, "maximum": 24, "default": 16, "unit": "ч/сут.", "description": "Работа освещения в сутки."},
    "ld": {"type": "integer", "minimum": 1, "maximum": 31, "default": 30, "unit": "дн./мес.", "description": "Дней работы освещения в месяц."},
    "et": {"type": "number", "minimum": 0, "maximum": 1000000, "default": 7, "unit": "₽/кВт·ч", "description": "Тариф электроэнергии."},
    "mo": {"type": "string", "encoding": "base64url(JSON object)", "maximumEncodedLength": 16000, "description": "Ручные смещения секций: безопасный идентификатор секции → {dx,dy} в метрах; не более 2000 записей."},
    "rm": {"type": "string", "encoding": "base64url(JSON array)", "maximumEncodedLength": 16000, "description": "Безопасные идентификаторы удалённых секций; не более 2000 записей."},
    "to": {"type": "string", "encoding": "base64url(JSON object)", "maximumEncodedLength": 16000, "description": "Понижение отдельных четырёхъярусных секций: безопасный идентификатор секции → 3; не более 2000 записей."},
    "ob": {"type": "string", "encoding": "base64url(JSON array)", "maximumEncodedLength": 16000, "description": "До 100 дверей/колонн. Дверь: {id,type:'door',wall,x,y,width}; колонна: {id,type:'column',x,y,width}."},
    "sn": {"type": "string", "encoding": "base64url(JSON array)", "maximumEncodedLength": 16000, "description": "До 20 ручных позиций растворных узлов: {id,cx,cy} в метрах."}
  },
  "security": {
    "unknownVariables": "reject",
    "duplicateVariables": "reject",
    "identifierPattern": "^[A-Za-z0-9:_-]{1,96}$",
    "reservedIdentifiers": ["__proto__", "prototype", "constructor"],
    "htmlFromUrl": "never rendered",
    "invalidProjectBehavior": "open defaults and show an explicit rejection message"
  },
  "additionalProperties": false
}
