Глава 22. Почему KContext существует отдельно
22.1. Контекст отвечает не на вопрос «что это?», а на вопрос «в каких условиях существует?»
Вернёмся к насосу Н1.
Он существует. У него есть собственная идентичность. У него есть описание. У него есть свойства.
Но существует он не в пустоте.
Насос Н1 разработан на предприятии А. В рамках проекта Б. Под ответственностью определённого владельца. В определённой организационной структуре. В определённой компании.
Все эти обстоятельства не определяют, что является самим объектом.
Насос не становится другим насосом только потому, что изменился его владелец. Он не становится другим объектом потому, что его передали другой группе или изменились административные условия его использования.
Но эти обстоятельства определяют, в каких условиях объект существует и управляется.
Именно для этого в модели существует KContext.
Контекст отвечает не на вопрос: Что это за объект?
а на вопрос: В каких административных условиях этот объект существует сейчас?
Это принципиальное разделение.
22.2. Классическая модель: контекст как поля
В традиционном подходе такие сведения часто хранятся непосредственно в записи объекта.
Product
id: 12345
name: Насос Н1
owner: Иванов
project: Проект А
organization: Предприятие Б
status: in_production
На первый взгляд это выглядит естественно.
Владелец — поле. Проект — поле. Организация — поле. Статус — поле.
Но проходит время.
Владелец меняется. Объект передаётся другой группе. Меняется административное окружение. Изменяется состояние управления объектом.
Каждое такое изменение приходится записывать непосредственно в объект.
Проблема не в самом изменении. Проблема в том, что сведения об объекте и сведения об условиях его управления оказываются смешаны в одной сущности.
Тогда изменение административного состояния выглядит как изменение самого объекта. Но инженерно это не так.
Объект остаётся тем же. Меняются условия, в которых он существует и управляется.
22.3. Почему контекст не является свойством объекта
Рассмотрим конкретную ситуацию.
Насос Н1 разработан в 2026 году. В определённый момент его владельцем является Иванов. Объект находится в определённой группе и компании.
Позже владелец меняется. Насос Н1 стал другим?
Нет. Изменились условия управления объектом.
Позже объект переводится в другую группу. Насос Н1 стал другим?
Нет. Изменился административный контекст.
Поэтому сведения о владельце и группе не должны превращаться в свойства самого объекта только потому, что они связаны с ним.
Это и есть причина существования KContext как отдельной сущности.
22.4. KContext не является частью KObject
Здесь есть важное архитектурное уточнение.
В модели Constructum KObject и KContext существуют раздельно.
KObject не знает о KContext. Связь направлена в другую сторону: KContext относится к конкретному KObject.
Это принципиально. KObject не зависит от KContext на уровне своей структуры. Это не означает, что активный объект может существовать без контекста. В Constructum создание KObject и его первоначального KContext является атомарной операцией: активный KObject всегда имеет активный KContext. Контекст, напротив, не имеет смысла без объекта.
KObject
│
│
│ объект не знает о контексте
│
▼
KContext
│
└── target_object_id → KObject
Это направление связи выбрано намеренно.
KObject является фундаментальным фактом существования объекта. Он не должен зависеть от административного механизма, который определяет владельца, группу или другие условия управления этим объектом.
KContext является самостоятельной сущностью, которая относится к KObject и хранит административное состояние, связанное с этим объектом.
Такое разделение позволяет отделить данные об объекте от управления доступом к нему. KContext хранит административные условия существования объекта. На основании этих данных могут строиться производные представления — projections, используемые механизмами авторизации. Эти projections не являются источником истины. Они являются производным представлением основной модели.
Это даёт важное разделение:
KObject
↓
факт существования объекта
KContext
↓
административные условия его существования
Projection
↓
производные представления для управления доступом
Последний уровень является уже производным. Он вычисляется на основании данных модели и не является частью самого KObject.
22.5. Что такое KContext
KContext отвечает на вопрос: В каких административных условиях находится объект?
В текущей модели контекст связан с объектом через target_object_id.
Его собственное состояние имеет время действия:
valid_from
valid_to
Административные характеристики контекста представлены отдельными атрибутами. В частности, текущая реализация хранит владельца и группу владения как атрибуты KContext.
Упрощённо:
KObject: 12345
↑
│ target_object_id
│
KContext
│
├── owner
├── owningGroup
├── valid_from
└── valid_to
Таким образом, KContext не превращает административные сведения в свойства KObject.
Он хранит их отдельно.
22.6. Контекст как самостоятельная сущность
Если контекст имеет собственное время, собственный идентификатор и собственные атрибуты, он не является простым полем объекта. Это самостоятельная сущность.
Она имеет:
- собственную идентичность;
- время действия;
- ссылку на объект, к которому относится;
- административные атрибуты;
- собственный жизненный цикл.
При этом KContext не является копией KObject и не является альтернативным представлением объекта. Он существует для объекта, но не внутри объекта.
Это различие кажется небольшим, но для архитектуры оно принципиально.
22.7. Инвариант: объект первичен, контекст вторичен
Здесь необходимо сформулировать одно из фундаментальных правил модели.
KObject
↑
│
│ относится к
│
KContext
Логически объект первичен. Контекст вторичен.
Контекст не имеет смысла без объекта, потому что сам вопрос «в каких условиях существует этот объект?» предполагает существование объекта.
Поэтому невозможно создать самостоятельный контекст, не относящийся ни к одному KObject.
Но в текущей реализации есть важное уточнение: KObject и его первоначальный KContext создаются как единое целое.
Это означает, что для активного объекта система не допускает состояния, при котором KObject уже зарегистрирован как активный объект, а его контекст отсутствует.
Таким образом, необходимо различать два утверждения:
логически:
KObject первичен → KContext относится к нему
технически:
создание KObject + первоначального KContext
является одной атомарной операцией
Это не противоречие. Первое утверждение описывает зависимость сущностей. Второе — правило их создания.
22.8. Почему невозможно создать контекст отдельно
Представим, что система разрешает создать KContext без объекта.
Пользователь создаёт контекст. Указывает владельца. Указывает группу. Определяет административные условия.
Но объекта, к которому всё это относится, нет. Что означает такой контекст?
Ничего.
Он не описывает условия существования какого-либо объекта.
Поэтому KContext не является самостоятельной административной записью, которую можно создать «на будущее».
Он всегда относится к конкретному KObject.
22.9. Почему KObject не знает о KContext
Это решение может показаться необычным.
Если KContext относится к KObject, почему бы просто не хранить context_id внутри KObject?
Потому что это создаёт обратную зависимость. Получилась бы модель:
KObject
│
└── context_id
↓
KContext
Тогда фундаментальная сущность объекта начинает зависеть от административной сущности. Вместо этого модель использует обратное направление:
KObject
↑
KContext
└── target_object_id
KObject остаётся независимым. Context Service может управлять контекстом, не изменяя структуру самого KObject.
Это особенно важно для распределённой системы. Данные об объекте и административное управление объектом могут находиться в разных границах ответственности.
KObject не должен знать, каким способом система определяет его владельца или область доступа.
Он просто существует.
22.10. Почему контекст не является ACL
На первый взгляд может показаться, что KContext — это просто механизм управления доступом (Access Control List).
Владелец определяет, кто имеет отношение к объекту. Группа определяет область управления. Из контекста строятся производные данные для проверки прав.
Но KContext и права — не одно и то же.
KContext отвечает на вопрос: В каких административных условиях существует объект?
Механизм прав отвечает на другой вопрос: Что конкретный пользователь имеет право сделать с этим объектом?
Эти сведения связаны, но не тождественны. Следовательно:
KContext
↓
административные факты
+
↓
другие факты системы
↓
проекции
↓
решение о доступе
Само право не является свойством KObject.
22.11. Почему контекст не является папкой
Другое распространённое заблуждение: контекст — это папка, в которой хранится объект.
Проект — папка.
Группа — папка.
Организация — папка.
Но папка является механизмом организации хранения.
KContext — не механизм хранения. Объект не «лежит» в контексте. KContext фиксирует административные условия, связанные с объектом.
Это принципиально разные вещи.
Папка может быть изменена исключительно ради организации пользовательского интерфейса.
Изменение KContext является изменением административного состояния объекта.
22.12. Почему контекст не является проектом
Ещё одно заблуждение: контекст — это проект.
В ранних вариантах модели проект рассматривался как один из элементов контекста. Но текущая реализация KContext уже не хранит projectId. Контекст в актуальной версии модели содержит ссылку на объект, владельца и группу владения; проект не является его самостоятельным атрибутом.
Это важное уточнение.
Не следует расширять понятие KContext до универсального контейнера для всех административных сведений.
KContext имеет строго определённую ответственность. Он описывает административное состояние объекта в пределах данной модели.
22.13. Время является частью контекста
Контекст не является неизменным.
Владелец может измениться. Группа владения может измениться. Сам контекст может быть закрыт.
Поэтому KContext имеет собственный временной интервал:
valid_from
valid_to
История при этом не заменяется новым значением. Предыдущее состояние закрывается, а новое становится действующим.
Упрощённо:
KObject: 12345
KContext
owner: Иванов
group: Группа А
valid_from: 2026
valid_to: 2028
KContext
owner: Петров
group: Группа Б
valid_from: 2028
valid_to: ...
Сам KObject остаётся тем же. Меняется административное состояние, связанное с ним.
Именно поэтому история должна принадлежать контексту и его атрибутам, а не превращать изменение контекста в изменение самого объекта.
22.14. Практический пример
Рассмотрим насос Н1.
В 2026 году он зарегистрирован в системе. Вместе с ним создаётся первоначальный KContext.
KObject: 12345
↑
│
KContext
owner: Иванов
group: Группа А
valid_from: 01.01.2026
valid_to: (действует)
В 2028 году владелец меняется. Сам KObject не изменяется. Изменяется контекстное состояние:
KObject: 12345
↑
│
KContext
owner: Иванов
group: Группа А
valid_from: 01.01.2026
valid_to: 01.06.2028
KContext
owner: Петров
group: Группа А
valid_from: 01.06.2028
valid_to: (действует)
В 2030 году меняется группа владения. Снова не возникает нового объекта. Изменяется административное состояние.
Так система может ответить не только на вопрос: Кто владеет объектом сейчас?
но и: Кто владел объектом в 2027 году?
Потому что история контекста не уничтожается при изменении текущего состояния.
22.15. Почему это важно для долгоживущих систем
PLM-система живёт десятилетиями. За это время меняются люди. Меняются группы. Реорганизуются компании. Изменяются административные полномочия.
Если такие сведения являются обычными полями KObject, история быстро превращается в историю изменений самого объекта.
Это смешивает два разных события: изменилось описание объекта
и
изменились условия управления объектом
Модель KContext разделяет эти события. Изменение владельца не является изменением Definition. Изменение группы не является новой Revision. Изменение административного состояния не создаёт новый KObject.
Это позволяет отдельно управлять историей объекта и историей условий его управления.
22.16. Контекст и производные представления
На этом месте возникает ещё один важный слой.
KContext хранит административные факты. Но проверка прав не обязана каждый раз заново собирать эти факты из основной модели.
На их основе строятся производные представления. Например:
KContext
│
├── owner
└── owningGroup
│
▼
Object Scope
│
▼
Effective Permissions
Такие проекции являются частью модели эксплуатации системы, но не частью самого объекта.
Они могут синхронизироваться и пересчитываться при изменении исходных данных.
Это важное архитектурное разделение: основная модель хранит факты, производная модель помогает быстро принимать решения на их основании.
Поэтому система управления доступом не должна превращать права в свойства KObject.
22.17. Связь с предыдущими главами
Глава 20 установила: KObject фиксирует сам факт существования объекта. Он не содержит его свойств, описания или контекста.
Глава 22 добавляет: условия существования и административного управления объектом также не должны смешиваться с самим объектом.
KContext является самостоятельной сущностью. Он относится к KObject. KObject не зависит от него на уровне своей структуры.
KContext хранит собственное временное состояние и административные атрибуты.
Производные проекции используют эти данные для решения задач доступа, но не становятся частью KObject.
Вместе эти главы формируют последовательную картину:
KObject
│
│ существует
│
├── Definition
├── Revision
├── Attribute
└── Relation
KContext
│
└── административное состояние,
связанное с KObject
Projection
│
└── производное представление
для задач доступа
22.18. Граница: KContext не является универсальным контейнером
Было бы неверно утверждать, что KContext может содержать любые сведения об объекте.
KContext не описывает конструкцию объекта.
Не содержит его Definition. Не содержит Revision. Не заменяет Attribute. Не является Relation. Не является ACL. Не является проектом.
Он отвечает только за свою часть модели: административное состояние, связанное с объектом.
Именно поэтому его можно отделить от KObject. Граница проходит по вопросу: Относится ли это знание к тому, что представляет собой объект, или к тому, в каких административных условиях он находится?
В первом случае речь идёт о самом объекте и его описании.
Во втором — о KContext.
22.19. Главный вывод
KContext существует отдельно не потому, что система требует ещё одну таблицу.
Он существует потому, что объект и условия его административного существования — разные сущности.
KObject отвечает за сам факт существования объекта.
KContext отвечает за административное состояние, связанное с этим объектом.
При этом KObject не знает о KContext. Связь направлена в другую сторону: KContext знает, к какому KObject он относится.
Это позволяет сохранить независимость фундаментального объекта от механизма его административного управления.
Логически объект первичен, контекст вторичен. Но технически в системе они создаются атомарно: активный KObject должен иметь активный KContext. Нельзя создать самостоятельный KContext без объекта и нельзя оставить активный объект без контекста.
Изменение контекста не является изменением самого объекта. Смена владельца не создаёт новый KObject. Смена группы не создаёт новую Revision. Изменение административного состояния не меняет Definition.
А производные представления прав строятся отдельно от самого объекта.
Так разделяются три разных уровня:
KObject
↓
что существует
KContext
↓
в каких административных условиях существует
Projection
↓
кому и как это доступно
Это разделение позволяет системе сохранять независимость объекта от его административной истории и одновременно хранить эту историю полностью.
В следующей главе: какие правила делают неправильные состояния модели невозможными? Если KObject, KAttribute, KContext и другие сущности имеют строгие отношения между собой, где проходят границы допустимого состояния системы?