Фисирую состояние

This commit is contained in:
2026-04-10 15:15:13 +03:00
parent 4e3435ad92
commit acac19da71
37 changed files with 1136 additions and 44 deletions
@@ -42,7 +42,8 @@
### Sections ### Sections
- `sections/summary.md` - `sections/summary.md`
- `sections/details.md` - `sections/details.md`
- `sections/api-scenario.md` - `sections/tech-use-case.md`
- `sections/fr.md`
- `sections/api-contract.md` - `sections/api-contract.md`
- `sections/requirements-format.md` - `sections/requirements-format.md`
@@ -25,6 +25,7 @@
## Особые правила ## Особые правила
- Во frontmatter обязательно указывать `endpoint` (например: `POST /api/v1/clients/contacts-dgr`).
- Сценарий оформляется как технический use case. - Сценарий оформляется как технический use case.
- Функциональные требования маркируются `FR-*`. - Функциональные требования маркируются `FR-*`.
- Нефункциональные требования маркируются `NFR-*`. - Нефункциональные требования маркируются `NFR-*`.
@@ -47,6 +47,7 @@ system_analytics_refs: []
- `module` — модуль или подсистема. - `module` — модуль или подсистема.
- `layer` — слой системы. - `layer` — слой системы.
- `updated_at` хранится в формате `YYYY-MM-DD`. - `updated_at` хранится в формате `YYYY-MM-DD`.
- Для документов с `doc_type: api_method` поле `endpoint` является обязательным.
## Связи и навигация ## Связи и навигация
@@ -1,21 +0,0 @@
# API Scenario Rules
## Назначение
Этот файл описывает, как оформлять подраздел `### Сценарий` в API-документах.
## Обязательные части
- название
- предусловия
- триггер
- основной сценарий
- альтернативный сценарий
- обработка ошибок
- постусловие
## Правила
- Сценарий должен быть лаконичным.
- Сценарий должен отражать суть шага.
- Сложные технические детали надо выносить в `FR-*`.
@@ -0,0 +1,37 @@
# Functional requrements rules
## Назначение
Этот файл описывает, как оформлять функциональные требования в подраздел `### Функциональные требования` в документах.
## Правила
- Функциональное требование (FR) расширяет и дополняет шаги, описанные в сценарии.
- Функциональное требование (FR) не должно копировать шаг сценария не неся дополнительной информации.
- Название функционального требования формируется следующим образом - "FR.<номер>. <Название>", где
- <номер> идет инкрементально внутри конкретного документа, начинается с 1.
- <Название> - кратко описывает что делает требование, суть действий (от 3 до 7 слов)
## Пример целевого описания сценария
### Примеры названия FR
- Получение данных клиента из АС ЕПК
- Проверка уровня доступа
- Сценарий построения списка связанных предложений
### Примеры описания FR
FR.1. Получение данных клиента из АС ЕПК
1. Сформировать запрос к эндпоинту POST /api/v1/path/to/resourse в АС ЕПК
- Заголовки
- <тут идет описание заголовков и того как они формируются>
- Параметры запроса
- <тут идет описание параметров и того как они формируются>
- Тело запроса
- <тут идет описание структуры объекта JSON или payload в другмо формате так как это задано требованиями>
2. Обработать ответ от АС ЕПК
Успешный ответ - <взять из описания вызываеого api критерии успешного ответа >
Ничего не найдено - <взять из описания вызываеого api критерии успешного овтета, опционально (если применимо)>
Ошибка - <взять из описания вызываеого api критерии успешного ответа >
@@ -0,0 +1,66 @@
# Scenario Rules
## Назначение
Этот файл описывает, как оформлять технический USE CASE в подраздел `### Сценарий` в документах.
## Обязательные части
- название
- предусловия
- триггер
- основной сценарий
- альтернативный сценарий
- обработка ошибок
- постусловие
## Правила
- Основной и альтернативные сценарии состоят из шагов.
- Каждый шаг описывается одним предложением не более 15-20 слов, и состоит из двух частей. Первая часть описывает что мы делаем по смыслу, чтобы это было понятно человеку без низкоуровневых технических деталей. Например: авторизует запрос, получает данные клиента, запрашивает справочники. Вторая часть описывает как это реализовано технически - вызывает эндпоинт /path/to/resource в системе <название системы>.
- В описании шага не должно быть длинных технических деталей. Если техничсекую реализацию нельхзя описатьодним предложенеим (в лимите длины описания шага), то необхлодимо это вынести в отдельное функциональное требование FR.<номер>. <Название> и описать в нем технические детали. А в шаге сослаться на это требование через "Описание приведено в FR.<номер>. <Название>"
- Для шагов авторизации обязателен доп шаг с описанием обработки ошибки.
- Для шагов с интеграцией обязателен доп шаг с описанием обработки ошибки.
- Для шагов с проверкой условий обязательны доп шаги с описанием переходов по сценарию.
- Название "FR.<номер>. <Название>" формируется следующим образом:
- <номер> идет инкрементально внутри конкретного документа, начинается с 1.
- <Название> - кратко описывает что делает требование, суть действий.
- Для каждого шага при необходимости нужно прописать логику действий в случае ошибки или если логика шага определяет несколько сценариев разивития при выполнении заданных условий.
- Для шагов, которые описывают интеграцию с другой системой необходимо указать название точки интеграции (название эндпоинта, название топика и так далее) и сделать ссылку на FR.<номер>. <Название> с описанием шагов интеграции - как сформировать запрос/сообщение, как обработать ответ, политику ретраев.
- Сценарий собирается из тезисов, приведенных системной аналимтике в свободной формулировке
- Функциональные требования "FR.<номер>. <Название>" не должны дублировать шагов сценария в use case. Они содержат детали, которые вынесены из юзкейса чтобы не делать его тяжелым. Если шаг юзкейса описывается одним предложением в лимите длины, то FR делать не нужно.
- FR обязательно описывается для шага с интеграцией
- FR Не описывается для шага авторизации.
## Пример целевого описания сценария
### Примеры шагов сценария
Пример 1
- Авторизует запрос пользователя по наличию у него экшена ролевой модели CI02792632.ContactsDGR.Detail
- В случае ошибки - завершить сценарий с кодом UNAUTHORIZED
Пример 2
- Запрашивает данные клиента - вызывает /api/v1/clients/{client-id}/info
- В случае ошибки - завершить сценарий с кодом CLIENT_INFO_REQUEST_FAIL
Пример 3
- Возвращает ответ в формате <название DTO>
### Примеры названия FR
- Получение данных клиента из АС ЕПК
- Проверка уровня доступа
- Сценарий построения списка связанных предложений
@@ -8,6 +8,7 @@ module: example_module
layer: application layer: application
domain: example_domain domain: example_domain
sub_domain: example_subdomain sub_domain: example_subdomain
endpoint: POST /api/v1/example
related_docs: [] related_docs: []
status: draft status: draft
updated_at: 2026-03-20 updated_at: 2026-03-20
@@ -0,0 +1,27 @@
# Documentation Rules V2
Этот каталог — новая структура правил для DOC_UPDATE/FROM_FEATURE.
## Цель
Разделить инструкции на 2 независимых блока:
1. `types/` — инструкции по структуре конкретных типов документов (`ui_page`, `api_method`, и т.д.).
2. `common-elements/` — инструкции по структуре общих элементов страницы (`tech-use-case`, `fr`, и др.).
## Структура каталога
- `documentation-rules.md` — верхнеуровневые правила.
- `global/` — общие правила оформления и frontmatter.
- `types/` — правила по типам документов (вместо `artifact-types/`).
- `common-elements/` — правила по общим секциям (вместо `sections/`).
- `templates/` — шаблоны документов.
## Переключение профиля
Загрузчик поддерживает переключение через env:
- `DOC_RULES_PROFILE=v2` (по умолчанию) — использовать `doc_rules_v2`.
- `DOC_RULES_PROFILE=legacy` — использовать старый каталог `doc_rules`.
Если `v2` не содержит валидных пар `type + template`, загрузчик автоматически fallback на `doc_rules`.
@@ -0,0 +1,24 @@
# API Contract Rules
## Назначение
Этот файл описывает, как оформлять подраздел `## Контракт` в API-документах.
## Что должно быть описано
- входные параметры
- выходные параметры
- JSON-структуры запросов и ответов
- обязательность полей
- типы полей
- ограничения
- описание назначения полей
- примеры данных
- auth
- idempotency
- timeout
- ошибки и их HTTP-коды
## Правило качества
Контракт должен быть достаточно формальным, чтобы по нему можно было собрать OpenAPI-спецификацию.
@@ -0,0 +1,13 @@
# Details Section Rules
## Назначение
Этот файл задает общие правила для секции `## Details`.
## Правила
- `Details` оформляется как `## Details`.
- Внутри `Details` используются заголовки уровня `###` и ниже.
- Структура Details зависит от типа документа.
- В Details не нужно повторно дублировать навигацию и связи, если они уже есть во frontmatter.
- Интеграции, ошибки и кодовые привязки должны быть выделены в отдельные подразделы, если они существенны для понимания документа.
@@ -0,0 +1,37 @@
# Functional requrements rules
## Назначение
Этот файл описывает, как оформлять функциональные требования в подраздел `### Функциональные требования` в документах.
## Правила
- Функциональное требование (FR) расширяет и дополняет шаги, описанные в сценарии.
- Функциональное требование (FR) не должно копировать шаг сценария не неся дополнительной информации.
- Название функционального требования формируется следующим образом - "FR.<номер>. <Название>", где
- <номер> идет инкрементально внутри конкретного документа, начинается с 1.
- <Название> - кратко описывает что делает требование, суть действий (от 3 до 7 слов)
## Пример целевого описания сценария
### Примеры названия FR
- Получение данных клиента из АС ЕПК
- Проверка уровня доступа
- Сценарий построения списка связанных предложений
### Примеры описания FR
FR.1. Получение данных клиента из АС ЕПК
1. Сформировать запрос к эндпоинту POST /api/v1/path/to/resourse в АС ЕПК
- Заголовки
- <тут идет описание заголовков и того как они формируются>
- Параметры запроса
- <тут идет описание параметров и того как они формируются>
- Тело запроса
- <тут идет описание структуры объекта JSON или payload в другмо формате так как это задано требованиями>
2. Обработать ответ от АС ЕПК
Успешный ответ - <взять из описания вызываеого api критерии успешного ответа >
Ничего не найдено - <взять из описания вызываеого api критерии успешного овтета, опционально (если применимо)>
Ошибка - <взять из описания вызываеого api критерии успешного ответа >
@@ -0,0 +1,16 @@
# Requirements Format Rules
## Назначение
Этот файл задает формат для функциональных и нефункциональных требований.
## Функциональные требования
- Использовать коды `FR-1`, `FR-2`, `FR-3` и так далее.
- Каждое требование должно описывать отдельный обязательный аспект поведения.
- Идентификаторы локальны в пределах одного документа.
## Нефункциональные требования
- Использовать коды `NFR-1`, `NFR-2`, `NFR-3` и так далее.
- Требования должны описывать характеристики качества, ограничения и эксплуатационные свойства.
@@ -0,0 +1,13 @@
# Summary Section Rules
## Назначение
Этот файл задает правила для секции `## Summary`.
## Правила
- Summary должен быть коротким explain-слоем быстрого контекста.
- Summary должен объяснять суть документа без лишних деталей.
- Summary должен быть пригоден для explain и быстрого чтения.
- Предпочтительный формат: список ключевых фактов `Purpose`, `Actor`, `Trigger`, `Errors`, `Related ...` и т.д.
- Для крупных документов допустим более длинный summary, если он остается структурированным.
@@ -0,0 +1,66 @@
# Scenario Rules
## Назначение
Этот файл описывает, как оформлять технический USE CASE в подраздел `### Сценарий` в документах.
## Обязательные части
- название
- предусловия
- триггер
- основной сценарий
- альтернативный сценарий
- обработка ошибок
- постусловие
## Правила
- Основной и альтернативные сценарии состоят из шагов.
- Каждый шаг описывается одним предложением не более 15-20 слов, и состоит из двух частей. Первая часть описывает что мы делаем по смыслу, чтобы это было понятно человеку без низкоуровневых технических деталей. Например: авторизует запрос, получает данные клиента, запрашивает справочники. Вторая часть описывает как это реализовано технически - вызывает эндпоинт /path/to/resource в системе <название системы>.
- В описании шага не должно быть длинных технических деталей. Если техничсекую реализацию нельхзя описатьодним предложенеим (в лимите длины описания шага), то необхлодимо это вынести в отдельное функциональное требование FR.<номер>. <Название> и описать в нем технические детали. А в шаге сослаться на это требование через "Описание приведено в FR.<номер>. <Название>"
- Для шагов авторизации обязателен доп шаг с описанием обработки ошибки.
- Для шагов с интеграцией обязателен доп шаг с описанием обработки ошибки.
- Для шагов с проверкой условий обязательны доп шаги с описанием переходов по сценарию.
- Название "FR.<номер>. <Название>" формируется следующим образом:
- <номер> идет инкрементально внутри конкретного документа, начинается с 1.
- <Название> - кратко описывает что делает требование, суть действий.
- Для каждого шага при необходимости нужно прописать логику действий в случае ошибки или если логика шага определяет несколько сценариев разивития при выполнении заданных условий.
- Для шагов, которые описывают интеграцию с другой системой необходимо указать название точки интеграции (название эндпоинта, название топика и так далее) и сделать ссылку на FR.<номер>. <Название> с описанием шагов интеграции - как сформировать запрос/сообщение, как обработать ответ, политику ретраев.
- Сценарий собирается из тезисов, приведенных системной аналимтике в свободной формулировке
- Функциональные требования "FR.<номер>. <Название>" не должны дублировать шагов сценария в use case. Они содержат детали, которые вынесены из юзкейса чтобы не делать его тяжелым. Если шаг юзкейса описывается одним предложением в лимите длины, то FR делать не нужно.
- FR обязательно описывается для шага с интеграцией
- FR Не описывается для шага авторизации.
## Пример целевого описания сценария
### Примеры шагов сценария
Пример 1
- Авторизует запрос пользователя по наличию у него экшена ролевой модели CI02792632.ContactsDGR.Detail
- В случае ошибки - завершить сценарий с кодом UNAUTHORIZED
Пример 2
- Запрашивает данные клиента - вызывает /api/v1/clients/{client-id}/info
- В случае ошибки - завершить сценарий с кодом CLIENT_INFO_REQUEST_FAIL
Пример 3
- Возвращает ответ в формате <название DTO>
### Примеры названия FR
- Получение данных клиента из АС ЕПК
- Проверка уровня доступа
- Сценарий построения списка связанных предложений
@@ -0,0 +1,71 @@
# Documentation Rules
Этот каталог оформляет MVP документации проекта в атомарном формате.
## Базовая структура
- Каждый документ содержит YAML frontmatter.
- В документе должен быть один `H1`, совпадающий с `title`.
- Основные разделы оформляются как `## Summary` и `## Details`.
- Внутри `Details` используются заголовки уровня `###` и ниже.
- Связи, сущности и навигация описываются во frontmatter через `related_docs`, `links`, `entities`, `parent`, `children`.
## Summary
- Краткий explain-слой быстрого контекста.
- Должен позволять быстро понять назначение документа без чтения `Details`.
- Предпочтительный формат: компактный список ключевых фактов без длинных абзацев.
## Details
- Раскрывает полное описание объекта.
- Структура `Details` зависит от типа документа.
- Сценарии, ограничения, интеграции, ошибки и кодовые привязки должны быть разнесены по отдельным подразделам.
## API documents
Для `api_method` внутри `## Details` обязательны разделы:
- `### Описание`
- `### Сценарий`
- `### Функциональные требования`
- `### Нефункциональные требования`
- `### Контракт`
Если у метода есть интеграции и ошибки, также обязательны:
- `### Интеграции`
- `### Ошибки`
- `### Связанный код`
- `### История изменений`
### Сценарий
Сценарий оформляется как технический use case и содержит:
- название
- предусловия
- триггер
- основной сценарий
- альтернативный сценарий
- обработку ошибок
- постусловие
### Требования
- Функциональные требования маркируются как `FR-1`, `FR-2`, ...
- Нефункциональные требования маркируются как `NFR-1`, `NFR-2`, ...
- Идентификаторы требований локальны в рамках одного документа.
### Контракт
Контракт должен быть пригоден для последующей сборки OpenAPI-спецификации и включать:
- входные параметры
- выходные параметры
- структуру JSON-сообщений
- обязательность полей
- типы и ограничения
- описание полей
- правила заполнения
- примеры данных
- auth
- idempotency
- timeout
- ошибки и их HTTP-коды
@@ -0,0 +1,38 @@
# Documentation System
## Назначение
Этот файл задает общую модель документации проекта.
## Базовая модель
Каждый документ должен состоять из двух слоев:
- YAML frontmatter
- контент
Контент всегда состоит из двух обязательных разделов:
- `## Summary`
- `## Details`
Над ними должен быть один заголовок `# <title>`, совпадающий со значением `title` во frontmatter.
## Принципы
- Документы должны быть атомарными.
- Один документ описывает одну тему.
- Вместо дублирования между документами используются явные ссылки.
- Связи и навигация должны быть формализованы.
- Документы должны быть пригодны для чтения человеком и для RAG.
- Документы должны быть пригодны для частичного обновления без деградации структуры.
## Типы документов
На уровне проекта поддерживаются типы:
- `api_method`
- `logic_block`
- `architecture_overview`
- `domain_entity`
- `ui_page`
- `integration_doc`
- `index_page`
- `glossary_item`
@@ -0,0 +1,67 @@
# Frontmatter Rules
## Назначение
Этот файл описывает единый контракт YAML frontmatter для всех документов.
## Обязательные поля
```yaml
id: string
title: string
doc_type: string
domain: string
sub_domain: string
related_docs: []
status: string
```
## Поля совместимости и рекомендуемые поля
```yaml
type: string
name: string
module: string
layer: string
updated_at: YYYY-MM-DD
tags: []
entities: []
parent: string | null
children: []
links: {}
source_of_truth: string
related_code: []
system_analytics_refs: []
```
## Правила
- `id` должен быть стабильным и уникальным в пределах документации проекта.
- `title` — человекочитаемый заголовок.
- `doc_type` — канонический тип документа.
- `domain` и `sub_domain` определяют бизнес-контекст документа.
- `related_docs` хранит явные связи с другими markdown-документами.
- `status` хранит жизненный цикл документа: например `draft`, `approved`, `active`.
- `type` допустимо дублировать как alias для tooling-совместимости с индексаторами.
- `name` — короткое системное имя документа.
- `module` — модуль или подсистема.
- `layer` — слой системы.
- `updated_at` хранится в формате `YYYY-MM-DD`.
## Связи и навигация
- `entities` описывает сущности, связанные с документом.
- `parent` и `children` описывают иерархию.
- `links` описывает typed graph связей между документами, кодом и интеграциями.
## Формат links
```yaml
links:
called_by:
- ext.health_probe
uses_logic:
- logic.some_flow
integrates_with:
- ext.some_system
```
@@ -0,0 +1,33 @@
# Linking Rules
## Назначение
Этот файл описывает, как связывать документы между собой.
## Иерархия
- `parent` используется для родительского документа.
- `children` используется для прямых дочерних документов.
- Иерархия должна быть осмысленной и стабильной.
- Для общей точки входа допустим `index_page`.
## Графовые связи
Для `related_docs` используются ссылки на соседние документы.
Для `links` рекомендуется использовать typed-ключи:
- `called_by`
- `uses_logic`
- `reads_db`
- `writes_db`
- `integrates_with`
- `used_by`
- `exposes_api`
- `uses_entities`
## Правила использования
- Если документ логически входит в другой, использовать `parent`/`children`.
- Если связь нужна для навигации между равноправными документами, дублировать ее в `related_docs`.
- Если связь отражает поведение, интеграции или переиспользование, фиксировать ее в `links`.
- Детальное описание интеграций хранить в body документа, а не только во frontmatter.
@@ -0,0 +1,24 @@
# Naming Rules
## Назначение
Этот файл описывает правила именования документов, файлов и идентификаторов.
## Правила для файлов
- Имена файлов должны быть в kebab-case.
- Имя файла должно отражать одну тему.
- Для шаблонов использовать суффикс `.template.md`.
## Правила для id
- `id` строится в формате `<type-group>.<name>`.
- Примеры:
- `api.send_message_endpoint`
- `logic.telegram_notification_loop`
- `architecture.telegram_notify_app`
## Правила для title
- `title` должен быть кратким и человекочитаемым.
- В `title` допускаются пробелы и естественный язык.
@@ -0,0 +1,19 @@
# Writing Style
## Назначение
Этот файл задает правила стиля для текстового наполнения документации.
## Правила стиля
- Текст должен быть лаконичным.
- Формулировки должны быть точными и техническими.
- Summary должен быть кратким explain-слоем.
- Details должен раскрывать суть без лишней воды.
- Нежелательно смешивать несколько тем в одном документе.
- Если детали относятся к другому артефакту, их нужно выносить в отдельный документ.
## Язык
- Основной язык документации — русский.
- Технические термины, названия классов, API, RAG, OpenAPI, runtime и другие устоявшиеся identifiers можно оставлять на английском.
@@ -0,0 +1,84 @@
---
id: api.example_method
type: api_method
doc_type: api_method
name: example_method
title: HTTP API /example
module: example_module
layer: application
domain: example_domain
sub_domain: example_subdomain
related_docs: []
status: draft
updated_at: 2026-03-20
source_of_truth: code
parent: null
children: []
tags: []
entities: []
links: {}
---
# HTTP API /example
## Summary
Краткое описание метода.
## Details
## Описание
Короткое описание сути метода.
## Сценарий
**Название:**
**Предусловия:**
-
**Триггер:**
-
**Основной сценарий:**
1.
**Альтернативный сценарий:**
1.
**Обработка ошибок:**
1.
**Постусловие:**
-
## Функциональные требования
**FR-1.**
## Нефункциональные требования
**NFR-1.**
## Контракт
### Входные параметры
| Параметр | Где передается | Тип | Обязательность | Ограничения | Описание | Пример |
|---|---|---|---|---|---|---|
| | | | | | | |
### Выходные параметры
| Поле | Тип | Обязательность | Ограничения | Описание | Заполнение | Пример |
|---|---|---|---|---|---|---|
| | | | | | | |
### Интеграции
### Ошибки
### Связанный код
### История изменений
@@ -0,0 +1,48 @@
---
id: architecture.example_system
type: architecture_overview
doc_type: architecture_overview
name: example_system
title: Обзор архитектуры Example System
module: example_module
layer: system
domain: example_domain
sub_domain: example_subdomain
related_docs: []
status: draft
updated_at: 2026-03-20
source_of_truth: mixed
parent: null
children: []
tags: []
entities: []
links: {}
---
# Обзор архитектуры Example System
## Summary
Краткое описание архитектуры.
## Details
### Описание
### Контекст
### Границы системы
### Компоненты
### Интеграционные сценарии
### Интеграции
### Ограничения
### Связанный код
### Связанные документы
### История изменений
@@ -0,0 +1,48 @@
---
id: domain.example_entity
type: domain_entity
doc_type: domain_entity
name: example_entity
title: Пример доменной сущности
module: example_module
layer: domain
domain: example_domain
sub_domain: example_subdomain
related_docs: []
status: draft
updated_at: 2026-03-20
source_of_truth: code
parent: null
children: []
tags: []
entities: []
links: {}
---
# Пример доменной сущности
## Summary
Краткое описание сущности.
## Details
### Описание
### Модель данных
### Состояния и инварианты
### Технический use case
### Функциональные требования
### Нефункциональные требования
### Интеграции
### Связанный код
### Связанные документы
### История изменений
@@ -0,0 +1,50 @@
---
id: logic.example_block
type: logic_block
doc_type: logic_block
name: example_block
title: Пример блока логики
module: example_module
layer: application
domain: example_domain
sub_domain: example_subdomain
related_docs: []
status: draft
updated_at: 2026-03-20
source_of_truth: code
parent: null
children: []
tags: []
entities: []
links: {}
---
# Пример блока логики
## Summary
Краткое описание блока логики.
## Details
### Описание
### Контекст
### Технический use case
### Функциональные требования
### Нефункциональные требования
### Интеграции
### Ограничения и условия вызова
### Ошибки и деградации
### Связанные API
### Связанный код
### История изменений
@@ -0,0 +1,50 @@
---
id: ui.example_page
type: ui_page
doc_type: ui_page
name: example_page
title: Пример UI-страницы
module: example_module
layer: presentation
domain: example_domain
sub_domain: example_subdomain
related_docs: []
status: draft
updated_at: 2026-03-20
source_of_truth: mixed
parent: null
children: []
tags: []
entities: []
links: {}
---
# Пример UI-страницы
## Summary
Краткое описание страницы и её назначения.
## Details
### Назначение страницы
### Пользовательский сценарий
### Основные блоки интерфейса
### Связанные API и сущности
### Функциональные требования
### Нефункциональные требования
### Ограничения и граничные случаи
### Ошибки и валидации
### Связанный код
### Связанные документы
### История изменений
@@ -0,0 +1,39 @@
# API Method Rules
## Назначение
Этот файл задает правила для документов типа `api_method`.
## Когда использовать
Использовать для описания одного HTTP endpoint или одного отдельного API метода.
## Обязательная структура
Документ должен содержать:
- YAML frontmatter
- `# <title>`
- `## Summary`
- `## Details`
Внутри `## Details` обязательны:
- `### Описание`
- `### Сценарий`
- `### Функциональные требования`
- `### Нефункциональные требования`
- `### Контракт`
## Особые правила
- Сценарий оформляется как технический use case.
- Функциональные требования маркируются `FR-*`.
- Нефункциональные требования маркируются `NFR-*`.
- Контракт должен быть пригоден для последующей сборки OpenAPI.
- Если у метода есть интеграции, они выносятся в `### Интеграции`.
- Ошибки и HTTP-коды либо описываются в `### Ошибки`, либо ссылаются на централизованный каталог ошибок.
## Ошибки оформления
- Нельзя заменять контракт общим текстовым описанием.
- Нельзя смешивать несколько endpoint в одном документе.
- Нельзя хранить связи и навигацию вне frontmatter.
@@ -0,0 +1,31 @@
# Architecture Overview Rules
## Назначение
Этот файл задает правила для документов типа `architecture_overview`.
## Когда использовать
Использовать как входной документ для понимания системы, модуля или сервиса.
## Обязательная структура
Документ должен содержать:
- YAML frontmatter
- `# <title>`
- `## Summary`
- `## Details`
## Что описывать в Details
- границы системы
- основные компоненты
- ключевые взаимодействия
- интеграционные сценарии
- главные ограничения
- ссылки на дочерние документы по API, logic, domain и другим артефактам
## Ошибки оформления
- Нельзя дублировать в архитектурном обзоре полные API-контракты.
- Нельзя делать архитектурный обзор единственным документом на всю систему без декомпозиции.
@@ -0,0 +1,30 @@
# Domain Entity Rules
## Назначение
Этот файл задает правила для документов типа `domain_entity`.
## Когда использовать
Использовать для описания одной доменной сущности, ее смысла, состояния и роли в системе.
## Обязательная структура
Документ должен содержать:
- YAML frontmatter
- `# <title>`
- `## Summary`
- `## Details`
## Что описывать в Details
- смысл сущности
- ключевые атрибуты
- состояния или инварианты
- использование сущности в системе
- интеграции с API, workflow или внешними потребителями, если они важны для понимания модели
## Ошибки оформления
- Нельзя смешивать несколько независимых сущностей в одном документе.
- Нельзя подменять доменную сущность описанием endpoint или workflow.
@@ -0,0 +1,25 @@
# Integration Doc Rules
## Назначение
Этот файл задает правила для документов типа `integration_doc`.
## Когда использовать
Использовать для описания интеграции между системами, сервисами или внешними провайдерами.
## Обязательная структура
Документ должен содержать:
- YAML frontmatter
- `# <title>`
- `## Summary`
- `## Details`
## Что описывать в Details
- цель интеграции
- участвующие стороны
- направление обмена
- ключевой сценарий взаимодействия
- ограничения и риски
@@ -0,0 +1,31 @@
# Logic Block Rules
## Назначение
Этот файл задает правила для документов типа `logic_block`.
## Когда использовать
Использовать для описания одного законченного блока логики, workflow или процесса.
## Обязательная структура
Документ должен содержать:
- YAML frontmatter
- `# <title>`
- `## Summary`
- `## Details`
## Что описывать в Details
- назначение логического блока
- входы и выходы
- последовательность выполнения
- интеграции
- ключевые ограничения
- состояние и ошибки, если они важны для понимания блока
## Ошибки оформления
- Нельзя описывать весь модуль целиком, если логика распадается на несколько независимых блоков.
- Нельзя превращать документ в пересказ исходного кода построчно.
@@ -0,0 +1,24 @@
# UI Page Rules
## Назначение
Этот файл задает правила для документов типа `ui_page`.
## Когда использовать
Использовать для описания одной пользовательской страницы, экрана или отдельного UI-сценария.
## Обязательная структура
Документ должен содержать:
- YAML frontmatter
- `# <title>`
- `## Summary`
- `## Details`
## Что описывать в Details
- назначение страницы
- пользовательский сценарий
- основные блоки интерфейса
- связанные API и сущности
@@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import os
from pathlib import Path from pathlib import Path
from app.core.agent.processes.v2.workflows.doc_update_from_feature.doc_rules_pipeline.models import DocRulesBundle from app.core.agent.processes.v2.workflows.doc_update_from_feature.doc_rules_pipeline.models import DocRulesBundle
@@ -7,20 +8,45 @@ from app.core.agent.processes.v2.workflows.doc_update_from_feature.doc_rules_pip
class DocRulesLoader: class DocRulesLoader:
def __init__(self, root: Path | None = None) -> None: def __init__(self, root: Path | None = None) -> None:
base = root or (Path(__file__).resolve().parents[3] / "doc_rules") base_dir = Path(__file__).resolve().parents[3]
self._root = base if root is not None:
self._root = root
return
profile = os.getenv("DOC_RULES_PROFILE", "legacy").strip().lower()
if profile == "legacy":
self._root = base_dir / "doc_rules"
return
self._root = base_dir / "doc_rules_v2"
@property @property
def root(self) -> Path: def root(self) -> Path:
return self._root return self._root
def load(self) -> DocRulesBundle: def load(self) -> DocRulesBundle:
bundle = self._load_from_root(self._root)
if bundle.supported_doc_types:
return bundle
# Safe fallback for quick rollback or incomplete v2 setup.
fallback = self._root.parent / "doc_rules"
if fallback != self._root:
fallback_bundle = self._load_from_root(fallback)
if fallback_bundle.supported_doc_types:
return fallback_bundle
return bundle
def _load_from_root(self, root: Path) -> DocRulesBundle:
artifact_rules = self._read_folder(root / "artifact-types", suffix=".md")
if not artifact_rules:
artifact_rules = self._read_folder(root / "types", suffix=".md")
sections = self._read_folder(root / "sections", suffix=".md")
if not sections:
sections = self._read_folder(root / "common-elements", suffix=".md")
return DocRulesBundle( return DocRulesBundle(
documentation_rules=self._read_file(self._root / "documentation-rules.md"), documentation_rules=self._read_file(root / "documentation-rules.md"),
global_rules=self._read_folder(self._root / "global", suffix=".md"), global_rules=self._read_folder(root / "global", suffix=".md"),
artifact_rules=self._read_folder(self._root / "artifact-types", suffix=".md"), artifact_rules=artifact_rules,
templates=self._read_templates(self._root / "templates"), templates=self._read_templates(root / "templates"),
sections=self._read_folder(self._root / "sections", suffix=".md"), sections=sections,
) )
def _read_templates(self, folder: Path) -> dict[str, str]: def _read_templates(self, folder: Path) -> dict[str, str]:
@@ -5,14 +5,14 @@ from app.core.agent.processes.v2.workflows.doc_update_from_feature.doc_rules_pip
class DocRulesSelector: class DocRulesSelector:
_DEFAULT_SECTIONS: tuple[str, ...] = ("summary", "details", "requirements-format") _DEFAULT_SECTIONS: tuple[str, ...] = ("summary", "details", "tech-use-case", "fr", "requirements-format")
_SECTIONS_BY_TYPE: dict[str, tuple[str, ...]] = { _SECTIONS_BY_TYPE: dict[str, tuple[str, ...]] = {
"api_method": ("summary", "details", "api-scenario", "api-contract", "requirements-format"), "api_method": ("summary", "details", "tech-use-case", "fr", "api-contract", "requirements-format"),
"integration_doc": ("summary", "details", "api-contract", "requirements-format"), "integration_doc": ("summary", "details", "tech-use-case", "fr", "api-contract", "requirements-format"),
"ui_page": ("summary", "details", "requirements-format"), "ui_page": ("summary", "details", "tech-use-case", "fr", "requirements-format"),
"logic_block": ("summary", "details", "requirements-format"), "logic_block": ("summary", "details", "tech-use-case", "fr", "requirements-format"),
"architecture_overview": ("summary", "details", "requirements-format"), "architecture_overview": ("summary", "details", "tech-use-case", "fr", "requirements-format"),
"domain_entity": ("summary", "details", "requirements-format"), "domain_entity": ("summary", "details", "tech-use-case", "fr", "requirements-format"),
} }
def select(self, bundle: DocRulesBundle, doc_type: str) -> SelectedDocRules | None: def select(self, bundle: DocRulesBundle, doc_type: str) -> SelectedDocRules | None:
+2 -2
View File
@@ -61,8 +61,8 @@ class IndexJobStore:
cache_miss_files=row.cache_miss_files, cache_miss_files=row.cache_miss_files,
error=payload, error=payload,
) )
stale_timeout_sec = max(1, int(os.getenv("RAG_RUNNING_STALE_TIMEOUT_SEC", "8"))) stale_timeout_sec = int(os.getenv("RAG_RUNNING_STALE_TIMEOUT_SEC", "0"))
if job.status == IndexJobStatus.RUNNING and self._is_stale(row.updated_at, stale_timeout_sec): if stale_timeout_sec > 0 and job.status == IndexJobStatus.RUNNING and self._is_stale(row.updated_at, stale_timeout_sec):
payload = ErrorPayload( payload = ErrorPayload(
code="index_stalled", code="index_stalled",
desc="Indexing stalled in running state; likely blocked network call during embedding/auth.", desc="Indexing stalled in running state; likely blocked network call during embedding/auth.",
+1 -1
View File
@@ -117,7 +117,7 @@ class IndexingOrchestrator:
}, },
) )
timeout_sec = max(1, int(os.getenv("RAG_INDEX_JOB_TIMEOUT_SEC", "15"))) timeout_sec = max(1, int(os.getenv("RAG_INDEX_JOB_TIMEOUT_SEC", "180")))
indexed, failed, cache_hits, cache_misses = await asyncio.wait_for( indexed, failed, cache_hits, cache_misses = await asyncio.wait_for(
operation(progress_cb), operation(progress_cb),
timeout=timeout_sec, timeout=timeout_sec,
+76 -4
View File
@@ -217,11 +217,23 @@ class RagService:
batch_size = max(1, int(os.getenv("RAG_EMBED_BATCH_SIZE", "16"))) batch_size = max(1, int(os.getenv("RAG_EMBED_BATCH_SIZE", "16")))
request_timeout_sec = max(1, int(os.getenv("RAG_EMBED_REQUEST_TIMEOUT_SEC", "5"))) request_timeout_sec = max(1, int(os.getenv("RAG_EMBED_REQUEST_TIMEOUT_SEC", "5")))
request_retries = max(1, int(os.getenv("RAG_EMBED_REQUEST_MAX_RETRIES", "1"))) request_retries = max(1, int(os.getenv("RAG_EMBED_REQUEST_MAX_RETRIES", "1")))
max_chars = max(200, int(os.getenv("RAG_EMBED_MAX_CHARS", "1200")))
overlap_chars = max(0, int(os.getenv("RAG_EMBED_OVERLAP_CHARS", "120")))
prepared = self._prepare_docs_for_embedding(docs, max_chars=max_chars, overlap_chars=overlap_chars)
if len(prepared) != len(docs):
LOGGER.warning(
"rag embed doc split: path=%s original_docs=%s prepared_docs=%s max_chars=%s overlap_chars=%s",
file.get("path", ""),
len(docs),
len(prepared),
max_chars,
overlap_chars,
)
metadata = self._document_metadata(file, repo_id, blob_sha) metadata = self._document_metadata(file, repo_id, blob_sha)
for doc in docs: for doc in prepared:
doc.metadata.update(metadata) doc.metadata.update(metadata)
for start in range(0, len(docs), batch_size): for start in range(0, len(prepared), batch_size):
batch = docs[start : start + batch_size] batch = prepared[start : start + batch_size]
LOGGER.warning( LOGGER.warning(
"rag embed batch start: path=%s batch_start=%s batch_size=%s timeout_sec=%s retries=%s", "rag embed batch start: path=%s batch_start=%s batch_size=%s timeout_sec=%s retries=%s",
file.get("path", ""), file.get("path", ""),
@@ -243,7 +255,67 @@ class RagService:
) )
for doc, vector in zip(batch, vectors): for doc, vector in zip(batch, vectors):
doc.embedding = vector doc.embedding = vector
return docs return prepared
def _prepare_docs_for_embedding(
self,
docs: list[RagDocument],
*,
max_chars: int,
overlap_chars: int,
) -> list[RagDocument]:
prepared: list[RagDocument] = []
for doc in docs:
text = str(doc.text or "")
if len(text) <= max_chars:
prepared.append(doc)
continue
parts = self._split_text_for_embedding(text, max_chars=max_chars, overlap_chars=overlap_chars)
if len(parts) <= 1:
prepared.append(doc)
continue
for idx, part in enumerate(parts, start=1):
metadata = dict(doc.metadata)
metadata["embed_part_index"] = idx
metadata["embed_part_total"] = len(parts)
if doc.doc_id:
metadata["embed_original_doc_id"] = doc.doc_id
prepared.append(
RagDocument(
layer=doc.layer,
source=doc.source,
title=f"{doc.title} [part {idx}/{len(parts)}]",
text=part,
metadata=metadata,
links=list(doc.links),
span=doc.span,
doc_id=f"{doc.doc_id}:part:{idx}" if doc.doc_id else None,
lang=doc.lang,
)
)
return prepared
def _split_text_for_embedding(self, text: str, *, max_chars: int, overlap_chars: int) -> list[str]:
normalized = text.replace("\r\n", "\n").replace("\r", "\n")
parts: list[str] = []
start = 0
length = len(normalized)
while start < length:
hard_end = min(length, start + max_chars)
end = hard_end
if hard_end < length:
soft_start = min(length, start + max_chars // 2)
pivot = normalized.rfind("\n", soft_start, hard_end)
if pivot > start:
end = pivot + 1
chunk = normalized[start:end].strip()
if chunk:
parts.append(chunk)
if end >= length:
break
next_start = max(start + 1, end - overlap_chars)
start = next_start
return parts or [normalized]
def _with_file_metadata(self, docs: list[RagDocument], file: dict, repo_id: str, blob_sha: str) -> list[RagDocument]: def _with_file_metadata(self, docs: list[RagDocument], file: dict, repo_id: str, blob_sha: str) -> list[RagDocument]:
metadata = self._document_metadata(file, repo_id, blob_sha) metadata = self._document_metadata(file, repo_id, blob_sha)
@@ -35,7 +35,7 @@ class GigaChatTokenProvider:
def _fetch_token(self) -> tuple[str, float]: def _fetch_token(self) -> tuple[str, float]:
if not self._settings.credentials: if not self._settings.credentials:
raise GigaChatError("GIGACHAT_TOKEN is not set") raise GigaChatError("GIGACHAT_TOKEN is not set")
timeout_sec = max(1, int(os.getenv("GIGACHAT_AUTH_TIMEOUT_SEC", "5"))) timeout_sec = max(1, int(os.getenv("GIGACHAT_AUTH_TIMEOUT_SEC", "20")))
headers = { headers = {
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json", "Accept": "application/json",