Andrey Epifancev 43cbfe8e38 docs: change slice-0-skeleton под факты платформы — NATS без JetStream, Python 3.11, без CI и Nexus
Обмен с ядром на core NATS: подписка queue group, ack status=processing сразу по получении, process-local
LRU job_id против повторных запросов, публикация результата с повторами; удалены durable consumer / max_deliver /
ack_wait. Dockerfile python:3.11-slim; make check / make check-full вместо CI; raisa_* фильтруются при
dev-установке. Обновлены proposal, design (решения без обсуждения), specs, tasks, CLAUDE.md, openspec/config.yaml.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 16:21:42 +04:00

4.7 KiB
Raw Blame History

Spec Delta: data-model

Purpose

Схема базы данных ядра совпадает с моделью данных DBML v5.13 один в один: таблицы, колонки, типы, enum'ы, ключи и индексы; миграции применяются к пустой базе и полностью откатываются; расхождение между ORM и DBML невозможно пропустить.

ADDED Requirements

Requirement: Схема БД равна DBML v5.13

ORM-метаданные SHALL содержать ровно 43 таблицы и 27 enum'ов из ../docs/model/data-model-v5.13.dbml в схеме dkb; имена таблиц, колонок, enum'ов и их значений SHALL совпадать с DBML буквально; nullability, PK, UNIQUE, FK, значения по умолчанию и индексы SHALL соответствовать DBML, включая частичные уникальные индексы (related_group_member WHERE is_current, consolidation_lock WHERE released_at IS NULL) и NULLS NOT DISTINCT на document (stored_file_id, document_type, osv_account_code). Поля, отсутствующие в DBML, MUST NOT существовать.

Scenario: Сверка ORM с DBML

  • WHEN выполняется python scripts/check_dbml_vs_orm.py ../../docs/model/data-model-v5.13.dbml
  • THEN вывод пуст и код возврата 0

Scenario: Лишняя колонка в ORM

  • WHEN в ORM добавлена колонка, которой нет в DBML (или удалена существующая)
  • THEN скрипт печатает таблица.колонка: отсутствует в DBML (или отсутствует в ORM) и возвращает код 1

Scenario: Расхождение типа или nullability

  • WHEN колонка osv_entry.opening_debit объявлена в ORM как Numeric(18, 4) или NOT NULL
  • THEN скрипт сообщает ожидалось numeric(18,2) NULL / фактически numeric(18,4) NOT NULL и возвращает код 1

Requirement: Миграции применяются с нуля и откатываются

Единственная ревизия 0001 SHALL создавать схему dkb (если нет), все enum'ы, таблицы, ограничения и индексы на пустой базе PostgreSQL 16 (требуется ≥ 15); downgrade SHALL удалять всё созданное, оставляя пустую схему; повторный upgrade после downgrade SHALL проходить без ошибок.

Scenario: Полный цикл

  • WHEN на пустой БД выполняются alembic upgrade head, alembic downgrade base, alembic upgrade head
  • THEN все три команды завершаются успешно, после последней в information_schema.tables схемы dkb 43 таблицы и в pg_type 27 enum-типов

Scenario: Автогенерация ничего не находит

  • WHEN после upgrade head выполняется alembic revision --autogenerate на той же БД
  • THEN сгенерированная ревизия не содержит операций (пустые upgrade/downgrade)

Requirement: Версия DBML зафиксирована в коде

Пакет моделей SHALL объявлять константу версии DBML (5.13); скрипт сверки SHALL сравнивать её с версией в шапке файла DBML и падать при расхождении — смена модели без осознанного обновления ORM невозможна.

Scenario: Новая версия DBML без обновления ORM

  • WHEN в docs/model/ появляется data-model-v5.14.dbml, а константа в ORM — 5.13
  • THEN сверка против нового файла падает с сообщением о версии до сравнения таблиц

Requirement: Деньги и проценты — точные типы

Все денежные колонки SHALL быть numeric(18,2), проценты — numeric(7,4)/numeric(9,4), уверенность — numeric(5,2); ORM SHALL отдавать их как Decimal, float в моделях MUST NOT встречаться.

Scenario: Чтение денежной колонки

  • WHEN из osv_entry читается строка со closing_debit = 106311116.46
  • THEN значение имеет тип Decimal и равно Decimal("106311116.46")