Contract Specification Guide¶
1. Обзор¶
Контракт данных — это набор файлов, описывающих соглашение между производителями и потребителями данных.
2. Структура контракта (несколько файлов!)¶
Зачем несколько файлов?¶
Проблема единого YAML: - ❌ Конфликты в git при параллельных изменениях - ❌ Изменение retention трогает всю схему - ❌ Сложно делать code review - ❌ Нет разделения ответственности
Решение - разделение на файлы:
domains/{namespace}/{entity}/
├── contract.yaml # Метаданные, владелец, ссылки (Data Owner)
├── schema.avsc # Avro схема (Application Developer)
├── quality_rules.yml # Правила качества (QA Engineer)
├── sla.yml # SLA, retention (Data Owner + SRE)
├── physical_layout.yml # Партиционирование, индексы (Data Engineer)
└── runbook.md # Операционная документация (SRE)
Разделение ответственности¶
| Файл | Кто редактирует | Когда меняется версия |
|---|---|---|
contract.yaml | Data Owner | Minor (новые теги, описание) |
schema.avsc | Application Developer | Major/Minor (изменение схемы) |
quality_rules.yml | QA Engineer | Patch (новые правила) |
sla.yml | Data Owner + SRE | Patch (изменение SLA) |
physical_layout.yml | Data Engineer | Не меняет версию! |
runbook.md | SRE | Не меняет версию |
3. Файл: contract.yaml¶
Назначение: Основная метаинформация о контракте.
Редактирует: Data Owner
# ═══════════════════════════════════════════════════════════════════════════
# DATA CONTRACT: sales/orders
# ═══════════════════════════════════════════════════════════════════════════
# Версии
spec_version: "1.0.0" # Версия спецификации (не менять)
contract_version: "2.1.0" # Версия контракта (SemVer: MAJOR.MINOR.PATCH)
# ───────────────────────────────────────────────────────────────────────────
# МЕТАДАННЫЕ
# ───────────────────────────────────────────────────────────────────────────
metadata:
name: "orders" # Имя entity (snake_case)
namespace: "sales" # Домен (snake_case)
display_name: "Заказы клиентов" # Человекочитаемое название
description: |
Заказы из системы 1С Бухгалтерия.
Содержит информацию о всех заказах клиентов,
включая сумму, статус и дату создания.
# Владелец данных
owner:
team: "sales-integration" # Команда-владелец
email: "sales-data@company.ru" # Email для уведомлений
slack: "#sales-data-alerts" # Slack канал
on_call: "https://pagerduty.com/sales-integration"
# Связанные системы
systems:
producer: "1C Enterprise v8.3"
consumers:
- name: "Data Warehouse"
team: "analytics"
- name: "BI Dashboard"
team: "business-intelligence"
- name: "ML Pipeline"
team: "data-science"
# Теги для поиска и фильтрации
tags:
- "revenue"
- "critical"
- "pii" # Есть персональные данные
- "gdpr" # GDPR compliance требуется
# Метаданные версии
created_at: "2026-01-15"
updated_at: "2026-01-23"
created_by: "ivan.petrov@company.ru"
# ───────────────────────────────────────────────────────────────────────────
# ССЫЛКИ НА ДРУГИЕ ФАЙЛЫ КОНТРАКТА
# ───────────────────────────────────────────────────────────────────────────
# Avro схема данных
schema:
file: "./schema.avsc"
format: "avro"
registry_url: "http://schema-registry:8081"
# Правила качества данных
quality_rules:
file: "./quality_rules.yml"
enabled: true
# SLA и retention политики
sla:
file: "./sla.yml"
# Physical layout для Data Engineers
physical_layout:
file: "./physical_layout.yml"
# Runbook для операторов
runbook:
file: "./runbook.md"
# ───────────────────────────────────────────────────────────────────────────
# LINEAGE (Data Lineage)
# ───────────────────────────────────────────────────────────────────────────
lineage:
# Upstream источники (откуда берутся данные)
upstream:
- system: "1C Enterprise"
database: "postgres://1c-db.local/orders"
tables:
- "orders"
- "order_items"
# Downstream потребители (куда идут данные)
downstream:
- system: "Clickhouse DWH"
database: "clickhouse://dwh.local/production"
tables:
- "sales.orders_fact"
- system: "S3 Data Lake"
path: "s3://data-lake/silver/sales/orders/"
# ───────────────────────────────────────────────────────────────────────────
# CHANGELOG (История изменений)
# ───────────────────────────────────────────────────────────────────────────
changelog:
- version: "2.1.0"
date: "2026-01-23"
author: "ivan.petrov@company.ru"
changes:
- type: "added"
description: "Добавлено поле discount_amount (nullable)"
- type: "added"
description: "Добавлено поле customer_phone (nullable)"
breaking: false
- version: "2.0.0"
date: "2026-01-15"
author: "maria.ivanova@company.ru"
changes:
- type: "changed"
description: "Поле status теперь enum вместо string"
- type: "removed"
description: "Удалено deprecated поле old_customer_id"
breaking: true
- version: "1.0.0"
date: "2025-12-01"
author: "ivan.petrov@company.ru"
changes:
- type: "initial"
description: "Первая версия контракта"
breaking: false
4. Файл: schema.avsc¶
Назначение: Apache Avro схема данных.
Редактирует: Application Developer
Формат: JSON (Avro schema)
{
"type": "record",
"name": "Order",
"namespace": "sales.orders",
"doc": "Заказ клиента из системы 1С",
"fields": [
{
"name": "order_id",
"type": "string",
"doc": "Уникальный идентификатор заказа (UUID)",
"logicalType": "uuid"
},
{
"name": "order_number",
"type": "string",
"doc": "Номер заказа в 1С (например: ЗК-001234)"
},
{
"name": "customer_id",
"type": "string",
"doc": "Идентификатор клиента"
},
{
"name": "customer_email",
"type": "string",
"doc": "Email клиента (PII!)"
},
{
"name": "customer_phone",
"type": ["null", "string"],
"default": null,
"doc": "Телефон клиента (PII!)"
},
{
"name": "total_amount",
"type": "double",
"doc": "Сумма заказа"
},
{
"name": "discount_amount",
"type": ["null", "double"],
"default": null,
"doc": "Сумма скидки"
},
{
"name": "currency",
"type": "string",
"default": "RUB",
"doc": "Валюта заказа (ISO 4217)"
},
{
"name": "status",
"type": {
"type": "enum",
"name": "OrderStatus",
"symbols": [
"pending",
"confirmed",
"processing",
"shipped",
"delivered",
"cancelled"
]
},
"doc": "Статус заказа"
},
{
"name": "items_count",
"type": "int",
"doc": "Количество позиций в заказе"
},
{
"name": "created_at",
"type": {
"type": "long",
"logicalType": "timestamp-millis"
},
"doc": "Дата и время создания заказа (UTC)"
},
{
"name": "updated_at",
"type": {
"type": "long",
"logicalType": "timestamp-millis"
},
"doc": "Дата и время последнего обновления (UTC)"
},
{
"name": "items",
"type": {
"type": "array",
"items": {
"type": "record",
"name": "OrderItem",
"fields": [
{
"name": "sku",
"type": "string",
"doc": "Артикул товара"
},
{
"name": "name",
"type": "string",
"doc": "Название товара"
},
{
"name": "quantity",
"type": "int",
"doc": "Количество"
},
{
"name": "price",
"type": "double",
"doc": "Цена за единицу"
},
{
"name": "discount",
"type": ["null", "double"],
"default": null,
"doc": "Скидка на позицию"
}
]
}
},
"doc": "Товары в заказе"
}
]
}
5. Файл: quality_rules.yml¶
Назначение: Правила качества данных для валидации.
Редактирует: QA Engineer
# ═══════════════════════════════════════════════════════════════════════════
# QUALITY RULES: sales/orders
# ═══════════════════════════════════════════════════════════════════════════
version: "2.1.0"
# ───────────────────────────────────────────────────────────────────────────
# ПРАВИЛА ВАЛИДАЦИИ
# ───────────────────────────────────────────────────────────────────────────
rules:
# Обязательные поля
- name: "required_fields"
type: "not_null"
fields:
- "order_id"
- "customer_id"
- "customer_email"
- "total_amount"
- "currency"
- "status"
- "created_at"
severity: "error"
description: "Критически важные поля не могут быть NULL"
# Диапазоны значений
- name: "valid_amount"
type: "range"
field: "total_amount"
min: 0.01
max: 10000000
severity: "error"
description: "Сумма заказа должна быть положительной и разумной"
- name: "valid_discount"
type: "range"
field: "discount_amount"
min: 0
max: "{total_amount}" # Скидка не может быть больше суммы
severity: "error"
description: "Скидка не может быть отрицательной или больше суммы заказа"
# Email формат
- name: "valid_email"
type: "regex"
field: "customer_email"
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
severity: "error"
description: "Email должен иметь валидный формат"
# Телефон формат (опционально)
- name: "valid_phone"
type: "regex"
field: "customer_phone"
pattern: "^\\+?[1-9]\\d{1,14}$" # E.164 format
severity: "warning"
description: "Телефон должен быть в международном формате"
allow_null: true
# Order ID формат
- name: "valid_order_id"
type: "regex"
field: "order_id"
pattern: "^ord_[a-z0-9]{12}$"
severity: "error"
description: "Order ID должен соответствовать формату ord_[12 hex chars]"
# Валюта из списка
- name: "valid_currency"
type: "enum"
field: "currency"
values: ["RUB", "USD", "EUR"]
severity: "error"
description: "Поддерживаемые валюты: RUB, USD, EUR"
# Количество товаров
- name: "valid_items_count"
type: "range"
field: "items_count"
min: 1
max: 1000
severity: "error"
description: "Заказ должен содержать от 1 до 1000 товаров"
# Соответствие items_count и длины массива items
- name: "items_count_matches_array"
type: "custom"
expression: "len(items) == items_count"
severity: "error"
description: "Поле items_count должно соответствовать фактическому количеству товаров"
# Свежесть данных
- name: "data_freshness"
type: "freshness"
field: "created_at"
max_age: "P7D" # 7 дней
severity: "warning"
description: "Заказ создан более 7 дней назад"
# Логическая консистентность
- name: "updated_after_created"
type: "custom"
expression: "updated_at >= created_at"
severity: "error"
description: "Дата обновления не может быть раньше даты создания"
# ───────────────────────────────────────────────────────────────────────────
# ПРАВИЛА ДЛЯ ТОВАРОВ (NESTED)
# ───────────────────────────────────────────────────────────────────────────
nested_rules:
items:
- name: "valid_item_quantity"
type: "range"
field: "quantity"
min: 1
max: 10000
severity: "error"
- name: "valid_item_price"
type: "range"
field: "price"
min: 0.01
max: 1000000
severity: "error"
- name: "valid_sku"
type: "regex"
field: "sku"
pattern: "^[A-Z0-9]{6,20}$"
severity: "error"
# ───────────────────────────────────────────────────────────────────────────
# МОНИТОРИНГ КАЧЕСТВА
# ───────────────────────────────────────────────────────────────────────────
monitoring:
# Минимальный процент записей, которые должны проходить валидацию
min_valid_percentage: 95.0
# Алерты
alerts:
- condition: "valid_percentage < 95"
severity: "critical"
channel: "#sales-data-alerts"
message: "Quality threshold breached for sales.orders"
- condition: "valid_percentage < 99"
severity: "warning"
channel: "#sales-data-alerts"
message: "Quality degradation for sales.orders"
6. Файл: sla.yml¶
Назначение: SLA, retention, freshness политики.
Редактирует: Data Owner + SRE
# ═══════════════════════════════════════════════════════════════════════════
# SLA: sales/orders
# ═══════════════════════════════════════════════════════════════════════════
version: "2.1.0"
# ───────────────────────────────────────────────────────────────────────────
# ДОСТУПНОСТЬ (Availability)
# ───────────────────────────────────────────────────────────────────────────
availability:
# Процент времени когда данные поступают без перебоев
target: "99.9%"
# Расписание (когда данные должны быть доступны)
schedule:
# Рабочие дни: 24/7
weekdays: "00:00-23:59"
# Выходные: 24/7
weekends: "00:00-23:59"
# Плановые окна обслуживания
maintenance_windows:
- day: "sunday"
time: "03:00-04:00"
description: "Еженедельное обслуживание БД 1С"
# ───────────────────────────────────────────────────────────────────────────
# СВЕЖЕСТЬ ДАННЫХ (Freshness)
# ───────────────────────────────────────────────────────────────────────────
freshness:
# Максимальный возраст данных
max_age: "PT1H" # 1 час (ISO 8601 duration)
# Поле для измерения свежести
timestamp_field: "created_at"
# Алерты
alert_threshold: "PT2H" # Алерт если данные старше 2 часов
critical_threshold: "PT4H" # Критический алерт если старше 4 часов
# ───────────────────────────────────────────────────────────────────────────
# ВРЕМЯ РЕАКЦИИ (Response Time)
# ───────────────────────────────────────────────────────────────────────────
response_time:
# Время реакции на инциденты
critical: "PT15M" # 15 минут
high: "PT1H" # 1 час
medium: "PT4H" # 4 часа
low: "P1D" # 1 день
# Время восстановления (MTTR)
recovery_time:
target: "PT2H" # Цель: 2 часа
maximum: "PT4H" # Максимум: 4 часа
# ───────────────────────────────────────────────────────────────────────────
# RETENTION (Хранение данных)
# ───────────────────────────────────────────────────────────────────────────
retention:
# RAW данные в Kafka
raw:
duration: "P7D" # 7 дней
reason: "Для переобработки при сбоях"
# PROD данные в Kafka
prod:
duration: "P30D" # 30 дней
reason: "Для анализа и отладки"
# DLQ данные в Kafka
dlq:
duration: "P90D" # 90 дней (дольше для анализа проблем)
reason: "Для расследования проблем качества"
# Данные в DWH
dwh:
hot:
duration: "P1Y" # 1 год в hot storage
storage_class: "ssd"
warm:
duration: "P3Y" # 3 года в warm storage
storage_class: "hdd"
cold:
duration: "P7Y" # 7 лет в cold storage (законодательство РФ)
storage_class: "s3_glacier"
# GDPR compliance
pii_deletion:
enabled: true
on_customer_request: "P30D" # Удалить PII в течение 30 дней по запросу
# ───────────────────────────────────────────────────────────────────────────
# BACKPRESSURE & THROTTLING
# ───────────────────────────────────────────────────────────────────────────
throughput:
# Ожидаемая пропускная способность
expected:
records_per_second: 100
peak_records_per_second: 1000
daily_volume: 500000
# Лимиты
limits:
max_batch_size: 1000
max_message_size_kb: 1024
# ───────────────────────────────────────────────────────────────────────────
# КОНТАКТЫ ДЛЯ ЭСКАЛАЦИИ
# ───────────────────────────────────────────────────────────────────────────
escalation:
level_1:
team: "sales-integration"
slack: "#sales-data-alerts"
email: "sales-data@company.ru"
level_2:
team: "data-platform"
slack: "#data-platform-oncall"
email: "data-platform@company.ru"
pagerduty: "https://company.pagerduty.com/services/PXXXXXX"
level_3:
team: "engineering-leadership"
email: "engineering-leads@company.ru"
7. Файл: physical_layout.yml¶
Назначение: Настройки для Data Engineers (партиционирование, сортировка, оптимизация).
Формат хранения: Apache Parquet (колоночный формат)
Таблицы: Apache Iceberg (ACID, schema evolution, time travel)
Редактирует: Data Engineer
⚠️ Важно: Изменение этого файла НЕ меняет версию контракта!
Ключевые концепции¶
Apache Iceberg: - Hidden partitioning (партиции скрыты от пользователя) - Schema evolution (изменение схемы без переписывания данных) - Time travel (чтение данных на определённый момент времени) - ACID гарантии - Snapshot isolation
Apache Parquet: - Колоночный формат (читаем только нужные колонки) - Column statistics (min/max/null_count для data skipping) - Bloom filters (для ускорения точечных запросов) - Dictionary encoding (для low cardinality колонок) - Compression codecs (ZSTD, Snappy, Gzip)
# ═══════════════════════════════════════════════════════════════════════════
# PHYSICAL LAYOUT: sales/orders
# ═══════════════════════════════════════════════════════════════════════════
#
# Формат: Apache Parquet + Apache Iceberg
# ═══════════════════════════════════════════════════════════════════════════
version: "1.2"
# ───────────────────────────────────────────────────────────────────────────
# ICEBERG TABLE CONFIGURATION
# ───────────────────────────────────────────────────────────────────────────
iceberg:
format_version: 2 # v2 поддерживает row-level updates/deletes
# Каталог метаданных
# ⚠️ РЕКОМЕНДУЕТСЯ: gravitino (unified metadata catalog)
# Альтернативы: rest | hive | glue
catalog:
type: "gravitino" # gravitino | rest | hive | glue
uri: "http://gravitino-server:8090"
warehouse: "s3://data-lake/warehouse"
database: "sales"
table: "orders"
properties:
"write.format.default": "parquet"
"write.parquet.compression-codec": "zstd"
"write.target-file-size-bytes": "536870912" # 512 MB
"history.expire.min-snapshots-to-keep": "10"
# ───────────────────────────────────────────────────────────────────────────
# ПАРТИЦИОНИРОВАНИЕ (Iceberg Hidden Partitioning)
# ───────────────────────────────────────────────────────────────────────────
partitioning:
strategy: "iceberg_hidden"
spec:
# Time-based partitioning
- source_column: "created_at"
transform: "day" # year | month | day | hour
partition_field: "created_at_day"
reason: "Большинство запросов фильтруют по дате"
# Bucket partitioning для распределения нагрузки
- source_column: "customer_id"
transform: "bucket[16]" # hash mod 16
partition_field: "customer_id_bucket"
reason: "Распределение по customer_id для параллелизма"
evolution:
enabled: true
reason: "Можно менять партиционирование без переписывания данных"
# ───────────────────────────────────────────────────────────────────────────
# СОРТИРОВКА (Iceberg Sort Order)
# ───────────────────────────────────────────────────────────────────────────
sort_order:
enabled: true
fields:
- column: "customer_id"
direction: "asc"
null_order: "nulls-first"
reason: "Частые запросы по customer_id"
- column: "created_at"
direction: "desc"
null_order: "nulls-last"
reason: "Последние заказы первыми"
- column: "order_id"
direction: "asc"
null_order: "nulls-last"
reason: "Детерминизм"
# ───────────────────────────────────────────────────────────────────────────
# PARQUET CONFIGURATION
# ───────────────────────────────────────────────────────────────────────────
parquet:
row_group_size: 134217728 # 128 MB
page_size: 1048576 # 1 MB
compression:
codec: "zstd"
level: 3
reason: "Баланс compression/speed"
column_compression:
- column: "status"
codec: "dictionary"
reason: "6 уникальных значений - dictionary эффективен"
- column: "currency"
codec: "dictionary"
reason: "3 значения - dictionary encoding"
# Bloom filters для point lookups
bloom_filters:
- column: "order_id"
fpp: 0.01
reason: "Частые точечные запросы"
- column: "customer_id"
fpp: 0.01
reason: "Фильтрация по customer_id"
# ───────────────────────────────────────────────────────────────────────────
# COMPACTION & OPTIMIZATION
# ───────────────────────────────────────────────────────────────────────────
compaction:
small_files:
enabled: true
target_file_size_mb: 512
schedule: "0 2 * * *" # Daily at 2 AM
# Z-ordering для multi-dimensional queries
z_order:
enabled: true
columns:
- "customer_id"
- "created_at"
reason: "Оптимизация для запросов по нескольким колонкам"
# ───────────────────────────────────────────────────────────────────────────
# TIME TRAVEL & SNAPSHOTS
# ───────────────────────────────────────────────────────────────────────────
snapshots:
retention:
min_snapshots_to_keep: 10
max_age_days: 30
reason: "Для debugging и rollback"
# Примеры Time Travel:
# SELECT * FROM sales.orders TIMESTAMP AS OF '2026-01-23 10:00:00'
# SELECT * FROM sales.orders VERSION AS OF 123456789
# ───────────────────────────────────────────────────────────────────────────
# QUERY PATTERNS
# ───────────────────────────────────────────────────────────────────────────
query_patterns:
- name: "get_customer_orders"
frequency: "very_high"
query: |
SELECT * FROM sales.orders
WHERE customer_id = 'cust_123'
ORDER BY created_at DESC LIMIT 100
optimization: |
- Partition pruning по customer_id_bucket
- Bloom filter на customer_id
- Sort order → sequential read
# ───────────────────────────────────────────────────────────────────────────
# PERFORMANCE TARGETS
# ───────────────────────────────────────────────────────────────────────────
performance:
point_lookup:
target_latency_p50: "50ms"
target_latency_p99: "200ms"
range_scan:
target_latency_p50: "500ms"
target_latency_p99: "2s"
full_scan:
target_throughput: "1GB/s per core"
# ───────────────────────────────────────────────────────────────────────────
# STORAGE
# ───────────────────────────────────────────────────────────────────────────
storage:
avg_row_size_bytes: 2048
compression_ratio: 4.5 # ZSTD level 3
growth:
daily_rows: 500000
daily_size_compressed_gb: 0.22
annual_size_compressed_tb: 0.08
tiering:
hot:
duration: "P30D"
storage_class: "S3 Standard"
warm:
duration: "P365D"
storage_class: "S3 Intelligent-Tiering"
cold:
duration: "P7Y"
storage_class: "S3 Glacier"
# ───────────────────────────────────────────────────────────────────────────
# MONITORING (Iceberg Metadata Tables)
# ───────────────────────────────────────────────────────────────────────────
monitoring:
metrics:
- name: "table_size_gb"
query: "SELECT SUM(file_size_in_bytes)/1024^3 FROM sales.orders.files"
- name: "small_files_count"
query: "SELECT COUNT(*) FROM sales.orders.files WHERE file_size_in_bytes < 128*1024^2"
maintenance:
- task: "expire_snapshots"
schedule: "0 3 * * 0"
command: "CALL system.expire_snapshots('sales.orders', TIMESTAMP '2026-01-01', 10)"
- task: "compact_small_files"
schedule: "0 2 * * *"
command: "CALL system.rewrite_data_files('sales.orders')"
Ключевые отличия от традиционных БД¶
| Концепция | Традиционная БД | Iceberg + Parquet |
|---|---|---|
| Индексы | B-tree, Hash индексы | Bloom filters, Column statistics |
| Партиционирование | Видно пользователю | Hidden partitioning |
| Сортировка | Физические индексы | Sort order в файлах |
| Компрессия | На уровне таблицы | Column-level + dictionary encoding |
| Schema changes | ALTER TABLE (блокирующие) | Schema evolution (non-blocking) |
| Time Travel | Нет (нужно делать backups) | Встроенная поддержка snapshots |
| Materialized Views | Традиционные MV | Трансформации через Spark/Flink |
Best Practices¶
- File Size: Целевой размер 512MB (баланс между parallelism и overhead)
- Partitioning: Используйте
bucket[N]для high cardinality колонок - Sort Order: Критичен для фильтрации - сортируйте по frequently filtered columns
- Bloom Filters: Добавляйте для ID колонок с point lookups
- Compression: ZSTD level 3 для баланса, Dictionary для enum/low cardinality
- Compaction: Регулярно объединяйте small files (daily/weekly)
- Snapshots: Expire старые snapshots (держите 10+ для debugging)
8. Semantic Versioning для контрактов¶
Правила версионирования¶
| Тип изменения | Файл | Версия | Пример |
|---|---|---|---|
| BREAKING | schema.avsc | MAJOR | 2.0.0 → 3.0.0 |
| - Удаление поля | |||
| - Изменение типа поля | |||
| - Переименование поля | |||
| NON-BREAKING | schema.avsc | MINOR | 2.0.0 → 2.1.0 |
| - Добавление nullable поля | |||
| - Добавление default значения | |||
| PATCH | quality_rules.yml | PATCH | 2.1.0 → 2.1.1 |
| - Новое правило качества | |||
| - Изменение SLA | sla.yml | PATCH | |
| - Обновление описания | contract.yaml | PATCH | |
| NO VERSION CHANGE | physical_layout.yml | - | - |
| - Изменение индексов | |||
| - Изменение партиционирования | |||
| - Обновление runbook | runbook.md | - |
Примеры версионирования¶
MAJOR (Breaking change)¶
# schema.avsc
# БЫЛО:
{"name": "status", "type": "string"}
# СТАЛО (breaking!):
{"name": "status", "type": {"type": "enum", "symbols": ["pending", "confirmed"]}}
# Версия: 1.5.0 → 2.0.0
MINOR (Non-breaking change)¶
# schema.avsc
# Добавлено новое поле с default:
{
"name": "discount_amount",
"type": ["null", "double"],
"default": null
}
# Версия: 2.0.0 → 2.1.0
PATCH¶
# quality_rules.yml
# Добавлено новое правило:
- name: "valid_phone"
type: "regex"
field: "customer_phone"
pattern: "^\\+?[1-9]\\d{1,14}$"
# Версия: 2.1.0 → 2.1.1
9. CI/CD валидация¶
CI/CD должен проверять:
- contract.yaml:
- Корректность YAML синтаксиса
- Наличие всех обязательных полей
- Существование ссылаемых файлов
-
Соответствие semantic versioning
-
schema.avsc:
- Корректность Avro schema
- Breaking changes detection
-
Backward compatibility
-
quality_rules.yml:
- Корректность синтаксиса
- Валидность выражений
-
Ссылки на существующие поля
-
sla.yml:
- Корректность ISO 8601 duration
-
Валидность процентов
-
physical_layout.yml:
- Ссылки на существующие поля в schema
- Валидность SQL в materialized views
См. 07_cicd_pipeline.md для деталей.
10. Migration Guide¶
При переходе с единого YAML на несколько файлов:
# Скрипт для миграции
python scripts/migrate_contract_to_multifile.py \
--input contracts/domains/sales/orders/contract.yaml \
--output contracts/domains/sales/orders/
Скрипт создаст: - contract.yaml (метаданные) - schema.avsc (из секции schema) - quality_rules.yml (из секции quality_rules) - sla.yml (из секции sla) - physical_layout.yml (новый, шаблон)