- .ai-specs/PROJECT_CONTEXT.md: new 'Language Model (UI vs. Content)' section (serviceLang ru->cu, fallback chain, scripture, Bible tab independence, fonts, calendar authority) + content-policy pointer in Critical Invariants. - .ai-specs/WORKING_POLICIES.md: new 'Liturgical Content Policies' — never translate service/Bible texts (sourced only), cu texts verbatim (no normalisation/latinisation), service assembly follows the Typicon. - DATA_EN.md/DATA_RUS.md: ru/ holds enriched lives only; services fall back to cu; cu is the authoritative calendar + service texts.
839 lines
40 KiB
Markdown
839 lines
40 KiB
Markdown
# Документация по формату статических данных
|
||
|
||
## Оглавление
|
||
1. [Обзор формата статических данных](#обзор-формата-статических-данных)
|
||
2. [Структура директорий и организация](#структура-директорий-и-организация)
|
||
3. [Модели данных и схемы](#модели-данных-и-схемы)
|
||
4. [Правила маршрутизации файлов](#правила-маршрутизации-файлов)
|
||
5. [Разбор компонентов данных](#разбор-компонентов-данных)
|
||
6. [Инструменты управления данными](#инструменты-управления-данными)
|
||
7. [Процесс обогащения](#процесс-обогащения)
|
||
8. [Рабочий процесс контроля качества](#рабочий-процесс-контроля-качества)
|
||
9. [Распространённые проблемы и решения](#распространённые-проблемы-и-решения)
|
||
10. [Краткий справочник](#краткий-справочник)
|
||
|
||
---
|
||
|
||
## Обзор формата статических данных
|
||
|
||
Ponomar PWA использует систему статических данных на основе JSON, организованную по языкам. Все литургические данные предварительно конвертированы из XML-источников и структурированы для эффективной отдачи и рендеринга на стороне клиента.
|
||
|
||
### Основные принципы
|
||
- **Организация по языкам**: Каждый язык имеет свою директорию в `static/data/`
|
||
- **Хранение в JSON**: Все данные хранятся в виде JSON-файлов для простого парсинга
|
||
- **Маршрутизация по датам**: Календарные данные организованы по датам юлианского календаря (формата ММ-ДД)
|
||
- **Идентификация по CId**: Канонические идентификаторы (CId) уникально идентифицируют святых и праздники
|
||
- **Маршрутизация по префиксу файлов**: Файлы житий маршрутизируются по префиксу CId (01-12 → файлы месяцев)
|
||
|
||
### Поддерживаемые языки
|
||
- `en` — английский
|
||
- `cu` — церковнославянский
|
||
- `ru` — русский
|
||
- `el` — греческий (включает `el/mono` для монохорда)
|
||
- `fr` — французский
|
||
- `zh` — китайский (включает `zh/Hans` и `zh/Hant` для упрощённого и традиционного)
|
||
- `shared` — межязыковые ресурсы
|
||
|
||
---
|
||
|
||
## Структура директорий и организация
|
||
|
||
```
|
||
static/data/
|
||
├── en/
|
||
│ ├── menaion-bundle.json # Отображение дата → CId (авторитетно)
|
||
│ ├── en-menaion-bundle.json # Переопределения для конкретного языка
|
||
│ ├── lives/ # Жития святых по месяцам
|
||
│ │ ├── 01.json through 12.json # Файлы месяцев с CId по префиксу (01XX-12XX)
|
||
│ │ ├── misc/ # CId без месячного префикса
|
||
│ │ │ ├── 1.json # CId, начинающиеся с цифры 1
|
||
│ │ │ ├── 2.json
|
||
│ ├── menaion/ # Ежедневные записи минеи (366 дней)
|
||
│ ├── calendar/ # Метаданные календаря
|
||
│ └── services/ # Шаблоны богослужений
|
||
├── cu/ # Церковнославянский (авторитетный календарь и богослужебные тексты)
|
||
├── ru/ # Русский (обогащённые жития; богослужения берутся из cu)
|
||
├── el/ # Греческий (включает mono/)
|
||
├── fr/ # Французский
|
||
├── zh/ # Китайский (включает Hans/, Hant/)
|
||
└── shared/ # Межязыковые ресурсы
|
||
├── calendar/ # Календарь подвижных праздников
|
||
├── services/ # Общие шаблоны богослужений
|
||
└── lives-index.json # Индекс поиска CId → чтения Писания
|
||
```
|
||
|
||
### Типы файлов
|
||
- `*-bundle.json` — файлы отображения календаря
|
||
- `lives/*.json` — пачки (bundles) житий святых
|
||
- `menaion/*.json` — ежедневные записи минеи
|
||
- `services/*.json` — шаблоны и логика богослужений
|
||
- `calendar/*.json` — вычисления календаря и метаданные
|
||
|
||
---
|
||
|
||
## Модели данных и схемы
|
||
|
||
### Запись пачки (bundle entry) (menaion-bundle.json)
|
||
```json
|
||
{
|
||
"01-01": [
|
||
{ "id": "010101" },
|
||
{ "id": "772426" },
|
||
{ "id": "010102" }
|
||
]
|
||
}
|
||
```
|
||
**Структура**: Объект с ключами по дате `ММ-ДД`, содержащий массив записей, каждая из которых содержит только поле `"id"` со значением CId.
|
||
|
||
### Запись жития (life entry) (lives/*.json)
|
||
```json
|
||
{
|
||
"772426": {
|
||
"name": {
|
||
"nominative": "Прп. Сильвестра Печерского (XII)",
|
||
"short": "Прп. Сильвестра Печерского"
|
||
},
|
||
"life": {
|
||
"id": "minei-0101-772426",
|
||
"copyright": "Четьи-Минеи свт. Димитрия Ростовского",
|
||
"text": "<p>Преподобный отец наш Сильвестр...</p>"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
**Структура**: Объект с ключами по CId (строка), каждый содержит:
|
||
- `name` (объект) с падежными вариантами (`nominative`, `short`, `genitive` и т.д.)
|
||
- `life` (объект, необязательный) с полями `id`, `copyright` и `text`
|
||
|
||
### Запись календаря
|
||
```json
|
||
{
|
||
"pascha": { "year": 2025, "date": "04-20" },
|
||
"fixed": [
|
||
{ "date": "01-01", "rank": 5, "celebration": "Circumcision" }
|
||
]
|
||
}
|
||
```
|
||
**Структура**: Содержит вычисления подвижных праздников и данные неподвижного календаря.
|
||
|
||
### Запись шаблона богослужения
|
||
```json
|
||
{
|
||
"ROYALHOURS": {
|
||
"0": {
|
||
"text": "Во имя Отца...",
|
||
"type": "0"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
**Структура**: Иерархическая структура богослужения с текстовыми узлами и условной логикой.
|
||
|
||
---
|
||
|
||
## Правила маршрутизации файлов
|
||
|
||
### Маршрутизация файлов житий
|
||
Пачки (bundles) житий маршрутизируются на основе префикса CId:
|
||
|
||
| Шаблон CId | Целевой файл | Примеры |
|
||
|-------------|--------------|----------|
|
||
| `01XX-01ZZ` | `01.json` | `010101`, `014567` |
|
||
| `02XX-02ZZ` | `02.json` | `023456`, `027890` |
|
||
| ... | ... | ... |
|
||
| `12XX-12ZZ` | `12.json` | `123456`, `127890` |
|
||
| Прочие CId | `misc/{n}.json` | `772426→misc/7.json`, `373→misc/3.json` |
|
||
|
||
**Примеры:**
|
||
- `010101` → `01.json`
|
||
- `1253` → `12.json`
|
||
- `772426` → `misc/7.json`
|
||
- `373` → `misc/3.json`
|
||
|
||
### Нейминг файлов пачек
|
||
- Основная пачка: `menaion-bundle.json` (для каждого языка)
|
||
- Переопределения языка: `{lang}-menaion-bundle.json`
|
||
- Маршрутизация по префиксу для пачек отсутствует (один файл на язык)
|
||
|
||
---
|
||
|
||
## Разбор компонентов данных
|
||
|
||
### Пачки минеи (Menaion Bundles)
|
||
**Назначение**: Авторитетное отображение дата → CId для рендеринга календаря
|
||
|
||
**Структура**: JSON с ключами по дате и массивами CId
|
||
```json
|
||
{
|
||
"01-01": [{ "id": "010101" }, { "id": "772426" }],
|
||
"01-02": [{ "id": "010201" }, { "id": "772455" }]
|
||
}
|
||
```
|
||
|
||
**Покрытие**: 366 дней юлианского календаря × несколько записей на день
|
||
**Размер файла**: ~50-100KB на язык
|
||
**Использование**: Представление календаря определяет, каких святых отображать в каждый день
|
||
|
||
### Пачки житий (Lives Bundles)
|
||
**Назначение**: Биографии и жития святых для обогащения
|
||
|
||
**Структура**: JSON с ключами по CId, вариантами имён и необязательным текстом жития
|
||
```json
|
||
{
|
||
"772426": {
|
||
"name": {
|
||
"nominative": "Прп. Сильвестра Печерского (XII)",
|
||
"short": "Прп. Сильвестра Печерского"
|
||
},
|
||
"life": {
|
||
"id": "minei-0101-772426",
|
||
"copyright": "Четьи-Минеи свт. Димитрия Ростовского",
|
||
"text": "<p>Полный текст жития в HTML...</p>"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**Покрытие**: 3046 CId всего, 1203 с обогащённым life.text
|
||
**Маршрутизация**: по префиксу (01.json-12.json + misc/{digit}.json)
|
||
**Использование**: Отображение житий на страницах подробностей о святых
|
||
|
||
### Данные календаря
|
||
**Назначение**: Вычисления подвижных праздников и метаданные календаря
|
||
|
||
**Компоненты**:
|
||
- `shared/calendar/triodion.json` — Масленица до Великой седмицы
|
||
- `shared/calendar/pentecostarion.json` — Пасха до всех святых
|
||
- `{lang}/calendar/` — данные календаря для конкретного языка
|
||
|
||
**Ключевые особенности:**
|
||
- Вычисления Пасхалии
|
||
- Определение дат подвижных праздников
|
||
- Определения постных периодов
|
||
- Метаданные праздников и commemorations
|
||
|
||
### Шаблоны богослужений
|
||
**Назначение**: Структурированные литургические данные с условной логикой
|
||
|
||
**Организация:**
|
||
```
|
||
services/
|
||
├── octoecheos/ # Восемь гласов × дни
|
||
├── triodion/ # 37 постных разделов
|
||
├── pentecostarion/ # 50 дней Пасхи
|
||
├── menaion/ # 366 ежедневных записей + 34 праздника
|
||
├── canons/ # Пареклит, Осмогласник, Великий канон
|
||
└── shared/templates/ # Переиспользуемые компоненты богослужений
|
||
```
|
||
|
||
**Структура**: Иерархический JSON с текстовыми узлами и условными префиксами
|
||
- **P-узлы**: Необязательный контент, который может быть включён
|
||
- **Var/I-узлы**: Логика условного выбора
|
||
- **Обычные узлы**: Обязательный контент, всегда включён
|
||
|
||
### Метаданные Библии
|
||
**Назначение**: Отображения версий Библии и перикоп чтений
|
||
|
||
**Структура**: Идентификаторы версий и отображения перикоп для 13 версий Библии
|
||
- Церковнославянский
|
||
- Русский синодальный
|
||
- KJV
|
||
- Брентон (Септуагинта)
|
||
- Вульгата
|
||
- Другие версии
|
||
|
||
### Правила молитв и команды (Prayer Rules & Commands)
|
||
**Назначение**: Структуры суточного круга и определения правила молитвы
|
||
|
||
**Компоненты:**
|
||
- **Правила молитвы**: Расписания ежедневных чтений
|
||
- **Команды**: Структуры команд богослужений
|
||
- **Часослов**: Часы, кафисмы, повечерие и т.д.
|
||
|
||
### Правила поста
|
||
**Назначение**: Определения периодов и исключений поста
|
||
|
||
**Структура**: JSON с правилами поста, периодами и детальными правилами
|
||
- Предпостные периоды
|
||
- Великий пост
|
||
- Безпостные периоды
|
||
- Рыбные и строгие постные дни
|
||
|
||
---
|
||
|
||
## Инструменты управления данными
|
||
|
||
### Конвейер конвертации (`scripts/convert-*.ts`)
|
||
|
||
#### Главный скрипт
|
||
**`convert-all.ts`** — Оркестрирует все этапы конвертации
|
||
```bash
|
||
npm run convert
|
||
```
|
||
|
||
Конвертирует данные XML из источников Java Ponomar в формат JSON.
|
||
|
||
#### Индивидуальные конвертеры
|
||
|
||
**`convert-lives.ts`** — Конвертация житий святых из XML в JSON
|
||
- Вход: `ponomar/Ponomar/languages/{lang}/xml/lives/*.xml`
|
||
- Выход: `{lang}/lives/{01.json|misc/{digit}.json}` пачки
|
||
- Особенности:
|
||
- Парсинг XML с извлечением атрибутов
|
||
- Нормализация падежей имён
|
||
- Извлечение грамматических данных
|
||
- Извлечение данных богослужений
|
||
- Извлечение ссылок на Писание
|
||
- Генерация пачек по месячному префиксу
|
||
|
||
**`convert-calendar.ts`** — Конвертация метаданных календаря
|
||
- Вход: данные календаря XML
|
||
- Выход: структуры календаря JSON
|
||
- Особенности:
|
||
- Вычисления подвижных праздников
|
||
- Отображения неподвижных праздников
|
||
- Определения периодов
|
||
|
||
**`convert-services.ts`** — Конвертация шаблонов богослужений
|
||
- Вход: определения богослужений XML
|
||
- Выход: шаблоны богослужений JSON
|
||
- Особенности:
|
||
- Сохранение иерархической структуры
|
||
- Извлечение условной логики
|
||
- Нормализация текстовых узлов
|
||
|
||
**`convert-bible-meta.ts`** — Извлечение метаданных Библии
|
||
- Вход: метаданные Библии XML
|
||
- Выход: отображения версий и перикоп JSON
|
||
|
||
**`convert-fasting.ts`** — Конвертация правил поста
|
||
- Вход: определения поста XML
|
||
- Выход: правила и периоды поста JSON
|
||
|
||
**`convert-commands.ts`** — Конвертация структур команд
|
||
- Вход: определения команд XML
|
||
- Выход: структуры команд JSON
|
||
|
||
**`convert-service-rules.ts`** — Извлечение правил богослужений
|
||
- Вход: определения правил богослужений XML
|
||
- Выход: правила богослужений JSON
|
||
|
||
### Инструменты миграции (`scripts/migrate-data.ts`)
|
||
|
||
**Назначение**: Нормализация формата данных между версиями и языками
|
||
|
||
**Операции:**
|
||
1. Удаление префиксов `@_` из ключей имён житий (все языки)
|
||
2. Удаление `SId` из записей минеи (сохранение id = CId) (все языки)
|
||
3. Переименование директорий богослужений в нижний регистр (cu, el, fr, zh/Hans, zh/Hant, ru)
|
||
4. Выравнивание структуры Осмогласника (cu, fr, zh/Hans, zh/Hant)
|
||
5. Преобразование `TEXT` → `text` в файлах команд
|
||
6. Перемещение общих богослужений в подкаталог `templates/`
|
||
7. Нормализация регистра ключей имён (Nominative → nominative, Short → short)
|
||
8. Миграция объединённых файлов календаря (triodion.json, pentecostarion.json)
|
||
|
||
**Использование:**
|
||
```bash
|
||
npm run migrate # Применение миграций
|
||
npm run migrate:dry # Предпросмотр изменений
|
||
```
|
||
|
||
### Набор валидации (`scripts/validate-*.ts`)
|
||
|
||
#### Главный валидатор
|
||
**`validate-data.ts`** — Комплексная валидация данных
|
||
```bash
|
||
npx tsx scripts/validate-data.ts
|
||
```
|
||
**Валидирует:**
|
||
- Структуру записей житий (обязательные поля)
|
||
- Формат пачек житий (ключи CId, объекты name)
|
||
- Целостность данных календаря
|
||
- Структуру шаблонов богослужений
|
||
- Соответствие формату молитв
|
||
- Структуру узлов команд
|
||
- Записи commemorations
|
||
- Определения правил поста
|
||
|
||
**Вывод:** Количество файлов, ошибки, предупреждения
|
||
|
||
#### Специализированные валидаторы
|
||
**`validate-i18n.ts`** — Полнота международной локализации
|
||
```bash
|
||
npx tsx scripts/validate-i18n.ts
|
||
```
|
||
Проверяет покрытие по языкам (en/ru/cu).
|
||
|
||
**`validate-tabs.ts`** — Согласованность вкладок/шаблонов богослужений
|
||
```bash
|
||
npx tsx scripts/validate-tabs.ts
|
||
```
|
||
Валидирует, что вкладки богослужений соответствуют структурам шаблонов.
|
||
|
||
**`validate-menaion.ts`** — Валидация данных минеи
|
||
```bash
|
||
npx tsx scripts/validate-menaion.ts
|
||
```
|
||
Валидирует записи минеи против правил календаря.
|
||
|
||
**`validate-prayer-rule.ts`** — Валидация структуры правила молитвы
|
||
```bash
|
||
npx tsx scripts/validate-prayer-rule.ts
|
||
```
|
||
Валидирует формат и полноту правила молитвы.
|
||
|
||
**Периодические валидаторы:**
|
||
- `validate-triodion.ts` — Валидация периода Триоди
|
||
- `validate-pentecostarion.ts` — Валидация Пятидесятницы
|
||
- `validate-holy-week.ts` — Валидация Страстной седмицы
|
||
- `validate-great-canon.ts` — Валидация Великого канона
|
||
- `validate-great-compline.ts` — Валидация великого повечерия
|
||
- `validate-libcs.ts` — Валидация содержания библиотеки
|
||
|
||
### Утилиты (`scripts/tools/`)
|
||
|
||
**`search-texts.ts`** — Полно-текстовый поиск по файлам данных
|
||
```bash
|
||
npx tsx scripts/tools/search-texts.ts <query> [--lang en] [--type prayers]
|
||
```
|
||
|
||
**`stats.ts`** — Статистика данных и анализ размеров
|
||
```bash
|
||
npx tsx scripts/tools/stats.ts [--lang en]
|
||
```
|
||
|
||
Предоставляет количество файлов, размеры и разбивку по категориям.
|
||
|
||
---
|
||
|
||
## Процесс обогащения
|
||
|
||
### Обзор
|
||
Процесс обогащения заполняет пустые поля `life.text` в пачках ru/lives, используя агиографические тексты Четьи-Миней (свт. Димитрия Ростовского).
|
||
|
||
### Подготовка источника: Импорт Четьи-Миней
|
||
|
||
**`convert-minei.ts`** — Конвертирует EPUB Четьи-Миней в JSON с ключами по датам
|
||
|
||
**Структура входа (извлечённый EPUB):**
|
||
```
|
||
extracted-epub/
|
||
├── index_split_000.xhtml through index_split_9999.xhtml
|
||
├── toc.ncx
|
||
└── content.opf
|
||
```
|
||
|
||
**Процесс:**
|
||
1. Последовательный парсинг дневных файлов
|
||
2. Извлечение заголовков: `h2` для дат (`"Память 1 января"`), `h3` для заголовков глав
|
||
3. Извлечение абзацев: `<p class="paragraph1">` для содержания
|
||
4. Сбор сносок из якорей `<a title="...">`
|
||
5. Добавление сносок в виде блока "Примечания:"
|
||
6. Применение исправлений дат заголовков (например, `calibre_toc_10023` → `01-27`)
|
||
7. Построение выходной структуры: `{ "ММ-ДД": [{ title, html }] }`
|
||
|
||
**Использование:**
|
||
```bash
|
||
npx tsx scripts/convert-minei.ts <extracted-epub-dir> [output.json]
|
||
```
|
||
|
||
**Вывод:** `scripts/output/minei.json` (игнорируется в git, ~33МБ)
|
||
|
||
### Конвейер обогащения
|
||
|
||
**`enrich-lives.ts`** — Нечёткое сопоставление названий minei с именами CId и заполнение пустых житий
|
||
|
||
**Входные данные:**
|
||
- `scripts/output/minei.json` — источники житий по дате (ММ-ДД)
|
||
- `static/data/cu/menaion-bundle.json` — Авторитетное отображение дата→CId
|
||
- `static/data/ru/lives/*.json` — целевые пачки для обогащения
|
||
|
||
**Стратегия сопоставления:**
|
||
1. **Токенизация**: Разбиение названий на токены, фильтрация ROLE_WORDS
|
||
2. **Коэффициент Dice**: Вычисление сходства по наборам токенов
|
||
3. **Классификация статусов**:
|
||
- `already-filled` — Целевой объект уже имеет `life.text` → пропускается
|
||
- `auto` — Оценка ≥ 0.6, пустой целевой объект → записывается
|
||
- `review` — Оценка 0.35–0.6 → требуется ручной обзор
|
||
- `unmatched` — Оценка < 0.35 или нет кандидатов → без совпадения
|
||
|
||
**Ручные переопределения:**
|
||
```typescript
|
||
const MANUAL_FIXES: Record<string, string> = {
|
||
'02-02|сказание о сретении': '373',
|
||
'03-24|воспоминание о чуде': '822',
|
||
// 214 записей всего
|
||
}
|
||
```
|
||
Формат ключа: `{дата}|{характерная подстрока}` → CId
|
||
|
||
**Обработка коллизий:** Несколько источников отображаются на один CId
|
||
- Первый источник: записывает `life.html` напрямую (без заголовка)
|
||
- Последующие источники: добавляют `<p><b>{title}</b></p>{html}`
|
||
|
||
**Маршрутизация файлов:**
|
||
```typescript
|
||
function bundleFileForCid(cid: string): string {
|
||
return /^(0[1-9]|1[0-2])\d+/.test(cid)
|
||
? `${cid.substring(0, 2)}.json`
|
||
: 'misc.json';
|
||
}
|
||
```
|
||
|
||
**Использование:**
|
||
```bash
|
||
# Тестовый прогон: только отчёт
|
||
npx tsx scripts/enrich-lives.ts
|
||
|
||
# Ограничение одним месяцем
|
||
npx tsx scripts/enrich-lives.ts --month 01
|
||
|
||
# Применение изменений
|
||
npx tsx scripts/enrich-lives.ts --write
|
||
|
||
# Применение изменений для конкретного месяца
|
||
npx tsx scripts/enrich-lives.ts --write --month 01
|
||
```
|
||
|
||
**Вывод:** `scripts/output/lives-match-report.json` со статусом совпадения для каждого источника
|
||
|
||
### Пример рабочего процесса
|
||
|
||
**Этап 1: Подготовка источника**
|
||
```bash
|
||
npx tsx scripts/convert-minei.ts ~/Downloads/chetyi-minei-epub/
|
||
# Вывод: scripts/output/minei.json
|
||
```
|
||
|
||
**Этап 2: Тестовый анализ**
|
||
```bash
|
||
npx tsx scripts/enrich-lives.ts
|
||
# Показывает: Auto-applied: 184, needs review: 127, unmatched: 94
|
||
# Обзор: scripts/output/lives-match-report.json
|
||
```
|
||
|
||
**Этап 3: Ручной обзор и исправления**
|
||
- Анализ записей `review` в отчёте
|
||
- Добавление MANUAL_FIXES для проблемных совпадений
|
||
- Повторный запуск, пока количество `review` не станет приемлемым
|
||
|
||
**Этап 4: Запись и валидация**
|
||
```bash
|
||
npx tsx scripts/enrich-lives.ts --write
|
||
# Показывает: Wrote 7 updated bundle(s)
|
||
npx tsx scripts/validate-data.ts
|
||
npx tsc --noEmit
|
||
npm run build
|
||
```
|
||
|
||
**Этап 5: Коммит**
|
||
```bash
|
||
git add scripts/enrich-lives.ts scripts/output/lives-match-report.json static/data/ru/lives/
|
||
git commit -m "enrich 121 more ru lives with Chetyi-Minei texts"
|
||
```
|
||
|
||
### Контроль качества
|
||
|
||
**Проверка коллизий:** Проверка много-главных записей на правильность заголовков
|
||
```bash
|
||
python3 -c "
|
||
import json, re
|
||
misc = json.load(open('static/data/ru/lives/misc.json'))
|
||
for cid in ['493', '1674', '257401']: # Известные цели коллизий
|
||
text = misc[cid]['life']['text']
|
||
headings = re.findall(r'<b>([^<]+)</b>', text)
|
||
print(f'{cid}: {len(headings)} глав - {headings}')
|
||
"
|
||
```
|
||
|
||
**Отслеживание покрытия:** Мониторинг прогресса обогащения
|
||
```bash
|
||
python3 -c "
|
||
import json, glob, os
|
||
total = has = 0
|
||
for fp in glob.glob('static/data/ru/lives/*.json'):
|
||
data = json.load(open(fp))
|
||
for cid, entry in data.items():
|
||
total += 1
|
||
if isinstance(entry.get('life'), dict) and entry.get('life', {}).get('text'):
|
||
has += 1
|
||
print(f'Покрытие: {has}/{total} ({has*100//total}%) житий с текстом')
|
||
"
|
||
```
|
||
|
||
---
|
||
|
||
## Рабочий процесс контроля качества
|
||
|
||
### Чек-лист перед коммитом
|
||
|
||
1. **Валидация данных**
|
||
```bash
|
||
npx tsx scripts/validate-data.ts
|
||
# Ожидается: "All files valid!" или конкретное количество ошибок
|
||
```
|
||
|
||
2. **Безопасность типов**
|
||
```bash
|
||
npm run check # или npx tsc --noEmit
|
||
# Ожидается: Нет ошибок TypeScript
|
||
```
|
||
|
||
3. **Проверка сборки**
|
||
```bash
|
||
npm run build
|
||
# Ожидается: Успешная сборка с размерами пакетов
|
||
```
|
||
|
||
4. **Функциональное тестирование**
|
||
```bash
|
||
npm run dev
|
||
# Ручной тест: Представление календаря, страницы подробностей святых, отображение житий
|
||
```
|
||
|
||
### Непрерывный мониторинг
|
||
|
||
**Автоматические проверки:**
|
||
- Проверка количества файлов (должно быть 274 файла)
|
||
- Возможность парсинга JSON (все файлы данных)
|
||
- Наличие обязательных полей (nominative, life.text для обогащённых записей)
|
||
- Согласованность CId (один и тот же CId должен иметь одинаковое имя на разных языках)
|
||
|
||
**Обнаружение проблем:**
|
||
- Повреждённые JSON-файлы → ошибки парсинга в validate-data.ts
|
||
- Отсутствие обязательных полей → предупреждения валидации
|
||
- Несоответствие типов → ошибки TypeScript
|
||
- Ошибки сборки → недопустимые структуры данных
|
||
|
||
### Решение проблем
|
||
|
||
**Распространённые ошибки валидации:**
|
||
1. **"Missing nominative"** — Объект name отсутствует именительный падеж
|
||
- **Решение**: Добавить поле `name.nominative` к затронутым записям
|
||
|
||
2. **"Failed to parse"** — Повреждённый JSON-файл
|
||
- **Решение**: Повторно запустить конвертацию или исправить синтаксис JSON
|
||
|
||
3. **"Rank should be 0-8"** — Недопустимое значение rank
|
||
- **Решение**: Нормализовать rank в диапазон 0-8
|
||
|
||
4. **Изменения размеров пакетов сборки** — Неожиданное увеличение размера файла
|
||
- **Решение**: Проверить на наличие дубликатов или искажённого содержимого
|
||
|
||
---
|
||
|
||
## Распространённые проблемы и решения
|
||
|
||
### Артефакты OCR в текстах Четьи-Миней
|
||
|
||
**Проблема:** Конвертация Четьи-Миней создаёт проблемы OCR, такие как:
|
||
- Латинские символы в русском тексте (`Taиcии` вместо `Таисии`)
|
||
- Маркеры сносок `[1]` в тексте тела
|
||
- Нестабильная пунктуация `[1]` в названиях
|
||
|
||
**Решение:**
|
||
- Оставлять артефакты OCR как есть (часть исходного текста)
|
||
- Ручные исправления используют точные подстроки OCR для сопоставления
|
||
- Примеры: `'02-15|onissima, odnogo iz lika'` → `'450'`
|
||
|
||
### Разрешение омонимов в одну дату
|
||
|
||
**Проблема:** Несколько святых имеют схожие имена в одну дату
|
||
|
||
**Примеры:**
|
||
- 03-24: Иаков исповедник (68501) против других записей Иаков
|
||
- 02-22: Варадат против Фалассия (оба отображаются на 493)
|
||
- 09-03: Анфим, Аристион, Василиса в одну дату
|
||
|
||
**Решение:**
|
||
- Использовать характерные подстроки в MANUAL_FIXES
|
||
- Обеспечить уникальность по дате (проверить с помощью скрипта верификации)
|
||
- Для коллизий: оба источника отображаются на один CId (поведение добавления)
|
||
|
||
### Нарративы на пересекающихся датах
|
||
|
||
**Проблема:** Некоторые главы minei являются повествованиями, не привязанными к конкретному празднику
|
||
|
||
**Примеры:**
|
||
- 02-02: "Сказание о Сретении Господнем" (повествование о сретении)
|
||
- 03-24: "Воспоминание о чуде в Печерском монастыре" (история чуда)
|
||
- 08-28: "Память святой праведной Анны" (пророчица Анна)
|
||
|
||
**Решение:**
|
||
- Определить соответствующий CId для святого/события
|
||
- Отобразить с MANUAL_FIXES, даже если не в ту же дату (хотя текущий конвейер основан на дате)
|
||
- Для записей без подходящего CId: остаться без совпадения
|
||
|
||
### Неверные отображения в пачке (bundle)
|
||
|
||
**Проблема:** Некоторые CId указаны в неправильных календарных датах
|
||
|
||
**Пример:**
|
||
- 868 Иаков Боровицкий указан под 05-22, фактический праздник 10-23
|
||
|
||
**Решение:**
|
||
- Вручную исправить menaion-bundle.json
|
||
- Переместить CId с неверной даты на правильную дату
|
||
- Проверить по источникам календаря и традиции
|
||
|
||
### Пограничные случаи маршрутизации файлов
|
||
|
||
**Проблема:** Неоднозначная маршрутизация для CId на границах
|
||
|
||
**Пограничные случаи:**
|
||
- Префиксы `00` → misc.json (не 00.json)
|
||
- Префиксы `99` → misc.json (не 09.json)
|
||
- Нецифровые CId → misc.json
|
||
|
||
**Решение:**
|
||
```typescript
|
||
/^(0[1-9]|1[0-2])\d+/.test(cid) // Совпадает только с 01-12, за которыми следуют цифры
|
||
```
|
||
|
||
### Отображение много-главных коллизий
|
||
|
||
**Проблема:** Когда несколько источников добавляются к одному CId, первая глава не имеет заголовка
|
||
|
||
**Поведение:**
|
||
- Первый источник: записывает `life.html` напрямую (без заголовка)
|
||
- Последующие источники: добавляют `<p><b>{title}</b></p>{html}`
|
||
- Результат: Первая глава без заголовка, другие чётко отмечены
|
||
|
||
**Приемлемый компромисс:** Соответствует всем одно-главным житиям (которые не имеют заголовка)
|
||
|
||
---
|
||
|
||
## Краткий справочник
|
||
|
||
### Сводка npm-скриптов
|
||
|
||
```bash
|
||
# Разработка
|
||
npm run dev # Запуск сервера разработки
|
||
npm run build # Продуктивная сборка
|
||
npm run preview # Предпросмотр продуктивной сборки
|
||
|
||
# Конвертация данных
|
||
npm run convert # Конвертация всех источников XML в JSON
|
||
npm run migrate # Нормализация к текущему формату
|
||
npm run migrate:dry # Предпросмотр изменений миграции
|
||
|
||
# Валидация
|
||
npm run check # Проверка типов (tsc --noEmit)
|
||
npx tsx scripts/validate-data.ts # Главный валидатор
|
||
npx tsx scripts/validate-i18n.ts # Полнота i18n
|
||
npx tsx scripts/validate-tabs.ts # Согласованность богослужений
|
||
|
||
# Инструменты
|
||
npx tsx scripts/tools/search-texts.ts <query> # Поиск по файлам данных
|
||
npx tsx scripts/tools/stats.ts # Статистика данных
|
||
|
||
# Обогащение
|
||
npx tsx scripts/convert-minei.ts <epub-dir> # Импорт Четьи-Миней
|
||
npx tsx scripts/enrich-lives.ts # Тестовый прогон обогащения
|
||
npx tsx scripts/enrich-lives.ts --write # Применение обогащения
|
||
```
|
||
|
||
### Расширения файлов
|
||
|
||
| Расширение | Назначение | Формат |
|
||
|-----------|-------------|--------|
|
||
| `.json` | Все файлы статических данных | JSON |
|
||
| `.text` | Ресурсы простого текста | Простой текст |
|
||
| `.xml` | Исходные данные (не в репо) | XML |
|
||
|
||
### Стратегия Git
|
||
|
||
**Отслеживается:** `static/data/` (за исключением выходных файлов)
|
||
**Игнорируется:**
|
||
- `scripts/output/minei.json` (33МБ, генерируемый)
|
||
- `node_modules/`
|
||
- `dist/`
|
||
|
||
### Важные пути к файлам
|
||
|
||
```bash
|
||
# Директории данных
|
||
static/data/cu/menaion-bundle.json # Авторитет календаря
|
||
static/data/ru/lives/ # Цель для обогащения
|
||
static/data/shared/services/ # Общие шаблоны богослужений
|
||
|
||
# Скрипты
|
||
scripts/enrich-lives.ts # Конвейер обогащения
|
||
scripts/convert-minei.ts # Импорт minei
|
||
scripts/validate-data.ts # Главный валидатор
|
||
|
||
# Выходные файлы
|
||
scripts/output/minei.json # Источник minei (игнорируется в git)
|
||
scripts/output/lives-match-report.json # Отчёт о совпадениях
|
||
```
|
||
|
||
### Статистика покрытия
|
||
|
||
**Текущий статус:**
|
||
- Всего CId: 3046
|
||
- Жития с текстом: 1190 (39%)
|
||
- Пустые жития: 1856 (61%)
|
||
|
||
**Прогресс обогащения:**
|
||
- Главы Четьи-Миней: 1154 всего
|
||
- Совпавшие: 1127 (auto 64 + already-filled 1063)
|
||
- Без совпадений: 27 (минимум: повествования, нет цели, уже заполнено)
|
||
|
||
### Классификация статусов
|
||
|
||
| Статус | Значение | Действие |
|
||
|--------|----------|----------|
|
||
| `auto` | Оценка ≥ 0.6, пустая цель | Автоматически записывается |
|
||
| `already-filled` | Цель уже имеет life.text | Пропускается (избыточно) |
|
||
| `review` | Оценка 0.35–0.6 | Требуется ручной обзор |
|
||
| `unmatched` | Оценка < 0.35 или нет кандидатов | Нет подходящей цели |
|
||
|
||
### Ключевые константы
|
||
|
||
**Пути к файлам:**
|
||
```typescript
|
||
const MINEI_PATH = 'scripts/output/minei.json';
|
||
const MENAION_BUNDLE_PATH = 'static/data/cu/menaion-bundle.json';
|
||
const LIVES_DIR = 'static/data/ru/lives';
|
||
const REPORT_PATH = 'scripts/output/lives-match-report.json';
|
||
```
|
||
|
||
**Пороги сопоставления:**
|
||
```typescript
|
||
const AUTO_THRESHOLD = 0.6; // Автоматическая запись
|
||
const REVIEW_THRESHOLD = 0.35; // Ручной обзор
|
||
```
|
||
|
||
**Строка авторских прав:**
|
||
```typescript
|
||
const COPYRIGHT = 'Четьи-Минеи свт. Димитрия Ростовского';
|
||
```
|
||
|
||
---
|
||
|
||
## История версий
|
||
|
||
- **Первоначальный выпуск** — Полная документация формата данных и процесса обогащения
|
||
- **Обновлено** — Добавлен раздел о неверных отображениях пачки, обработка повествований на пересекающихся датах, рабочий процесс QA
|
||
|
||
---
|
||
|
||
## Вклад
|
||
|
||
При вкладе в формат данных или конвейер обогащения:
|
||
|
||
1. **Тщательно тестируйте:** Запускайте валидацию, проверку типов и сборку перед коммитом
|
||
2. **Документируйте изменения:** Обновляйте эту документацию при любых изменениях схемы
|
||
3. **Сохраняйте совместимость:** Поддерживайте существующие правила маршрутизации файлов и соглашения об именовании
|
||
4. **Валидируйте данные:** Запускайте `validate-data.ts` и исправляйте любые ошибки
|
||
|
||
---
|
||
|
||
## Поддержка
|
||
|
||
По вопросам или проблемам с форматом статических данных:
|
||
- Ознакомьтесь с этой документацией
|
||
- Проверьте существующие проблемы в репозитории
|
||
- Запустите инструменты валидации для диагностики ошибок
|
||
- Изучите конвейер обогащения для проблем сопоставления |