# Data Model: Clean Repository Enterprise Preparation

## Overview

Модель данных описывает сущности, необходимые для подготовки и контроля enterprise clean-поставки в изолированном контуре без внешнего интернета.

---

## 1) ReleaseCandidate

**Purpose**: Представляет конкретный релиз-кандидат, проходящий clean-подготовку и compliance-проверку.

### Fields

- `candidate_id` (string, required, unique)  
  Уникальный идентификатор релиз-кандидата.
- `version` (string, required)  
  Версия/метка релиза.
- `profile` (enum, required)  
  Допустимые значения: `enterprise-clean`, `development`.
- `created_at` (datetime, required)
- `created_by` (string, required)  
  Идентификатор оператора/сервиса, создавшего candidate.
- `source_snapshot_ref` (string, required)  
  Ссылка на исходный снимок/состояние для воспроизводимости.
- `status` (enum, required)  
  `draft`, `prepared`, `compliant`, `blocked`, `released`.

### Validation Rules

- `candidate_id` и `source_snapshot_ref` не могут быть пустыми.
- Для `profile=enterprise-clean` переход в `released` разрешён только после `compliant`.
- Переходы статусов должны быть монотонными по lifecycle (без недетерминированных откатов).

---

## 2) CleanProfilePolicy

**Purpose**: Формальная политика классификации артефактов и источников ресурсов для enterprise clean-профиля.

### Fields

- `policy_id` (string, required, unique)
- `policy_version` (string, required)
- `active` (boolean, required)
- `prohibited_artifact_categories` (array[string], required)  
  Примеры: `test-data`, `demo-data`, `load-test`, `sample-repository`.
- `required_system_categories` (array[string], required)  
  Примеры: `system-init`, `security-bootstrap`, `schema-migrations`.
- `external_source_forbidden` (boolean, required; для enterprise-clean = true)
- `internal_source_registry_ref` (string, required)  
  Ссылка на реестр внутренних серверов.
- `effective_from` (datetime, required)
- `effective_to` (datetime, optional)

### Validation Rules

- Политика не может быть активирована без `internal_source_registry_ref`.
- Одновременная активность двух политик для одного профиля и периода запрещена.
- Для `enterprise-clean` поле `external_source_forbidden` всегда `true`.

---

## 3) ResourceSourceRegistry

**Purpose**: Реестр разрешённых внутренних серверов компании, используемых для загрузки всех ресурсов.

### Fields

- `registry_id` (string, required, unique)
- `name` (string, required)
- `entries` (array[ResourceSourceEntry], required, min=1)
- `updated_at` (datetime, required)
- `updated_by` (string, required)
- `status` (enum, required)  
  `active`, `inactive`.

### ResourceSourceEntry (nested)

- `source_id` (string, required, unique within registry)
- `host` (string, required)
- `protocol` (enum, required)  
  `http`, `https`, `ssh`, `file`.
- `purpose` (string, required)  
  Например: `artifact-repo`, `package-mirror`, `git-mirror`.
- `allowed_paths` (array[string], optional)
- `enabled` (boolean, required)

### Validation Rules

- В `entries` запрещены дубликаты `host + purpose`.
- При `status=active` должен существовать хотя бы один `enabled=true` entry.
- Внешние публичные хосты не допускаются в активном реестре enterprise clean-профиля.

---

## 4) DistributionManifest

**Purpose**: Зафиксированный состав итогового дистрибутива для аудита и воспроизводимости.

### Fields

- `manifest_id` (string, required, unique)
- `candidate_id` (string, required, FK -> ReleaseCandidate)
- `policy_id` (string, required, FK -> CleanProfilePolicy)
- `generated_at` (datetime, required)
- `generated_by` (string, required)
- `items` (array[ManifestItem], required)
- `summary` (ManifestSummary, required)
- `deterministic_hash` (string, required)

### ManifestItem (nested)

- `path` (string, required)
- `category` (string, required)
- `classification` (enum, required)  
  `required-system`, `allowed`, `excluded-prohibited`.
- `reason` (string, required)
- `checksum` (string, optional for included items)

### ManifestSummary (nested)

- `included_count` (integer, required, >=0)
- `excluded_count` (integer, required, >=0)
- `prohibited_detected_count` (integer, required, >=0)

### Validation Rules

- `candidate_id` и `policy_id` должны ссылаться на существующие записи.
- `deterministic_hash` должен быть одинаковым для идентичного входного состояния.
- `included_count + excluded_count` должно совпадать с размером `items`.

---

## 5) ComplianceCheckRun

**Purpose**: Один запуск проверки соответствия clean/compliance для релиз-кандидата.

### Fields

- `check_run_id` (string, required, unique)
- `candidate_id` (string, required, FK -> ReleaseCandidate)
- `policy_id` (string, required, FK -> CleanProfilePolicy)
- `started_at` (datetime, required)
- `finished_at` (datetime, optional)
- `final_status` (enum, required)  
  `running`, `compliant`, `blocked`, `failed`.
- `triggered_by` (string, required)
- `execution_mode` (enum, required)  
  `tui`, `ci`.
- `checks` (array[CheckStageResult], required)

### CheckStageResult (nested)

- `stage` (enum, required)  
  `data_purity`, `internal_sources_only`, `no_external_endpoints`, `manifest_consistency`.
- `status` (enum, required)  
  `pass`, `fail`, `skipped`.
- `details` (string, optional)
- `duration_ms` (integer, optional, >=0)

### Validation Rules

- `final_status=compliant` допускается только при `pass` для всех обязательных стадий.
- `final_status=blocked` обязателен при `fail` хотя бы одной обязательной стадии.
- `execution_mode=ci` и `execution_mode=tui` должны быть сопоставимы по policy/version.

---

## 6) ComplianceViolation

**Purpose**: Нормализованная запись конкретного нарушения, найденного в ходе проверки.

### Fields

- `violation_id` (string, required, unique)
- `check_run_id` (string, required, FK -> ComplianceCheckRun)
- `category` (enum, required)  
  `data-purity`, `external-source`, `manifest-integrity`, `policy-conflict`, `operational-risk`.
- `severity` (enum, required)  
  `critical`, `high`, `medium`, `low`.
- `location` (string, required)  
  Путь/endpoint/конфигурационный ключ.
- `evidence` (string, optional)
- `remediation` (string, required)
- `blocked_release` (boolean, required)
- `detected_at` (datetime, required)

### Validation Rules

- Для `category=external-source` поле `blocked_release` всегда `true` в enterprise clean-профиле.
- Для `severity=critical` поле `remediation` обязательно и непустое.
- `check_run_id` должен ссылаться на существующий запуск проверки.

---

## 7) ComplianceReport

**Purpose**: Финальный отчёт проверки для оператора и аудита.

### Fields

- `report_id` (string, required, unique)
- `check_run_id` (string, required, FK -> ComplianceCheckRun)
- `candidate_id` (string, required)
- `generated_at` (datetime, required)
- `operator_summary` (string, required)
- `structured_payload_ref` (string, required)  
  Ссылка на машинно-читаемое представление.
- `violations_count` (integer, required, >=0)
- `blocking_violations_count` (integer, required, >=0)

### Validation Rules

- `blocking_violations_count` ≤ `violations_count`.
- При `final_status=blocked` в связанном check run `blocking_violations_count` > 0.
- Отчёт должен быть доступен для экспортирования из TUI сценария.

---

## 8) CleanReleaseConfig

**Purpose**: Декларативный конфиг `.clean-release.yaml` в корне репозитория — центральный source of truth для политики clean-валидации.

### Top-Level Fields

- `profile` (enum, required): `enterprise-clean`, `development`.
- `scan_mode` (enum, required): `repo`, `build`, `docker`.
- `prohibited_categories` (array[string], required): категории запрещённых артефактов.
- `prohibited_paths` (array[string], required): glob-паттерны запрещённых путей.
- `allowed_sources` (array[string], required): glob-паттерны допустимых endpoint'ов.
- `ignore_paths` (array[string], optional): пути, исключённые из сканирования.
- `database_cleanup` (DatabaseCleanupConfig, optional): правила очистки БД.

### DatabaseCleanupConfig (nested)

- `enabled` (boolean, required)
- `tables` (array[TableCleanupRule], required when enabled)
- `preserve` (array[string], optional): whitelist записей, защищённых от очистки.

### TableCleanupRule (nested)

- `name` (string, required): имя таблицы.
- `condition` (string, required): SQL WHERE-условие для идентификации тестовых записей.

### Validation Rules

- Для `profile=enterprise-clean` поля `prohibited_categories` и `allowed_sources` обязательны.
- При `database_cleanup.enabled=true` список `tables` не может быть пустым.
- `preserve` записи не могут пересекаться с `condition` в `tables`.

---

## Relationships

1. `ReleaseCandidate` 1—N `DistributionManifest`  
2. `CleanProfilePolicy` 1—N `DistributionManifest`  
3. `ReleaseCandidate` 1—N `ComplianceCheckRun`  
4. `CleanProfilePolicy` 1—N `ComplianceCheckRun`  
5. `ComplianceCheckRun` 1—N `ComplianceViolation`  
6. `ComplianceCheckRun` 1—1 `ComplianceReport`  
7. `ResourceSourceRegistry` 1—N `CleanProfilePolicy` (по ссылке active policy)

---

## State Model Highlights

### ReleaseCandidate lifecycle

`draft -> prepared -> compliant -> released`  
`draft|prepared -> blocked` (при нарушениях)

### ComplianceCheckRun lifecycle

`running -> compliant|blocked|failed`

---

## TUI Mapping Notes (from UX reference)

Состояния TUI из [`ux_reference.md`](./ux_reference.md) напрямую маппятся на сущности:

- `READY` -> `ReleaseCandidate.status in {draft, prepared}`
- `RUNNING` -> `ComplianceCheckRun.final_status = running`
- `COMPLIANT` -> `ComplianceCheckRun.final_status = compliant` + `ComplianceReport`
- `BLOCKED` -> `ComplianceCheckRun.final_status = blocked` + `ComplianceViolation[*].blocked_release=true`