documentation: AI specs, data format docs, Russian README
This commit is contained in:
1 parent
4a1e22d68b
commit
84c8ceb172
8 files changed
+2662
-7
No files matched your search
@@ -0,0 +1,246 @@
|
||||
# Data Model Specification
|
||||
|
||||
## CId (Canonical Identifier) System
|
||||
|
||||
### Format Rules
|
||||
|
||||
CIds are identifiers for saints, feasts, and liturgical elements. They follow these routing rules:
|
||||
|
||||
| CId Pattern | Target File | Examples | Notes |
|
||||
|-------------|-------------|----------|-------|
|
||||
| `01XX-01ZZ` | `01.json` | `010101`, `014567` | January saints |
|
||||
| `02XX-02ZZ` | `02.json` | `023456`, `027890` | February saints |
|
||||
| ... | ... | ... | ... |
|
||||
| `12XX-12ZZ` | `12.json` | `123456`, `127890` | December saints |
|
||||
| Other CIds | `misc.json` | `772426`, `373`, `868` | Non-month-prefixed |
|
||||
|
||||
### Routing Logic
|
||||
```typescript
|
||||
function bundleFileForCid(cid: string): string {
|
||||
return /^(0[1-9]|1[0-2])\d+/.test(cid)
|
||||
? `${cid.substring(0, 2)}.json`
|
||||
: 'misc.json';
|
||||
}
|
||||
```
|
||||
|
||||
## Menaion Bundle Structure
|
||||
|
||||
### Format Definition
|
||||
```json
|
||||
{
|
||||
"MM-DD": [
|
||||
{ "id": "CId" },
|
||||
{ "id": "CId" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Key Points**:
|
||||
- Each date key: "MM-DD" format (Julian calendar)
|
||||
- Array of objects with only "id" field
|
||||
- CIds correspond to actual commemorations on that date
|
||||
- One per language: `menaion-bundle.json`, `{lang}-menaion-bundle.json`
|
||||
|
||||
### Example
|
||||
```json
|
||||
{
|
||||
"01-01": [
|
||||
{ "id": "010101" },
|
||||
{ "id": "772426" },
|
||||
{ "id": "010102" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Life Entry Structure
|
||||
|
||||
### Format Definition
|
||||
```json
|
||||
{
|
||||
"CId": {
|
||||
"name": {
|
||||
"nominative": "Прп. Сильвестра Печерского (XII)",
|
||||
"short": "Прп. Сильвестра Печерского",
|
||||
"genitive": "Прп. Сильвестра Печерского"
|
||||
},
|
||||
"life": {
|
||||
"id": "minei-0101-772426",
|
||||
"copyright": "Четьи-Минеи свт. Димитрия Ростовского",
|
||||
"text": "<p>Complete life text in HTML...</p>"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Required Fields
|
||||
- **`CId`**: String key (the canonical identifier)
|
||||
- **`name.nominative`**: Required field (validated by validate-data.ts)
|
||||
|
||||
### Optional Fields
|
||||
- **`name.short`**: Short name variant
|
||||
- **`life.text`**: HTML content (only written when empty)
|
||||
- **`life.id`**: Source identifier (e.g., "minei-0101-772426")
|
||||
- **`life.copyright`**: Copyright string
|
||||
|
||||
## Service Template Structure
|
||||
|
||||
### Hierarchical JSON Format
|
||||
```json
|
||||
{
|
||||
"ROYALHOURS": {
|
||||
"0": {
|
||||
"text": "In the name of the Father...",
|
||||
"type": "0"
|
||||
}
|
||||
},
|
||||
"MATINS": {
|
||||
"kathisma": {
|
||||
"text": "Kathisma content..."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Conditional Logic Markers
|
||||
- **P-prefix nodes**: Optional content that may be included
|
||||
- **Var/I-prefix nodes**: Conditional selection logic
|
||||
- **Plain nodes**: Required content always included
|
||||
|
||||
## Chetyi-Minei Source Format
|
||||
|
||||
### Format Definition
|
||||
```json
|
||||
{
|
||||
"MM-DD": [
|
||||
{
|
||||
"title": "Память святого X",
|
||||
"html": "<p>Content paragraphs...</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Key Characteristics
|
||||
- Generated by `convert-mines.ts` from EPUB source
|
||||
- Stored in `scripts/output/minei.json` (gitignored, 33MB)
|
||||
- Titles and HTML are carefully extracted and parsed
|
||||
- Footnotes collected and appended as "Примечания:" blocks
|
||||
|
||||
## File Organization Rules
|
||||
|
||||
### Lives Files
|
||||
- **Location**: `static/data/{lang}/lives/`
|
||||
- **Files**:
|
||||
- `01.json` through `12.json` (month-prefixed CIds)
|
||||
- `misc.json` (non-month-prefixed CIds)
|
||||
- **Routing**: Based on first two digits of CId
|
||||
|
||||
### Menaion Files
|
||||
- **Location**: `static/data/{lang}/menaion/`
|
||||
- **Files**: `01-01.json` through `12-31.json` (daily entries)
|
||||
- **Purpose**: Daily liturgical readings by date
|
||||
|
||||
### Service Templates
|
||||
- **Location**: `static/data/{lang}/services/`
|
||||
- **Shared**: `static/data/shared/services/templates/`
|
||||
|
||||
### Calendar Data
|
||||
- **Location**: `static/data/{lang}/calendar/` and `static/data/shared/calendar/`
|
||||
- **Purpose**: Movable feast calculations and metadata
|
||||
|
||||
## Data Invariants
|
||||
|
||||
### CId Consistency Rules
|
||||
- Same CId must have consistent name across all languages
|
||||
- Bundle CIds must have corresponding lives entries
|
||||
- CIds that exist in bundle must have lives entries
|
||||
- CIds with lives entries must exist in bundle for their date
|
||||
|
||||
### File Organization Invariants
|
||||
- No month file contains CIds with different month prefix
|
||||
- `misc.json` contains all CIds outside the 01-12 prefix range
|
||||
- All data files are tracked in `static/data/`
|
||||
|
||||
### Content Validation Invariants
|
||||
- All lives entries must have `name.nominative` field
|
||||
- HTML content in `life.text` must be properly escaped
|
||||
- JSON files must be parseable (no syntax errors)
|
||||
- File routing must match CId prefixes consistently
|
||||
|
||||
## Common Data Mistakes to Avoid
|
||||
|
||||
### CId Pattern Errors
|
||||
- ⚠️ Don't create CIds with invalid prefixes
|
||||
- ⚠️ Don't put CIds in wrong month files
|
||||
- ⚠️ Don't create duplicate CIds with different meanings
|
||||
|
||||
### JSON Structure Errors
|
||||
- ⚠️ Don't omit required fields (`name.nominative`)
|
||||
- ⚠️ Don't nest structures incorrectly (service templates)
|
||||
- ⚠️ Don't mix CId numbers and strings inconsistently
|
||||
- ⚠️ Don't leave trailing commas in JSON
|
||||
|
||||
### File Organization Mistakes
|
||||
- ⚠️ Don't place month-prefixed CIds in misc.json
|
||||
- ⚠️ Don't create inconsistent JSON indentation
|
||||
- ⚠️ Don't mix languages in incorrect directories
|
||||
|
||||
## Examples
|
||||
|
||||
### Valid CId Examples
|
||||
- `010101` → `01.json` (January saint)
|
||||
- `1253` → `12.json` (December saint)
|
||||
- `772426` → `misc.json` (non-prefixed saint)
|
||||
|
||||
### Invalid CId Examples
|
||||
- `00501` → Should not exist (prefix `00` → misc)
|
||||
- `13xxx` → Should not exist (prefix `13` → misc)
|
||||
|
||||
### File Routing Examples
|
||||
- CId `1253` routes to `12.json`
|
||||
- CId `772426` routes to `misc.json`
|
||||
- CId `010101` routes to `01.json`
|
||||
|
||||
### Bundle Entry Examples
|
||||
```json
|
||||
{
|
||||
"01-15": [
|
||||
{ "id": "010201" },
|
||||
{ "id": "772455" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Life Entry Examples
|
||||
```json
|
||||
{
|
||||
"772426": {
|
||||
"name": {
|
||||
"nominative": "Прп. Сильвестра Печерского (XII)",
|
||||
"short": "Прп. Сильвестра Печерского"
|
||||
},
|
||||
"life": {
|
||||
"id": "minei-0101-772426",
|
||||
"copyright": "Четьи-Минеи свт. Димитрия Ростовского",
|
||||
"text": "<p>Complete life content...</p>"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Current Project State
|
||||
|
||||
### Coverage Statistics
|
||||
- Total CIds: 3046
|
||||
- Lives with text: 1190 (39% coverage)
|
||||
- Empty lives: 1856 (61% remain)
|
||||
|
||||
### Data Files
|
||||
- Total validated files: 274
|
||||
- Main source files: 6 Lives bundle files (misc, 01-12)
|
||||
- Service template files: Multiple per language
|
||||
|
||||
### Recent Changes
|
||||
- Bundle fix: 868 Иаков Боровицký moved from 05-22 to 10-23
|
||||
- Enrichment: 64 manual fixes added to enrich-lives.ts
|
||||
- Coverage increase: 1009→1190 lives with text (191 new)
|
||||
@@ -0,0 +1,257 @@
|
||||
# Enrichment Workflow for AI Agents
|
||||
|
||||
## Quick Start Guide
|
||||
|
||||
Run enrichment in safe mode first:
|
||||
```bash
|
||||
# Dry run to see matches
|
||||
npx tsx scripts/enrich-lives.ts
|
||||
|
||||
# Write changes when confident
|
||||
npx tsx scripts/enrich-lates.ts --write
|
||||
```
|
||||
|
||||
## Common Enrichment Mistakes
|
||||
|
||||
### Auto-Matching Pitfalls
|
||||
- ⚠️ Don't ignore low scores when a clear match exists
|
||||
- ⚠️ Don't skip review phase entirely — need to examine unmatched entries carefully
|
||||
- ⚠️ Don't assume auto means "correct" — scores ≥0.6 can still be wrong-saint
|
||||
- ⚠️ Don't overlook `already-filled` status — some matches hit CIds already filled
|
||||
|
||||
### Manual Fixes Errors
|
||||
- ⚠️ Don't create substrings that match multiple source titles on same date
|
||||
- ⚠️ Don't use substrings with spaces that appear in multiple contexts
|
||||
- ⚠️ Don't forget about OCR artifacts in source titles (Latin `a`, `[1]` markers)
|
||||
- ⚠️ Don't mismatch case forms: account for case differences in substrings
|
||||
|
||||
### Collision Issues
|
||||
- ⚠️ Don't expect first chapter to have a heading (this is by design)
|
||||
- ⚠️ Don't count chapters by counting `<b>` tags alone (verify by checking content)
|
||||
- ⚠️ Don't append to CIds that already have life.text without checking collision behavior
|
||||
- ⚠️ Don't assume all multi-source CIds follow same pattern
|
||||
|
||||
### Validation Skipping
|
||||
- ⚠️ Don't skip `npx tsx scripts/validate-data.ts` — it catches real errors
|
||||
- ⚠️ Don't skip `npx tsc --noEmit` — type errors indicate real problems
|
||||
- ⚠️ Don't skip `npm run build` — build failures need investigation
|
||||
- ⚠️ Don't assume "all files valid" without actually running it
|
||||
|
||||
## Decision Points for AI Agents
|
||||
|
||||
### When to Add MANUAL_FIXES
|
||||
- When score is 0.35-0.6 and you can identify the correct target
|
||||
- When source title contains distinctive substring not in other titles on same date
|
||||
- When auto-matcher picks wrong saint (e.g., different homonym on same date)
|
||||
- When target CId exists but is listed on wrong calendar date (bundle bug)
|
||||
- When narrative maps to known CId but has empty life (can be enriched)
|
||||
|
||||
### When to Leave Unmatched
|
||||
- When source is a narrative or homily without saint association
|
||||
- When no appropriate CId exists in the bundle for that saint
|
||||
- When target CId already has life (no data improvement possible)
|
||||
- When cross-date narratives have no clear target CId
|
||||
|
||||
### When to Use `--month` Flag
|
||||
- When working on enrichment for a specific period only
|
||||
- When testing changes without affecting entire dataset
|
||||
- When troubleshooting issues in a particular month
|
||||
|
||||
## Quality Checkpoints
|
||||
|
||||
### After Manual Fixes Addition
|
||||
- Verify substring uniqueness per date (use verification script)
|
||||
- Check that target CIds exist and are empty
|
||||
- Re-run dry run to verify improvement
|
||||
- Check for potential new conflicts with existing fixes
|
||||
|
||||
### After Writing Changes
|
||||
- Verify coverage increased appropriately
|
||||
- Check that collision targets have correct chapter count
|
||||
- Confirm only intended files were written
|
||||
- Verify no unintended side effects on other files
|
||||
|
||||
### Before Committing
|
||||
- Run full validation: `npx tsx scripts/validate-data.ts`
|
||||
- Type check: `npx tsc --noEmit`
|
||||
- Build verify: `npm run build`
|
||||
- Check git status to confirm intended files staged
|
||||
|
||||
## Troubleshooting Common Issues
|
||||
|
||||
### Unexpected Unmatched Entries
|
||||
**Problem**: Good match exists but score < 0.35
|
||||
- **Solution**: Add MANUAL_FIX with distinctive substring
|
||||
- **Check**: Verify target CId exists and is empty
|
||||
- **Alternative**: Check if bundle has correct CIds on that date
|
||||
|
||||
### No Auto Matches on Date
|
||||
**Problem**: All entries on a date show unmatched
|
||||
- **Solution**: Check menaion-bundle.json for correct CIds on that date
|
||||
- **Alternative**: May be narrative without target CId → leave unmatched
|
||||
|
||||
### Target Already Filled
|
||||
**Problem**: Manual fix shows `already-filled` in report
|
||||
- **Solution**: Fix targeting or remove fix (no data change)
|
||||
- **Check**: Verify CId already has life.text (no improvement possible)
|
||||
|
||||
### Wrong Match Applied
|
||||
**Problem**: Good score applied to wrong CId
|
||||
- **Solution**: Add MANUAL_FIX with more distinctive substring
|
||||
- **Verify**: Check score distribution for potential collisions
|
||||
|
||||
### Collision Issues
|
||||
- ⚠️ **First chapter unheaded**: This is expected behavior by design
|
||||
- ⚠️ **Expected behavior**: First source writes without heading, subsequent sources append
|
||||
- **Check**: Verify total chapters match expected count for CId
|
||||
|
||||
### Strange JSON Syntax Errors
|
||||
- **Problem**: Parse errors in data files after modification
|
||||
- **Solution**: Check JSON syntax, fix trailing commas, quote issues
|
||||
- **Verify**: Run `validate-data.ts` to get specific error location
|
||||
|
||||
### Build Size Changes
|
||||
- **Problem**: Unexpected file size increases/decreases
|
||||
- **Solution**: Check for malformed content, duplicate data, formatting changes
|
||||
- **Check**: Compare before/after file sizes in git diff
|
||||
|
||||
## Verification Commands
|
||||
|
||||
### Coverage Tracking
|
||||
```bash
|
||||
# Check coverage statistics
|
||||
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'Coverage: {has}/{total} ({has*100//total}%) lives with text')
|
||||
"
|
||||
```
|
||||
|
||||
### Collision Chapter Count Check
|
||||
```bash
|
||||
# Check collision targets have correct chapter counts
|
||||
python3 -c "
|
||||
import json, re
|
||||
misc = json.load(open('static/data/ru/lives/misc.json'))
|
||||
for cid in ['493', '1674', '257401']: # Known collision targets
|
||||
text = misc[cid]['life']['text']
|
||||
headings = re.findall(r'<b>([^<]+)</b>', text)
|
||||
print(f'{cid}: {len(headings)} chapters')
|
||||
"
|
||||
```
|
||||
|
||||
### Find Specific Pattern in Data
|
||||
```bash
|
||||
npx tsx scripts/tools/search-texts.ts "Захарии" --lang cu --type menaion
|
||||
```
|
||||
|
||||
### Get Statistics by Language
|
||||
```bash
|
||||
npx tsx scripts/tools/stats.ts --lang ru
|
||||
```
|
||||
|
||||
## Recent Context Updates
|
||||
|
||||
### Known Fixed Issues
|
||||
- 868 Иаков Боровицký moved from 05-22 to 10-23 (bundle mis-mapping correction)
|
||||
- Сретение→373 added (02-02 Сказание about Presentation)
|
||||
- Захарий Печерский→822 added (03-24 miracle story)
|
||||
- Анна пророчица→2396 added (08-28 prophetess Anna)
|
||||
|
||||
### Current Unmatched Floor
|
||||
- 27 entries remain unmatched (all narratives/homilies or already-filled targets)
|
||||
- These are at the floor for Chetyi-Minei source — no recoverable matches available
|
||||
|
||||
## File Routing Quick Reference
|
||||
|
||||
### Lives File Routing
|
||||
- Files: `static/data/ru/lives/01.json` through `12.json` for month-prefixed CIds
|
||||
- File: `misc.json` for non-month-prefixed CIds
|
||||
- Route: `bundleFileForCid(cid: string):` checks `/^(0[1-9]|1[0-2])\d+/.test(cid)`
|
||||
|
||||
### Bundle File Organization
|
||||
- Main bundle: `static/data/cu/menaion-bundle.json` (authoritative calendar)
|
||||
- Language overrides: `{lang}-menaion-bundle.json`
|
||||
- Format: Date keys (MM-DD) with arrays of CId objects
|
||||
|
||||
## Next Steps After Completing Enrichment
|
||||
|
||||
### Quality Assurance
|
||||
- Verify collision targets have correct chapter counts
|
||||
- Check that file sizes are reasonable after writing
|
||||
- Confirm coverage increased as expected
|
||||
|
||||
### Documentation Updates
|
||||
- Update DATA_FORMAT.md or DATA_RUS.md if schema changed
|
||||
- Update coverage statistics in relevant documentation
|
||||
- Add new manual fixes to enrichment documentation if needed
|
||||
|
||||
### Commit Sequence
|
||||
```bash
|
||||
# 1. Validate, typecheck, build all passing
|
||||
npx tsx scripts/validate-data.ts && npx tsc --noEmit && npm run build
|
||||
|
||||
# 2. Stage all changes
|
||||
git add scripts/enrich-lives.ts scripts/output/lives-match-report.json static/data/ru/lives/
|
||||
|
||||
# 3. Commit with description
|
||||
git commit -m "enrich [N] more ru lives: [description]"
|
||||
```
|
||||
|
||||
## Coverage Tracking
|
||||
|
||||
### Current Status
|
||||
- Total CIds: 3046
|
||||
- Lives with text: 1190 (enriched from Chetyi-Minei)
|
||||
- Unmatched minei chapters: 27 (floor: narratives, no-target, already-filled)
|
||||
- Files validated: 274 files (all passing)
|
||||
|
||||
### Recent Enrichment Work
|
||||
- Baseline: 1009 lives with text (from prior work)
|
||||
- Latest commits added 181 lives (121 + 57 + 3)
|
||||
- Manual fixes added: 214 total in enrich-lives.ts
|
||||
- Bundle corrections applied: 868 date fix
|
||||
|
||||
### Progress Tracking
|
||||
- Review band: 127 entries resolved, 0 remaining
|
||||
- Unmatched band: 94 → 30 → 27 (final floor)
|
||||
- Coverage: 1009→1130→1190 lives (181 net increase)
|
||||
|
||||
## Example Workflow for Adding Manual Fixes
|
||||
|
||||
### Step 1: Identify Problematic Match
|
||||
```
|
||||
Date: 03-24
|
||||
Source: "Воспоминание о чуде в Печерском monastery" → score 0.12
|
||||
Candidate: 722 (Прп. Евстратий Печерский, LIFE) - wrong saint
|
||||
Target: 822 (Прп. Захарий Печерский, EMPTY) - correct saint
|
||||
```
|
||||
|
||||
### Step 2: Create Fix
|
||||
```typescript
|
||||
'03-24|воспоминание о чуде': '822'
|
||||
```
|
||||
|
||||
### Step 3: Verify Uniqueness
|
||||
```bash
|
||||
# Check if substring is unique on date 03-24
|
||||
python3 -c "
|
||||
import json, re
|
||||
m=json.load(open('scripts/output/minei.json'))
|
||||
titles=[t['title'] for t in m['03-24']]
|
||||
cnt=sum(1 for t in titles if 'воспоминание о чуде' in re.sub(r'\s+',' ',t['title']).lower())
|
||||
print(f'Count: {cnt}')
|
||||
"
|
||||
```
|
||||
|
||||
### Step 4: Apply and Verify
|
||||
```bash
|
||||
npx tsx scripts/enrich-lives.ts # Check new counts
|
||||
npx tsx scripts/validate-data.ts # Validate all files
|
||||
```
|
||||
@@ -0,0 +1,124 @@
|
||||
# Project Context for AI Agents
|
||||
|
||||
## Quick Project Overview
|
||||
|
||||
**Ponomar** is a Progressive Web App for Orthodox Church calendar, liturgical services, and Bible readings.
|
||||
|
||||
- **Technology**: TypeScript + Vite + Tailwind CSS v4
|
||||
- **Data**: JSON-based liturgical data organized by language (en, cu, el, fr, zh, ru)
|
||||
- **Architecture**: Client-side PWA with static JSON data, no backend database
|
||||
- **Core Functionality**: Calendar display, service assembly, Bible reading, saint lives
|
||||
|
||||
## Key Architectural Patterns
|
||||
|
||||
### Data Organization
|
||||
- **Language-based structure**: `static/data/{lang}/` (en, cu, el, fr, zh, ru)
|
||||
- **Bundle system**: menaion-bundles, lives bundles, service templates
|
||||
- **File routing**: CIds with `01`-`12` prefix → month files, else `misc.json`
|
||||
|
||||
### Core Scripts
|
||||
- `convert-all.ts` — Master conversion script
|
||||
- `enrich-lives.ts` — Fuzzy matching and enrichment pipeline
|
||||
- `validate-data.ts` — Main validator (checks 274 files)
|
||||
- `convert-minei.ts` — Chetyi-Minei EPUB to JSON conversion
|
||||
- `migrate-data.ts` — Data normalization
|
||||
|
||||
## Recent Work Context
|
||||
|
||||
### Completed Enrichment
|
||||
- **Chetyi-Minei import**: 1154 chapters processed, 1190/3046 lives enriched
|
||||
- **Manual fixes**: 214 manual corrections in `enrich-lives.ts`
|
||||
- **Bundle fixes**: 868 Иаков Боровицký corrected from 05-22 to 10-23
|
||||
- **Coverage**: 39% of lives have texts (source from Chetyi-Minei)
|
||||
|
||||
### Validation Status
|
||||
- All data files validated: 274 files checked
|
||||
- TypeScript compiles cleanly
|
||||
- Build succeeds without errors
|
||||
|
||||
## Critical Invariants
|
||||
|
||||
- **Never overwrite existing `life.text`** — enrichment only fills empty entries
|
||||
- **File routing is strict**: CId prefix determines file location
|
||||
- **Bundle CIds must exist**: Menaion CIds require corresponding lives entries
|
||||
- **Static data is tracked**: `static/data/` in git (except `scripts/output/minei.json`)
|
||||
- **Validation must pass**: Changes must pass `validate-data.ts`, `tsc --noEemit`, `npm run build`
|
||||
|
||||
## Key Script Quick Reference
|
||||
|
||||
```bash
|
||||
# Development
|
||||
npm run dev # Start dev server
|
||||
npm run build # Production build
|
||||
|
||||
# Data operations
|
||||
npm run convert # Convert XML to JSON
|
||||
npm run migrate # Normalize data format
|
||||
|
||||
# Validation
|
||||
npx tsx scripts/validate-data.ts # Main validator
|
||||
npx tsc --noEmit # Type checking
|
||||
npm run build # Build verification
|
||||
|
||||
# Enrichment
|
||||
npx tsx scripts/enrich-lives.ts # Dry run enrichment
|
||||
npx tsx scripts/enrich-lives.ts --write # Apply enrichment
|
||||
```
|
||||
|
||||
## File Structure Highlights
|
||||
|
||||
```
|
||||
src/
|
||||
├── core/ # Domain logic (calendar, paschalion, service assembly)
|
||||
├── ui/ # View components
|
||||
└── main.ts # Entry point
|
||||
|
||||
scripts/
|
||||
├── convert-*.ts # XML→JSON conversion pipeline
|
||||
├── validate-*.ts # Comprehensive validation suite
|
||||
└── enrich-lives.ts # Enrichment with manual fixes
|
||||
|
||||
static/data/
|
||||
├── cu/ # Church Slavonic (authoritative calendar)
|
||||
├── ru/ # Russian (enriched lives)
|
||||
├── en/ # English
|
||||
└── shared/ # Cross-language resources
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
### Pipeline Dependencies
|
||||
- **Chetyi-Minei source**: EPUB conversion requires `convert-minei.ts`
|
||||
- **Enrichment workflow**: Requires minei.json output + menaion-bundle.json
|
||||
- **Validation chain**: Each commit must pass validation → typecheck → build
|
||||
|
||||
### File System Constraints
|
||||
- `scripts/output/minei.json` is gitignored (33MB source file)
|
||||
- `static/data/` is fully tracked in git
|
||||
- Lives files are written by month (01.json-12.json) or misc.json
|
||||
|
||||
## Common Tools Reference
|
||||
|
||||
- **Search**: `npx tsx scripts/tools/search-texts.ts <query>`
|
||||
- **Stats**: `npx tsx scripts/tools/stats.ts [--lang en]`
|
||||
- **Validate**: `npx tsx scripts/validate-data.ts`
|
||||
|
||||
## Documentation Reference
|
||||
|
||||
- **DATA_FORMAT.md** — Detailed technical specifications (English)
|
||||
- **DATA_RUS.md** — Complete documentation in Russian
|
||||
- **README.md** — Project overview and getting started
|
||||
|
||||
## Working Reminders
|
||||
|
||||
- Always run validation before committing data changes
|
||||
- Check coverage statistics when working with enrichment
|
||||
- Test builds after any modifications to static data
|
||||
- Review the match report after dry runs
|
||||
|
||||
## Current State
|
||||
|
||||
- Total CIds: 3046
|
||||
- Lives with text: 1190 (enriched from Chetyi-Minei)
|
||||
- Unmatched minei chapters: 27 (floor: narratives, no-target, already-filled)
|
||||
- Latest enrichment commits: `ec3f593` (3 more lives), `08950cd` (57 more lives), `381a494` (121 more lives), `7dde216` (baseline enrichment)
|
||||
@@ -0,0 +1,235 @@
|
||||
# Working Policies for AI Agents
|
||||
|
||||
## Data Modification Rules
|
||||
|
||||
### Never Overwrite Existing Content
|
||||
- **CRITICAL**: Never overwrite existing `life.text` fields in lives entries
|
||||
- Enrichment pipeline only fills empty entries
|
||||
- If a target already has content, classify as `already-filled` and skip
|
||||
|
||||
### File Modification Permissions
|
||||
- **Allowed**: Adding new life.text to empty entries
|
||||
- **Allowed**: Adding manual fixes to `enrich-lives.ts` MANUAl_FIXES
|
||||
- **Allowed**: Correcting menaion-bundle.json for CId date corrections
|
||||
- **Forbidden**: Modifying existing life.text content
|
||||
- **Forbidden**: Deleting or renaming CIds without proper validation
|
||||
- **Forbidden**: Changing JSON structure without updating related code
|
||||
|
||||
## Validation Requirements
|
||||
|
||||
### Pre-Commit Checklist
|
||||
All changes must pass all three checks:
|
||||
|
||||
```bash
|
||||
# 1. Data validation
|
||||
npx tsx scripts/validate-data.ts
|
||||
# Expected: "All files valid!" or specific error count
|
||||
|
||||
# 2. Type safety
|
||||
npx tsc --noEmit
|
||||
# Expected: No TypeScript errors
|
||||
|
||||
# 3. Build verification
|
||||
npm run build
|
||||
# Expected: Successful build with reasonable bundle sizes
|
||||
```
|
||||
|
||||
### When to Stop
|
||||
- Stop immediately if any validation fails
|
||||
- Fix errors before proceeding
|
||||
- Address TypeScript compilation issues
|
||||
- Check build output for unexpected size changes
|
||||
|
||||
## Commit Message Standards
|
||||
|
||||
### Format Conventions
|
||||
|
||||
**Enrichment commits**:
|
||||
```
|
||||
enrich [N] more ru lives: [brief description]
|
||||
```
|
||||
|
||||
**Bundle fix commits**:
|
||||
```
|
||||
fix bundle: move [saint] from [date1] to [date2]
|
||||
```
|
||||
|
||||
**Script updates**:
|
||||
```
|
||||
update [script name]: [brief description]
|
||||
```
|
||||
|
||||
**General guidance**:
|
||||
- Be specific about what changed
|
||||
- Reference specific CIds or dates when applicable
|
||||
- Keep messages concise but descriptive
|
||||
- Reference recent commits for style
|
||||
|
||||
## File Change Guidelines
|
||||
|
||||
### Static Data Files
|
||||
- **Tracked**: `static/data/` directory (all JSON files tracked)
|
||||
- **Not tracked**: `scripts/output/minei.json` (33MB generated file)
|
||||
- **Validate**: Always run validation after data changes
|
||||
|
||||
### Script Files
|
||||
- Maintain existing code patterns
|
||||
- Use existing helper functions when available
|
||||
- Update documentation in relevant markdown files
|
||||
|
||||
### Output Files
|
||||
- Generated files (`dist/`, `scripts/output/`) should not be committed
|
||||
- Only commit source code and data files
|
||||
|
||||
## Code Quality Standards
|
||||
|
||||
### TypeScript Requirements
|
||||
- Maintain strict typing
|
||||
- Follow existing code conventions
|
||||
- Add type annotations where appropriate
|
||||
- Use proper error handling
|
||||
|
||||
### Data Structure Integrity
|
||||
- Maintain CId naming conventions
|
||||
- Preserve JSON structure consistency
|
||||
- Ensure required fields are present (`name.nominative` in lives entries)
|
||||
|
||||
## Error Handling Protocols
|
||||
|
||||
### When Validation Fails
|
||||
1. Review error messages carefully
|
||||
2. Identify root cause (JSON syntax, missing fields, type issues)
|
||||
3. Fix the underlying problem
|
||||
4. Re-run validation until it passes
|
||||
5. Then proceed to type checking
|
||||
|
||||
### When TypeScript Fails
|
||||
1. Check for type mismatches in modified code
|
||||
2. Verify imports and exports
|
||||
3. Ensure all dependencies are properly declared
|
||||
4. Fix type errors
|
||||
5. Re-run tsc --noEmit
|
||||
|
||||
### When Build Fails
|
||||
1. Check console output for specific errors
|
||||
2. Verify data file integrity
|
||||
3. Check for import/export issues
|
||||
4. Resolve build errors before proceeding
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
### When Modifying Data Schemas
|
||||
- Update relevant documentation files (DATA_FORMAT.md, DATA_RUS.md)
|
||||
- Note any breaking changes or invariants
|
||||
- Update project README if structural changes
|
||||
|
||||
### When Adding New Scripts
|
||||
- Document the script's purpose and usage
|
||||
- Add NPM script entry if needed
|
||||
- Update project documentation as appropriate
|
||||
|
||||
## Common Operational Pitfalls
|
||||
|
||||
### Data Modification Risks
|
||||
- ⚠️ **Don't accidentally overwrite existing life.text** — Always check before writing
|
||||
- ⚠️ **Don't skip validation** — Always validate before committing
|
||||
- ⚠️ **Don't ignore build errors** — Build failures indicate real problems
|
||||
- ⚠️ **Don't commit generated files** — Avoid committing dist/ or output files
|
||||
|
||||
### Code Change Risks
|
||||
- ⚠️ **Don't break existing patterns** — Follow established code conventions
|
||||
- ⚠️ **Don't duplicate logic** — Use existing helper functions
|
||||
- ⚠️ **Don't ignore type safety** — Maintain TypeScript strict typing
|
||||
- ⚠️ **Don't make undocumented changes** — Update relevant documentation
|
||||
|
||||
### Commit Risks
|
||||
- ⚠️ **Don't commit without validation** — Ensure all checks pass
|
||||
- ⚠️ **Don't write vague commit messages** — Be specific about what changed
|
||||
- ⚠️ **Don't assume `static/data/` is excluded** — It's tracked, commit your changes
|
||||
|
||||
## Workflow for New Enrichment Work
|
||||
|
||||
### Before Starting
|
||||
1. Review existing MANUAL_FIXES in `enrich-lives.ts`
|
||||
2. Understand the current coverage status
|
||||
3. Identify which dates/cases you're targeting
|
||||
|
||||
### During Work
|
||||
1. Use dry runs first: `npx tsx scripts/enrich-lives.ts`
|
||||
2. Review the match report carefully
|
||||
3. Add MANUAL_FIXES only for problematic matches
|
||||
4. Re-run dry run until satisfied with results
|
||||
5. Only use `--write` when confident
|
||||
|
||||
### After Completion
|
||||
1. Verify file sizes are reasonable
|
||||
2. Check that collision appends are correct
|
||||
3. Run full validation suite
|
||||
4. Commit with descriptive message
|
||||
|
||||
## Quality Assurance Standards
|
||||
|
||||
### Coverage Tracking
|
||||
- Monitor coverage statistics: `1190/3046 lives with text`
|
||||
- Track unmatched count: currently 27 (floor for this data source)
|
||||
- Report changes in coverage when adding MANUAL_FIXES
|
||||
|
||||
### Content Verification
|
||||
- For collision targets, verify chapter counts
|
||||
- Check that first chapter being unheaded is expected behavior
|
||||
- Verify that life.text contains expected content for known CIds
|
||||
|
||||
### Consistency Checks
|
||||
- Ensure similar fixes follow the same pattern
|
||||
- Maintain consistency with existing MANUAL_FIXES format
|
||||
- Keep naming conventions consistent across all entries
|
||||
|
||||
## Quick Reference for Common Operations
|
||||
|
||||
### Adding a MANUAL_FIX
|
||||
```typescript
|
||||
const MANUAL_FIXES: Record<string, string> = {
|
||||
'MM-DD|distinctive-substring': 'CId',
|
||||
};
|
||||
```
|
||||
- Key format: `${date}|${substring}` → CId
|
||||
- Substring must be unique within that date
|
||||
- CId must be empty for the fix to have effect
|
||||
|
||||
### Running Enrichment
|
||||
```bash
|
||||
# Dry run
|
||||
npx tsx scripts/enrich-lives.ts
|
||||
|
||||
# Write changes
|
||||
npx tsx scripts/enrich-lives.ts --write
|
||||
|
||||
# Single month
|
||||
npx tsx scripts/enrich-lives.ts --month 01
|
||||
npx tsx scripts/enrich-lives.ts --write --month 01
|
||||
```
|
||||
|
||||
### Validating Data
|
||||
```bash
|
||||
# Main validator
|
||||
npx tsx scripts/validate-data.ts
|
||||
|
||||
# Period-specific validators
|
||||
npx tsx scripts/validate-menaion.ts
|
||||
npx tsx scripts/validate-triodion.ts
|
||||
```
|
||||
|
||||
### Quick Coverage Check
|
||||
```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'Coverage: {has}/{total} ({has*100//total}%) lives with text')
|
||||
"
|
||||
```
|
||||
+837
@@ -0,0 +1,837 @@
|
||||
# Static Data Format Documentation
|
||||
|
||||
## Table of Contents
|
||||
1. [Static Data Format Overview](#static-data-format-overview)
|
||||
2. [Directory Structure & Organization](#directory-structure--organization)
|
||||
3. [Data Models & Schemas](#data-models--schemas)
|
||||
4. [File Routing Rules](#file-routing-rules)
|
||||
5. [Data Components Breakdown](#data-components-breakdown)
|
||||
6. [Data Management Tools](#data-management-tools)
|
||||
7. [Enrichment Process](#enrichment-process)
|
||||
8. [Quality Assurance Workflow](#quality-assurance-workflow)
|
||||
9. [Common Issues & Solutions](#common-issues--solutions)
|
||||
10. [Quick Reference](#quick-reference)
|
||||
|
||||
---
|
||||
|
||||
## Static Data Format Overview
|
||||
|
||||
The Ponomar PWA uses a JSON-based static data system organized by language. All liturgical data is pre-converted from XML sources and structured for efficient serving and client-side rendering.
|
||||
|
||||
### Core Principles
|
||||
- **Language-based organization**: Each language has its own directory under `static/data/`
|
||||
- **JSON storage**: All data stored as JSON files for easy parsing
|
||||
- **Date-based routing**: Calendar data organized by Julian calendar dates (MM-DD format)
|
||||
- **CId-based identification**: Canonical Identifiers (CIds) uniquely identify saints and feasts
|
||||
- **Prefix-based file routing**: Lives files routed by CId prefix (01-12 → month files)
|
||||
|
||||
### Supported Languages
|
||||
- `en` — English
|
||||
- `cu` — Church Slavonic
|
||||
- `ru` — Russian
|
||||
- `el` — Greek (includes `el/mono` for monochord)
|
||||
- `fr` — French
|
||||
- `zh` — Chinese (includes `zh/Hans` and `zh/Hant` for Simplified/Traditional)
|
||||
- `shared` — Cross-language resources
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure & Organization
|
||||
|
||||
```
|
||||
static/data/
|
||||
├── en/
|
||||
│ ├── menaion-bundle.json # Date → CId mapping (authoritative)
|
||||
│ ├── en-menaion-bundle.json # Language-specific overrides
|
||||
│ ├── lives/ # Saint lives by month
|
||||
│ │ ├── 01.json through 12.json # Month-prefixed CIds (01XX-12XX)
|
||||
│ │ └── misc.json # Non-month-prefixed CIds
|
||||
│ ├── menaion/ # Daily menaion entries (366 days)
|
||||
│ ├── calendar/ # Calendar metadata
|
||||
│ └── services/ # Service templates
|
||||
├── cu/ # Church Slavonic (similar structure)
|
||||
├── ru/ # Russian (lives, services)
|
||||
├── el/ # Greek (includes mono/)
|
||||
├── fr/ # French
|
||||
├── zh/ # Chinese (includes Hans/, Hant/)
|
||||
└── shared/ # Cross-language resources
|
||||
├── calendar/ # Movable feast calendar
|
||||
├── services/ # Shared service templates
|
||||
└── lives-index.json # CId → scripture lookup index
|
||||
```
|
||||
|
||||
### File Types
|
||||
- `*-bundle.json` — Calendar mapping files
|
||||
- `lives/*.json` — Saint lives bundles
|
||||
- `menaion/*.json` — Daily liturgical entries
|
||||
- `services/*.json` — Service templates and logic
|
||||
- `calendar/*.json` — Calendar calculations and metadata
|
||||
|
||||
---
|
||||
|
||||
## Data Models & Schemas
|
||||
|
||||
### Bundle Entry (menaion-bundle.json)
|
||||
```json
|
||||
{
|
||||
"01-01": [
|
||||
{ "id": "010101" },
|
||||
{ "id": "772426" },
|
||||
{ "id": "010102" }
|
||||
]
|
||||
}
|
||||
```
|
||||
**Structure**: Object keyed by date `MM-DD` with array of entries, each containing only `"id"` field with CId value.
|
||||
|
||||
### Life Entry (lives/*.json)
|
||||
```json
|
||||
{
|
||||
"772426": {
|
||||
"name": {
|
||||
"nominative": "Прп. Сильвестра Печерского (XII)",
|
||||
"short": "Прп. Сильвестра Печерского"
|
||||
},
|
||||
"life": {
|
||||
"id": "minei-0101-772426",
|
||||
"copyright": "Четьи-Минеи свт. Димитрия Ростовского",
|
||||
"text": "<p>Преподобный отец наш Сильвестр...</p>"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
**Structure**: Object keyed by CId (string), each containing:
|
||||
- `name` object with case variants (`nominative`, `short`, `genitive`, etc.)
|
||||
- `life` object (optional) with `id`, `copyright`, and `text` fields
|
||||
|
||||
### Calendar Entry
|
||||
```json
|
||||
{
|
||||
"pascha": { "year": 2025, "date": "04-20" },
|
||||
"fixed": [
|
||||
{ "date": "01-01", "rank": 5, "celebration": "Circumcision" }
|
||||
]
|
||||
}
|
||||
```
|
||||
**Structure**: Contains movable feast calculations and fixed calendar data.
|
||||
|
||||
### Service Template Entry
|
||||
```json
|
||||
{
|
||||
"ROYALHOURS": {
|
||||
"0": {
|
||||
"text": "In the name of the Father...",
|
||||
"type": "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
**Structure**: Hierarchical service structure with text nodes and conditional logic.
|
||||
|
||||
---
|
||||
|
||||
## File Routing Rules
|
||||
|
||||
### Lives File Routing
|
||||
Lives bundles are routed based on CId prefix:
|
||||
|
||||
| CId Pattern | Target File | Examples |
|
||||
|-------------|--------------|----------|
|
||||
| `01XX-01ZZ` | `01.json` | `010101`, `014567` |
|
||||
| `02XX-02ZZ` | `02.json` | `023456`, `027890` |
|
||||
| ... | ... | ... |
|
||||
| `12XX-12ZZ` | `12.json` | `123456`, `127890` |
|
||||
| Other CIds | `misc.json` | `772426`, `373`, `2396` |
|
||||
|
||||
**Examples:**
|
||||
- `010101` → `01.json`
|
||||
- `1253` → `12.json`
|
||||
- `772426` → `misc.json`
|
||||
- `373` → `misc.json`
|
||||
|
||||
### Bundle File Naming
|
||||
- Main bundle: `menaion-bundle.json` (per language)
|
||||
- Language overrides: `{lang}-menaion-bundle.json`
|
||||
- No prefix-based routing for bundles (single file per language)
|
||||
|
||||
---
|
||||
|
||||
## Data Components Breakdown
|
||||
|
||||
### Menaion Bundles
|
||||
**Purpose**: Authoritative date → CId mapping for calendar rendering
|
||||
|
||||
**Structure**: Date-keyed JSON with arrays of CIds
|
||||
```json
|
||||
{
|
||||
"01-01": [{ "id": "010101" }, { "id": "772426" }],
|
||||
"01-02": [{ "id": "010201" }, { "id": "772455" }]
|
||||
}
|
||||
```
|
||||
|
||||
**Coverage**: 366 Julian calendar days × multiple entries per day
|
||||
**File Size**: ~50-100KB per language
|
||||
**Usage**: Calendar view determines which saints to display on each day
|
||||
|
||||
### Lives Bundles
|
||||
**Purpose**: Saint biographies and lives for enrichment
|
||||
|
||||
**Structure**: CId-keyed JSON with name variants and optional life text
|
||||
```json
|
||||
{
|
||||
"772426": {
|
||||
"name": {
|
||||
"nominative": "Прп. Сильвестра Печерского (XII)",
|
||||
"short": "Прп. Сильвестра Печерского"
|
||||
},
|
||||
"life": {
|
||||
"id": "minei-0101-772426",
|
||||
"copyright": "Четьи-Минеи свт. Димитрия Ростовского",
|
||||
"text": "<p>Complete life text in HTML...</p>"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Coverage**: 3046 total CIds, 1190 with life.text enriched
|
||||
**Routing**: Prefix-based (01.json-12.json + misc.json)
|
||||
**Usage**: Lives display on saint detail pages
|
||||
|
||||
### Calendar Data
|
||||
**Purpose**: Movable feast calculations and calendar metadata
|
||||
|
||||
**Components**:
|
||||
- `shared/calendar/triodion.json` — Pre-Lent through Holy Week
|
||||
- `shared/calendar/pentecostarion.json` — Pascha through All Saints
|
||||
- `{lang}/calendar/` — Language-specific calendar data
|
||||
|
||||
**Key Features**:
|
||||
- Paschalion calculations
|
||||
- Movable feast dating
|
||||
- Fasting period definitions
|
||||
- Holiday and commemoration metadata
|
||||
|
||||
### Service Templates
|
||||
**Purpose**: Structured liturgical service data with conditional logic
|
||||
|
||||
**Organization**:
|
||||
```
|
||||
services/
|
||||
├── octoecheos/ # Eight tones × days
|
||||
├── triodion/ # 37 Lenten sections
|
||||
├── pentecostarion/ # 50 Paschal days
|
||||
├── menaion/ # 366 daily entries + 34 feasts
|
||||
├── canons/ # Paraclete, Octoechos, Great Canon
|
||||
└── shared/templates/ # Reusable service components
|
||||
```
|
||||
|
||||
**Structure**: Hierarchical JSON with text nodes and conditional prefixes
|
||||
- **P-prefix nodes**: Optional content that may be included
|
||||
- **Var/I-prefix nodes**: Conditional selection logic
|
||||
- **Plain nodes**: Required content always included
|
||||
|
||||
### Bible Metadata
|
||||
**Purpose**: Bible version mappings and reading pericopes
|
||||
|
||||
**Structure**: Version identifiers and pericope mappings across 13 Bible versions
|
||||
- Church Slavonic
|
||||
- Russian Synodal
|
||||
- KJV
|
||||
- Brenton (Septuagint)
|
||||
- Vulgate
|
||||
- Other versions
|
||||
|
||||
### Prayer Rules & Commands
|
||||
**Purpose**: Daily cycle structures and prayer rule definitions
|
||||
|
||||
**Components**:
|
||||
- **Prayer Rules**: Daily reading schedules
|
||||
- **Commands**: Service command structures
|
||||
- **Horologion**: Hours, Kathismata, Compline, etc.
|
||||
|
||||
### Fasting Rules
|
||||
**Purpose**: Period definitions and fasting exceptions
|
||||
|
||||
**Structure**: JSON with fasting periods, exceptions, and detailed rules
|
||||
- Pre-Lent periods
|
||||
- Great Lent
|
||||
- Fast-free periods
|
||||
- Fish/strict fasting days
|
||||
|
||||
---
|
||||
|
||||
## Data Management Tools
|
||||
|
||||
### Conversion Pipeline (`scripts/convert-*.ts`)
|
||||
|
||||
#### Master Script
|
||||
**`convert-all.ts`** — Orchestrates all conversion steps
|
||||
```bash
|
||||
npm run convert
|
||||
```
|
||||
|
||||
Converts XML data from Java Ponomar sources to JSON format.
|
||||
|
||||
#### Individual Converters
|
||||
|
||||
**`convert-lives.ts`** — Saint lives XML → JSON conversion
|
||||
- Input: `ponomar/Ponomar/languages/{lang}/xml/lives/*.xml`
|
||||
- Output: `{lang}/lives/{01.json|misc.json}` bundles
|
||||
- Features:
|
||||
- XML parsing with attribute extraction
|
||||
- Name case normalization
|
||||
- Grammar data extraction
|
||||
- Service data extraction
|
||||
- Scripture reference extraction
|
||||
- Bundle generation by month prefix
|
||||
|
||||
**`convert-calendar.ts`** — Calendar metadata conversion
|
||||
- Input: XML calendar data
|
||||
- Output: JSON calendar structures
|
||||
- Features:
|
||||
- Movable feast calculations
|
||||
- Fixed feast mappings
|
||||
- Period definitions
|
||||
|
||||
**`convert-services.ts`** — Service template conversion
|
||||
- Input: XML service definitions
|
||||
- Output: JSON service templates
|
||||
- Features:
|
||||
- Hierarchical structure preservation
|
||||
- Conditional logic extraction
|
||||
- Text node normalization
|
||||
|
||||
**`convert-bible-meta.ts`** — Bible metadata extraction
|
||||
- Input: XML bible metadata
|
||||
- Output: JSON version mappings and pericopes
|
||||
|
||||
**`convert-fasting.ts`** — Fasting rules conversion
|
||||
- Input: XML fasting definitions
|
||||
- Output: JSON fasting rules and periods
|
||||
|
||||
**`convert-commands.ts`** — Command structure conversion
|
||||
- Input: XML command definitions
|
||||
- Output: JSON command structures
|
||||
|
||||
**`convert-service-rules.ts`** — Service rule extraction
|
||||
- Input: XML service rule definitions
|
||||
- Output: JSON service rules
|
||||
|
||||
### Migration Tools (`scripts/migrate-data.ts`)
|
||||
|
||||
**Purpose**: Normalize data format across versions and languages
|
||||
|
||||
**Operations:**
|
||||
1. Strip `@_` prefixes from lives name keys (all languages)
|
||||
2. Remove `SId` from menaion entries (keep id = CId) (all languages)
|
||||
3. Rename service directories to lowercase (cu, el, fr, zh/Hans, zh/Hant, ru)
|
||||
4. Flatten Octoecheos structure (cu, fr, zh/Hans, zh/Hant)
|
||||
5. Convert `TEXT` → `text` in command files
|
||||
6. Move shared services into `templates/` subdirectory
|
||||
7. Normalize name key casing (Nominative → nominative, Short → short)
|
||||
8. Migrate merged calendar files (triodion.json, pentecostarion.json)
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
npm run migrate # Apply migrations
|
||||
npm run migrate:dry # Preview changes
|
||||
```
|
||||
|
||||
### Validation Suite (`scripts/validate-*.ts`)
|
||||
|
||||
#### Main Validator
|
||||
**`validate-data.ts`** — Comprehensive data validation
|
||||
```bash
|
||||
npx tsx scripts/validate-data.ts
|
||||
```
|
||||
**Validates:**
|
||||
- Life entry structure (required fields)
|
||||
- Lives bundle format (CId keys, name objects)
|
||||
- Calendar data integrity
|
||||
- Service template structure
|
||||
- Prayer format compliance
|
||||
- Command node structure
|
||||
- Commemoration entries
|
||||
- Fasting rule definitions
|
||||
|
||||
**Output:** File count, errors, warnings
|
||||
|
||||
#### Specialized Validators
|
||||
**`validate-i18n.ts`** — Internationalization completeness
|
||||
```bash
|
||||
npx tsx scripts/validate-i18n.ts
|
||||
```
|
||||
Checks coverage across languages (en/ru/cu).
|
||||
|
||||
**`validate-tabs.ts`** — Service tab/template consistency
|
||||
```bash
|
||||
npx tsx scripts/validate-tabs.ts
|
||||
```
|
||||
Validates that service tabs match template structures.
|
||||
|
||||
**`validate-menaion.ts`** — Menaion data validation
|
||||
```bash
|
||||
npx tsx scripts/validate-menaion.ts
|
||||
```
|
||||
Validates menaion entries against calendar rules.
|
||||
|
||||
**`validate-prayer-rule.ts`** — Prayer rule structure validation
|
||||
```bash
|
||||
npx tsx scripts/validate-prayer-rule.ts
|
||||
```
|
||||
Validates prayer rule format and completeness.
|
||||
|
||||
**Period-specific Validators:**
|
||||
- `validate-triodion.ts` — Triodion period validation
|
||||
- `validate-pentecostarion.ts` — Pentecostarion validation
|
||||
- `validate-holy-week.ts` — Holy Week validation
|
||||
- `validate-great-canon.ts` — Great Canon validation
|
||||
- `validate-great-compline.ts` — Great Compline validation
|
||||
- `validate-libcs.ts` — Library content validation
|
||||
|
||||
### Utility Tools (`scripts/tools/`)
|
||||
|
||||
**`search-texts.ts`** — Full-text search across data files
|
||||
```bash
|
||||
npx tsx scripts/tools/search-texts.ts <query> [--lang en] [--type prayers]
|
||||
```
|
||||
|
||||
**`stats.ts`** — Data statistics and size analysis
|
||||
```bash
|
||||
npx tsx scripts/tools/stats.ts [--lang en]
|
||||
```
|
||||
|
||||
Provides file counts, sizes, and category breakdowns.
|
||||
|
||||
---
|
||||
|
||||
## Enrichment Process
|
||||
|
||||
### Overview
|
||||
The enrichment process fills empty `life.text` fields in ru/lives bundles using Chetyi-Minei (St. Dimitri of Rostov) hagiographic texts.
|
||||
|
||||
### Source Preparation: Chetyi-Minei Import
|
||||
|
||||
**`convert-minei.ts`** — Converts Chetyi-Minei EPUB to date-keyed JSON
|
||||
|
||||
**Input Layout (extracted EPUB):**
|
||||
```
|
||||
extracted-epub/
|
||||
├── index_split_000.xhtml through index_split_9999.xhtml
|
||||
├── toc.ncx
|
||||
└── content.opf
|
||||
```
|
||||
|
||||
**Process:**
|
||||
1. Parse day files sequentially
|
||||
2. Extract headings: `h2` for dates (`"Память 1 января"`), `h3` for chapter titles
|
||||
3. Extract paragraphs: `<p class="paragraph1">` for content
|
||||
4. Collect footnotes from `<a title="...">` anchors
|
||||
5. Append notes as "Примечания:" block
|
||||
6. Apply heading date corrections (e.g., `calibre_toc_10023` → `01-27`)
|
||||
7. Build output structure: `{ "MM-DD": [{ title, html }] }`
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
npx tsx scripts/convert-minei.ts <extracted-epub-dir> [output.json]
|
||||
```
|
||||
|
||||
**Output:** `scripts/output/minei.json` (gitignored, ~33MB)
|
||||
|
||||
### Enrichment Pipeline
|
||||
|
||||
**`enrich-lives.ts`** — Fuzzy-matches minei titles to CId names and fills empty lives
|
||||
|
||||
**Inputs:**
|
||||
- `scripts/output/minei.json` — Source lives by date (MM-DD)
|
||||
- `static/data/cu/menaion-bundle.json` — Authoritative date→CId map
|
||||
- `static/data/ru/lives/*.json` — Target bundles for enrichment
|
||||
|
||||
**Matching Strategy:**
|
||||
1. **Tokenization**: Split titles into tokens, filter ROLE_WORDS
|
||||
2. **Dice Coefficient**: Calculate similarity over token sets
|
||||
3. **Status Classification**:
|
||||
- `already-filled` — Target already has `life.text` → skip
|
||||
- `auto` — Score ≥ 0.6, empty target → write
|
||||
- `review` — Score 0.35–0.6 → manual review
|
||||
- `unmatched` — Score < 0.35 or no candidates → unmatched
|
||||
|
||||
**Manual Overrides:**
|
||||
```typescript
|
||||
const MANUAL_FIXES: Record<string, string> = {
|
||||
'02-02|сказание о сретении': '373',
|
||||
'03-24|воспоминание о чуде': '822',
|
||||
// 214 entries total
|
||||
}
|
||||
```
|
||||
Key format: `{date}|{distinctive substring}` → CId
|
||||
|
||||
**Collision Handling:** Multiple sources map to same CId
|
||||
- First source: writes `life.html` directly (no heading)
|
||||
- Subsequent sources: append `<p><b>{title}</b></p>{html}`
|
||||
|
||||
**File Routing:**
|
||||
```typescript
|
||||
function bundleFileForCid(cid: string): string {
|
||||
return /^(0[1-9]|1[0-2])\d+/.test(cid)
|
||||
? `${cid.substring(0, 2)}.json`
|
||||
: 'misc.json';
|
||||
}
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
# Dry run: report only
|
||||
npx tsx scripts/enrich-lives.ts
|
||||
|
||||
# Limit to one month
|
||||
npx tsx scripts/enrich-lives.ts --month 01
|
||||
|
||||
# Apply changes
|
||||
npx tsx scripts/enrich-lives.ts --write
|
||||
|
||||
# Apply changes for specific month
|
||||
npx tsx scripts/enrich-lives.ts --write --month 01
|
||||
```
|
||||
|
||||
**Output:** `scripts/output/lives-match-report.json` with match status per source
|
||||
|
||||
### Workflow Example
|
||||
|
||||
**Phase 1: Source Preparation**
|
||||
```bash
|
||||
npx tsx scripts/convert-minei.ts ~/Downloads/chetyi-minei-epub/
|
||||
# Output: scripts/output/minei.json
|
||||
```
|
||||
|
||||
**Phase 2: Dry Run Analysis**
|
||||
```bash
|
||||
npx tsx scripts/enrich-lives.ts
|
||||
# Shows: Auto-applied: 184, needs review: 127, unmatched: 94
|
||||
# Review: scripts/output/lives-match-report.json
|
||||
```
|
||||
|
||||
**Phase 3: Manual Review & Fixes**
|
||||
- Analyze `review` entries in report
|
||||
- Add MANUAL_FIXES for problematic matches
|
||||
- Re-run until `review` count acceptable
|
||||
|
||||
**Phase 4: Write & Validate**
|
||||
```bash
|
||||
npx tsx scripts/enrich-lives.ts --write
|
||||
# Shows: Wrote 7 updated bundle(s)
|
||||
npx tsx scripts/validate-data.ts
|
||||
npx tsc --noEmit
|
||||
npm run build
|
||||
```
|
||||
|
||||
**Phase 5: Commit**
|
||||
```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"
|
||||
```
|
||||
|
||||
### Quality Controls
|
||||
|
||||
**Collision Verification:** Check multi-chapter entries have correct headings
|
||||
```bash
|
||||
python3 -c "
|
||||
import json, re
|
||||
misc = json.load(open('static/data/ru/lives/misc.json'))
|
||||
for cid in ['493', '1674', '257401']: # Known collision targets
|
||||
text = misc[cid]['life']['text']
|
||||
headings = re.findall(r'<b>([^<]+)</b>', text)
|
||||
print(f'{cid}: {len(headings)} chapters - {headings}')
|
||||
"
|
||||
```
|
||||
|
||||
**Coverage Tracking:** Monitor enrichment progress
|
||||
```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'Coverage: {has}/{total} ({has*100//total}%) lives with text')
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quality Assurance Workflow
|
||||
|
||||
### Pre-Commit Checklist
|
||||
|
||||
1. **Data Validation**
|
||||
```bash
|
||||
npx tsx scripts/validate-data.ts
|
||||
# Expected: "All files valid!" or specific error count
|
||||
```
|
||||
|
||||
2. **Type Safety**
|
||||
```bash
|
||||
npm run check # or npx tsc --noEmit
|
||||
# Expected: No TypeScript errors
|
||||
```
|
||||
|
||||
3. **Build Verification**
|
||||
```bash
|
||||
npm run build
|
||||
# Expected: Successful build with bundle sizes
|
||||
```
|
||||
|
||||
4. **Functional Testing**
|
||||
```bash
|
||||
npm run dev
|
||||
# Manual test: Calendar view, saint detail pages, lives display
|
||||
```
|
||||
|
||||
### Continuous Monitoring
|
||||
|
||||
**Automated Checks:**
|
||||
- File count validation (should be 274 files)
|
||||
- JSON parseability (all data files)
|
||||
- Required field presence (nominative, life.text for enriched entries)
|
||||
- CId consistency (same CId should have same name across languages)
|
||||
|
||||
**Issue Detection:**
|
||||
- Corrupted JSON files → parse errors in validate-data.ts
|
||||
- Missing required fields → validation warnings
|
||||
- Type mismatches → TypeScript errors
|
||||
- Build failures → invalid data structures
|
||||
|
||||
### Issue Resolution
|
||||
|
||||
**Common Validation Errors:**
|
||||
1. **"Missing nominative"** — Name object lacks nominative case
|
||||
- **Solution**: Add `name.nominative` field to affected entries
|
||||
|
||||
2. **"Failed to parse"** — Corrupted JSON file
|
||||
- **Solution**: Re-run conversion or fix JSON syntax
|
||||
|
||||
3. **"Rank should be 0-8"** — Invalid rank value
|
||||
- **Solution**: Normalize rank to range 0-8
|
||||
|
||||
4. **Build bundle size changes** — Unexpected file size increases
|
||||
- **Solution**: Check for duplicate or malformed content
|
||||
|
||||
---
|
||||
|
||||
## Common Issues & Solutions
|
||||
|
||||
### OCR Artifacts in Minei Texts
|
||||
|
||||
**Problem:** Chetyi-Minei conversion produces OCR issues like:
|
||||
- Latin characters in Russian text (`Taиcии` instead of `Таисии`)
|
||||
- Footnote markers `[1]` in body text
|
||||
- Erratic punctuation `[1]` in titles
|
||||
|
||||
**Solution:**
|
||||
- Keep OCR artifacts as-is (part of source text)
|
||||
- Manual fixes use exact OCR substrings for matching
|
||||
- Examples: `'02-15|onissima, odnogo iz lika'` → `'450'`
|
||||
|
||||
### Homonym Resolution on Same Date
|
||||
|
||||
**Problem:** Multiple saints share similar names on same date
|
||||
|
||||
**Examples:**
|
||||
- 03-24: Иаков исповедник (68501) vs other Иаков entries
|
||||
- 02-22: Варадат vs Фалассий (both map to 493)
|
||||
- 09-03: Анфим, Аристион, Василиса on same date
|
||||
|
||||
**Solution:**
|
||||
- Use distinctive substrings in MANUAL_FIXES
|
||||
- Ensure uniqueness per date (verify with verification script)
|
||||
- For collisions: both sources map to same CId (append behavior)
|
||||
|
||||
### Cross-Date Narratives
|
||||
|
||||
**Problem:** Some minei chapters are narratives not tied to a specific feast
|
||||
|
||||
**Examples:**
|
||||
- 02-02: "Сказание о Сретении Господнем" (presentation narrative)
|
||||
- 03-24: "Воспоминание о чуде в Печерском монастыре" (miracle story)
|
||||
- 08-28: "Память святой праведной Анны" (prophetess Anna)
|
||||
|
||||
**Solution:**
|
||||
- Identify appropriate CId for the saint/event
|
||||
- Map with MANUAL_FIXES even if not on same date (though current pipeline is date-based)
|
||||
- For entries with no appropriate CId: remain unmatched
|
||||
|
||||
### Bundle Mis-Mappings
|
||||
|
||||
**Problem:** Some CIds are listed on wrong calendar dates
|
||||
|
||||
**Example:**
|
||||
- 868 Иаков Боровицкий listed under 05-22, actual feast 10-23
|
||||
|
||||
**Solution:**
|
||||
- Manually correct menaion-bundle.json
|
||||
- Move CIds from incorrect date to correct date
|
||||
- Verify with calendar sources and tradition
|
||||
|
||||
### File Routing Edge Cases
|
||||
|
||||
**Problem:** Ambiguous routing for CIds at boundaries
|
||||
|
||||
**Edge Cases:**
|
||||
- `00` prefixes → misc.json (not 00.json)
|
||||
- `99` prefixes → misc.json (not 09.json)
|
||||
- Non-numeric CIds → misc.json
|
||||
|
||||
**Solution:**
|
||||
```typescript
|
||||
/^(0[1-9]|1[0-2])\d+/.test(cid) // Match only 01-12 followed by digits
|
||||
```
|
||||
|
||||
### Multi-Chapter Collision Display
|
||||
|
||||
**Problem:** When multiple sources append to same CId, first chapter lacks heading
|
||||
|
||||
**Behavior:**
|
||||
- First source: writes `life.html` directly (no title)
|
||||
- Subsequent sources: append `<p><b>{title}</b></p>{html}`
|
||||
- Result: First chapter unheaded, others clearly marked
|
||||
|
||||
**Acceptable Trade-off:** Consistent with all single-chapter lives (which have no heading)
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### NPM Scripts Summary
|
||||
|
||||
```bash
|
||||
# Development
|
||||
npm run dev # Start development server
|
||||
npm run build # Production build
|
||||
npm run preview # Preview production build
|
||||
|
||||
# Data Conversion
|
||||
npm run convert # Convert all XML sources to JSON
|
||||
npm run migrate # Normalize to current format
|
||||
npm run migrate:dry # Preview migration changes
|
||||
|
||||
# Validation
|
||||
npm run check # Type check (tsc --noEmit)
|
||||
npx tsx scripts/validate-data.ts # Main validator
|
||||
npx tsx scripts/validate-i18n.ts # i18n completeness
|
||||
npx tsx scripts/validate-tabs.ts # Service consistency
|
||||
|
||||
# Tools
|
||||
npx tsx scripts/tools/search-texts.ts <query> # Search data files
|
||||
npx tsx scripts/tools/stats.ts # Data statistics
|
||||
|
||||
# Enrichment
|
||||
npx tsx scripts/convert-minei.ts <epub-dir> # Import Chetyi-Minei
|
||||
npx tsx scripts/enrich-lives.ts # Dry run enrichment
|
||||
npx tsx scripts/enrich-lives.ts --write # Apply enrichment
|
||||
```
|
||||
|
||||
### File Extensions
|
||||
|
||||
| Extension | Purpose | Format |
|
||||
|-----------|---------|--------|
|
||||
| `.json` | All static data files | JSON |
|
||||
| `.text` | Plain text resources | Plain text |
|
||||
| `.xml` | Source data (not in repo) | XML |
|
||||
|
||||
### Git Strategy
|
||||
|
||||
**Tracked:** `static/data/` (except output files)
|
||||
**Ignored:**
|
||||
- `scripts/output/minei.json` (33MB, generated)
|
||||
- `node_modules/`
|
||||
- `dist/`
|
||||
|
||||
### Important File Paths
|
||||
|
||||
```bash
|
||||
# Data directories
|
||||
static/data/cu/menaion-bundle.json # Calendar authority
|
||||
static/data/ru/lives/ # Target for enrichment
|
||||
static/data/shared/services/ # Shared service templates
|
||||
|
||||
# Scripts
|
||||
scripts/enrich-lives.ts # Enrichment pipeline
|
||||
scripts/convert-minei.ts # Minei import
|
||||
scripts/validate-data.ts # Main validator
|
||||
|
||||
# Output files
|
||||
scripts/output/minei.json # Minei source (gitignored)
|
||||
scripts/output/lives-match-report.json # Match report
|
||||
```
|
||||
|
||||
### Coverage Statistics
|
||||
|
||||
**Current Status:**
|
||||
- Total CIds: 3046
|
||||
- Lives with text: 1190 (39%)
|
||||
- Empty lives: 1856 (61%)
|
||||
|
||||
**Enrichment Progress:**
|
||||
- Chetyi-Minei chapters: 1154 total
|
||||
- Matched: 1127 (auto 64 + already-filled 1063)
|
||||
- Unmatched: 27 (floor: narratives, no-target, already-filled)
|
||||
|
||||
### Status Classifications
|
||||
|
||||
| Status | Meaning | Action |
|
||||
|--------|---------|--------|
|
||||
| `auto` | Score ≥ 0.6, empty target | Automatically written |
|
||||
| `already-filled` | Target already has life.text | Skip (redundant) |
|
||||
| `review` | Score 0.35–0.6 | Manual review required |
|
||||
| `unmatched` | Score < 0.35 or no candidates | No suitable target |
|
||||
|
||||
### Key Constants
|
||||
|
||||
**File Paths:**
|
||||
```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';
|
||||
```
|
||||
|
||||
**Matching Thresholds:**
|
||||
```typescript
|
||||
const AUTO_THRESHOLD = 0.6; // Automatic write
|
||||
const REVIEW_THRESHOLD = 0.35; // Manual review
|
||||
```
|
||||
|
||||
**Copyright String:**
|
||||
```typescript
|
||||
const COPYRIGHT = 'Четьи-Минеи свт. Димитрия Ростовского';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
- **Initial release** — Complete data format and enrichment process documentation
|
||||
- **Updated** — Added bundle mis-mapping section, cross-date narrative handling, QA workflow
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
When contributing to the data format or enrichment pipeline:
|
||||
|
||||
1. **Test thoroughly:** Run validation, typecheck, and build before committing
|
||||
2. **Document changes:** Update this documentation for any schema changes
|
||||
3. **Preserve compatibility:** Maintain existing file routing rules and naming conventions
|
||||
4. **Validate data:** Run `validate-data.ts` and fix any errors
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For questions or issues with the static data format:
|
||||
- Review this documentation
|
||||
- Check existing issues in the repository
|
||||
- Run validation tools for error diagnosis
|
||||
- Examine the enrichment pipeline for matching problems
|
||||
+837
@@ -0,0 +1,837 @@
|
||||
# Документация по формату статических данных
|
||||
|
||||
## Оглавление
|
||||
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.json # CId без месячного префикса
|
||||
│ ├── menaion/ # Ежедневные записи минеи (366 дней)
|
||||
│ ├── calendar/ # Метаданные календаря
|
||||
│ └── services/ # Шаблоны богослужений
|
||||
├── cu/ # Церковнославянский (аналогичная структура)
|
||||
├── ru/ # Русский (жития, богослужения)
|
||||
├── 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.json` | `772426`, `373`, `2396` |
|
||||
|
||||
**Примеры:**
|
||||
- `010101` → `01.json`
|
||||
- `1253` → `12.json`
|
||||
- `772426` → `misc.json`
|
||||
- `373` → `misc.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 всего, 1190 с обогащённым life.text
|
||||
**Маршрутизация**: по префиксу (01.json-12.json + misc.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.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` и исправляйте любые ошибки
|
||||
|
||||
---
|
||||
|
||||
## Поддержка
|
||||
|
||||
По вопросам или проблемам с форматом статических данных:
|
||||
- Ознакомьтесь с этой документацией
|
||||
- Проверьте существующие проблемы в репозитории
|
||||
- Запустите инструменты валидации для диагностики ошибок
|
||||
- Изучите конвейер обогащения для проблем сопоставления
|
||||
@@ -29,7 +29,7 @@ npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Data files in `static/data/` are pre-converted JSON (not committed). To regenerate from the Java XML sources, run:
|
||||
Data files in `static/data/` are tracked in git. The only gitignored output is `scripts/output/minei.json` (33MB Chetyi-Minei source).
|
||||
|
||||
```bash
|
||||
npm run convert # re-convert all data from XML
|
||||
@@ -46,9 +46,16 @@ npm run preview # preview production build
|
||||
## QA / Validation
|
||||
|
||||
```bash
|
||||
npx tsx scripts/validate-i18n.ts # i18n completeness (en/ru/cu)
|
||||
npx tsx scripts/validate-tabs.ts # service tab/template consistency
|
||||
npx tsx scripts/assembler-test.ts # service assembler integration tests
|
||||
npx tsx scripts/validate-data.ts # Main validator (274 files checked)
|
||||
npx tsx scripts/validate-i18n.ts # i18n completeness (en/ru/cu)
|
||||
npx tsx scripts/validate-tabs.ts # service tab/template consistency
|
||||
npx tsx scripts/validate-menaion.ts # menaion data validation
|
||||
npx tsx scripts/validate-prayer-rule.ts # prayer rule structure validation
|
||||
npx tsx scripts/validate-triodion.ts # Triodion period validation
|
||||
npx tsx scripts/validate-pentecostarion.ts # Pentecostarion validation
|
||||
npx tsx scripts/validate-holy-week.ts # Holy Week validation
|
||||
npx tsx scripts/validate-great-canon.ts # Great Canon validation
|
||||
npx tsx scripts/assembler-test.ts # service assembler integration tests
|
||||
```
|
||||
|
||||
## Liturgical Text Categories (static/data/shared/services/)
|
||||
@@ -60,7 +67,7 @@ npx tsx scripts/assembler-test.ts # service assembler integration tests
|
||||
- **Canons** — Paraclete (weekday, 8 tones × 6 days = 48), Octoechos (Sunday, 8 tones), Great Canon
|
||||
- **Services** — 78 data-backed services with full.json (Pascha, Paralytic, Sergius, Pokrov, etc.; Var/I-prefix + bare P-prefix varNodes now intercepted)
|
||||
- **Horologion / Sbornik / Prayer Rule / Akathists / Parimii / Paraclete / Irmologion** — daily-cycle collections
|
||||
- **Lives** — Saint lives (en/cu, name.nominative validated by `validate-data.ts`)
|
||||
- **Lives** — Saint lives (en/cu/ru, 1190/3046 with life.text enriched from Chetyi-Minei)
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -69,9 +76,9 @@ src/
|
||||
core/ — Domain logic (calendar, paschalion, service assembly, i18n)
|
||||
ui/ — View components (app, calendar, bible, service, settings)
|
||||
main.ts — Entry point
|
||||
scripts/ — Data conversion, migration, validation, and CLI tools
|
||||
scripts/ — Data conversion, migration, validation, enrichment, and CLI tools
|
||||
static/
|
||||
data/ — Liturgical data as JSON (not committed, generated from Java XML via npm run convert)
|
||||
data/ — Liturgical data as JSON (tracked in git, generated from Java XML via npm run convert)
|
||||
fonts/ — Church Slavonic fonts
|
||||
icons/ — PWA icons
|
||||
```
|
||||
@@ -79,3 +86,14 @@ static/
|
||||
## License
|
||||
|
||||
Same as the original Java project.
|
||||
|
||||
## Documentation
|
||||
|
||||
- **[DATA_FORMAT.md](DATA_FORMAT.md)** — Comprehensive static data format documentation in English
|
||||
- **[DATA_RUS.md](DATA_RUS.md)** — Complete Russian documentation of data format and enrichment process
|
||||
|
||||
Covers:
|
||||
- Static data models, routing rules, and component breakdown
|
||||
- Complete tool inventory for conversion, migration, and validation
|
||||
- Chetyi-Minei enrichment pipeline and quality assurance workflow
|
||||
- Quick reference for all available NPM scripts and commands
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
# Ponomar — Православный календарь PWA
|
||||
|
||||
Прогрессивное веб-приложение для православного церковного календаря, богослужебных текстов и чтений Писания.
|
||||
|
||||
Произведено из оригинального Java-приложения Ponomar от Александра Андреева, Юрия Шардта и Сергея Ф.
|
||||
|
||||
**Демо:** <https://ponomar.atroshin.ru>
|
||||
|
||||
## Возможности
|
||||
|
||||
- **Calendar** — Просмотр сеток месяцев с литургическими днями, периодами поста, чинами и празднованиями. Поддерживает юлианский календарь с григорианскими эквивалентами.
|
||||
- **Service Reader** — Сборка богослужебных текстов (часов, кафизм) из структурированных шаблонов с условной логикой.
|
||||
- **Bible Reader** — Чтение Писания на 13 языках (церковнославянский, русский синодальный, KJV, Брентон, Вульгата и др.). Позиция чтения для каждой версии сохраняется между сессиями.
|
||||
- **Многоязычный интерфейс** — Английский, русский, церковнославянский (со специальными шрифтами для церковнославянского).
|
||||
- **PWA** — Устанавливается на настольные и мобильные устройства.
|
||||
- **Навигация** — 3 элемента верхнего уровня (Calendar, Library, Settings) с выпадающим меню Library: Библия, Service (Часослов, Сборник, Молитвенное правило, Каноны и акафисты, Паримии, Пареклит, Ирмологий), Праздники (Минея, Постная Триодь).
|
||||
|
||||
## Технологический стек
|
||||
|
||||
- [TypeScript](https://www.typescriptlang.org/) — полностью типизированный
|
||||
- [Vite](https://vitejs.dev/) — инструмент сборки
|
||||
- [Tailwind CSS v4](https://tailwindcss.com/) — CSS с утилитарными классами
|
||||
- [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) — конвертация устаревшего XML (только ручной режим)
|
||||
|
||||
## Начало работы
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Файлы данных в `static/data/` отслеживаются в git. Единственный игнорируемый файл вывода — `scripts/output/minei.json` (33МБ источник Четьи-Миней).
|
||||
|
||||
Для повторного создания из XML-источников Java Ponomar запустите:
|
||||
|
||||
```bash
|
||||
npm run convert # повторная конвертация всех данных из XML
|
||||
npm run migrate # нормализация к текущему формату
|
||||
```
|
||||
|
||||
Установите `PONOMAR_JAVA_HOME` для указания на локальный клон репозитория Java Ponomar (по умолчанию `../ponomar`).
|
||||
|
||||
```bash
|
||||
npm run build # продуктивная сборка
|
||||
npm run preview # предпросмотр продуктивной сборки
|
||||
```
|
||||
|
||||
## QA / Валидация
|
||||
|
||||
```bash
|
||||
npx tsx scripts/validate-data.ts # Главный валидатор (274 файлов проверено)
|
||||
npx tsx scripts/validate-i18n.ts # Полнота i18n (en/ru/cu)
|
||||
npx tsx scripts/validate-tabs.ts # Согласованность вкладок/шаблонов богослужений
|
||||
npx tsx scripts/validate-menaion.ts # Валидация данных минеи
|
||||
npx tsx scripts/validate-prayer-rule.ts # Валидация структуры правила молитвы
|
||||
npx tsx scripts/validate-triodion.ts # Валидация периода Триоди
|
||||
npx tsx scripts/validate-pentecostarion.ts # Валидация Пятидесятницы
|
||||
npx tsx scripts/validate-holy-week.ts # Валидация Страстной седмицы
|
||||
npx tsx scripts/validate-great-canon.ts # Валидация Великого канона
|
||||
npx tsx scripts/assembler-test.ts # Интеграционные тесты сборщика богослужений
|
||||
```
|
||||
|
||||
## Категории литургических текстов (static/data/shared/services/)
|
||||
|
||||
- **Triodion** — 37 разделов (Масленица → Великий пост → Страстная седмица)
|
||||
- **Pentecostarion** — 50 дней (Пасха → Все святые)
|
||||
- **Menaion (daily)** — 367 ежедневных записей (одна на каждый день юлианского календаря)
|
||||
- **Menaion (feasts)** — 34 неподвижных праздника с отдельными богослужениями
|
||||
- **Canons** — Пареклит (будние дни, 8 гласов × 6 дней = 48), Осмогласник (воскресенье, 8 гласов), Великий канон
|
||||
- **Services** — 78 богослужений с полными данными (Пасха, расслабленный, Сергий, Покров и др.; Var/I-префикс + простые P-узлы varNodes теперь перехватываются)
|
||||
- **Horologion / Sbornik / Prayer Rule / Akathists / Parimii / Paraclete / Irmologion** — коллекции суточного круга
|
||||
- **Lives** — Жития святых (en/cu/ru, 1190/3046 с обогащённым life.text из Четьи-Миней)
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
src/
|
||||
core/ — Логика предметной области (календарь, пасхалия, сборка богослужений, i18n)
|
||||
ui/ — Компоненты представления (приложение, календарь, библия, богослужения, настройки)
|
||||
main.ts — Точка входа
|
||||
scripts/ — Конвертация данных, миграция, валидация, обогащение и инструменты CLI
|
||||
static/
|
||||
data/ — Литургические данные в формате JSON (отслеживаются в git)
|
||||
fonts/ — Шрифты для церковнославянского языка
|
||||
icons/ — Иконки PWA
|
||||
```
|
||||
|
||||
## Лицензия
|
||||
|
||||
Такая же, как у оригинального Java-проекта.
|
||||
|
||||
## Документация
|
||||
|
||||
- **[DATA_FORMAT.md](DATA_FORMAT.md)** — Комплексная документация формата статических данных на английском языке
|
||||
- **[DATA_RUS.md](DATA_RUS.md)** — Полная русская документация формата данных и процесса обогащения
|
||||
|
||||
Охватывает:
|
||||
- Модели статических данных, правила маршрутизации и разбор компонентов
|
||||
- Полный набор инструментов для конвертации, миграции и валидации
|
||||
- Конвейер обогащения Четьи-Миней и рабочий процесс контроля качества
|
||||
- Краткий справочник по всем доступным npm-скриптам и командам
|
||||
Reference in new issue
Block a user