Initial commit

This commit is contained in:
malysheva committed 2026-10-09 04:24:38 +00:00
commit c534d5ce80
163 files changed
+11500

No files matched your search

@@ -0,0 +1,30 @@
# ADR-0001: Typst 0.15.1 как минимальная платформа
**Дата**: 2026-08-26
**Статус**: Принято
## Контекст
Шаблон уже реализован на Typst и использует его counters, introspection, show rules и PDF-рендер. После обновления окружения доступен Typst 0.15.1, который добавляет несколько bibliographies, тип `path` для передачи project-relative ресурсов и более подробные diagnostics. Одновременно 0.15 меняет baseline некоторых layout-элементов, поэтому обновление должно сопровождаться визуальным аудитом.
Официальные основания: [changelog Typst 0.15.0](https://typst.app/docs/changelog/0.15.0/), [bibliography](https://typst.app/docs/reference/model/bibliography/), [path](https://typst.app/docs/reference/foundations/path/).
## Рассматриваемые варианты
1. **Остаться на Typst 0.14.2** — меньше миграционных рисков сейчас, но нет нативных нескольких bibliographies и нового `path`.
2. **Принять Typst 0.15.1+** — доступны нужные возможности, но требуется новый baseline и контроль будущих обновлений.
3. **Перейти на LaTeX или Word** — большая экосистема, но фактически требует переписать проверенную вёрстку и усложняет программируемые компоненты.
## Решение
Выбрали **Typst 0.15.1 как минимальную поддерживаемую версию**, потому что она уже установлена, поддерживает несколько bibliographies и даёт корректную модель передачи путей между пользовательским проектом и библиотекой.
Каждое обновление Typst выполняется отдельным изменением: сначала полная компиляционная и визуальная матрица, затем принятие новых snapshots.
## Последствия
**Становится проще**: тематические и поглавные библиографии, автономное подключение шаблона, диагностика layout convergence.
**Становится сложнее**: необходимо контролировать версию CLI и визуальные изменения baseline.
**Закрывает дверь на**: поддержку Typst 0.14 и более ранних версий без отдельной compatibility-ветки.
@@ -0,0 +1,37 @@
# ADR-0002: Публичные, пользовательские и приватные ресурсы
**Дата**: 2026-08-31
**Статус**: Принято
> Способ доставки через ZIP заменён папкой `.private` в [ADR-0010](0010-private-folder-and-employees.md). Граница публичных и приватных данных остаётся действующей.
## Контекст
Внутренний шаблон Scientia содержит фирменные реквизиты, логотипы, имена, подписи, печати и материалы конкретного документа. Логотипы, адреса, имена и реквизиты разрешено распространять внутри компании. Реальные подписи и печати нельзя хранить в Git вместе с шаблоном.
Typst не читает ZIP напрямую и не умеет проверить наличие изображения без попытки его загрузить. Поэтому приватный архив должен быть внешним каналом доставки, а отсутствие ресурса должно моделироваться значением `none`.
## Рассматриваемые варианты
1. **Оставить всё в одном tracked-каталоге** — максимально просто, но подписи и печати неизбежно распространяются с каждым форком.
2. **Хранить приватные изображения в Git LFS** — уменьшает основной репозиторий, но не устраняет доступ и историю распространения.
3. **Хранить подписи и печати в отдельном ZIP** — требует извлечения, зато отделяет приватный канал от шаблона.
4. **Не поддерживать реальные изображения вообще** — безопасно, но не покрывает подготовку финальных документов.
## Решение
Выбрали **три класса ресурсов**:
- публичные фирменные данные и логотипы хранятся в `.template/companies/`;
- материалы конкретного документа хранятся в `assets/`;
- реальные подписи и печати поставляются отдельным `private-assets.zip`; проверенная задача извлекает их в `.private/` и включает через `sys.inputs` только на время приватной сборки `main.typ`.
`.private/` и `private-assets*.zip` исключаются через `.gitignore`. В репозитории остаются только нейтральные placeholders: векторный круг для печати и крест для подписи. При значении ресурса `none` renderer использует placeholder; указанный путь обязан существовать.
## Последствия
**Становится проще**: безопасно форкать шаблон, централизованно обновлять публичные реквизиты и собирать документ без приватного архива.
**Становится сложнее**: для финального подписанного PDF нужно получить ZIP, извлечь его и явно указать пути.
**Закрывает дверь на**: хранение настоящих подписей и печатей в обычном Git, Git LFS или visual snapshots.
@@ -0,0 +1,28 @@
# ADR-0003: Синхронная детерминированная модель сборки
**Дата**: 2026-08-26
**Статус**: Принято
## Контекст
Сборка документа выполняется локальным Typst compiler: данные читаются из файлов проекта, затем происходит несколько внутренних итераций layout и создаётся PDF. Внешних сетевых сервисов, конкурентной записи или длительных независимых операций в v1 нет.
Добавление собственной async-модели не ускорит Typst-layout, но усложнит диагностику, воспроизводимость и тестирование.
## Рассматриваемые варианты
1. **Синхронная сборка одного документа** — простая, воспроизводимая и соответствует модели Typst.
2. **Параллельные renderer-профили внутри Typst** — не поддерживаются как управляемая модель и не дают изоляции layout-state.
3. **Внешний асинхронный build-сервис** — полезен для массовой генерации, но избыточен для локального шаблона.
## Решение
Выбрали **синхронную детерминированную сборку одного документа**. Параллельный запуск нескольких независимых fixtures допускается только во внешнем test harness, где каждый процесс получает собственный entry point и output.
## Последствия
**Становится проще**: воспроизводимость, порядок diagnostics, изоляция `state` и расследование visual regressions.
**Становится сложнее**: массовая генерация большого набора документов должна оркестрироваться внешним скриптом.
**Закрывает дверь на**: сетевые и фоновые операции непосредственно внутри шаблона v1.
@@ -0,0 +1,36 @@
# ADR-0004: Ранняя валидация и явные fallback-политики
**Дата**: 2026-08-26
**Статус**: Принято
## Контекст
Ошибки Typst часто проявляются во время layout далеко от места, где пользователь передал неверное значение. Для бизнес-документа особенно опасны тихие fallback: неверная компания, отсутствующая сторона, незаметно пропавшая подпись или citation, не попавшая в список источников.
При этом распространяемый шаблон должен компилироваться без реальных подписей и печатей. Они поставляются отдельным ZIP; PowerShell task проверяет и извлекает архив, после чего запускает `main.typ` с явным `sys.inputs`. Typst 0.15 не предоставляет проверки существования файла без попытки загрузки.
## Рассматриваемые варианты
1. **Полагаться только на diagnostics Typst** — мало кода, но сообщения не отражают доменный путь поля.
2. **Всегда аварийно завершаться при любом отсутствующем ресурсе** — строго, но шаблон нельзя удобно распространять без подписей.
3. **Валидировать domain до layout и явно моделировать необязательные ресурсы** — больше контрактов, зато ошибки предсказуемы.
## Решение
Выбрали **раннюю profile-specific валидацию**. Каждая ошибка называет профиль, путь поля, фактическое значение и ожидаемое ограничение.
Для подписи, печати и необязательных изображений поддерживаются политики:
- `hide` — не показывать ресурс и не резервировать место;
- `placeholder` — показать безопасную графическую заглушку: круг для печати или крест для подписи;
- `reserve-space` — оставить место для ручной подписи или печати.
Политика применяется только если поле равно `none`. Если поле содержит путь, но файл отсутствует, сборка завершается ошибкой.
## Последствия
**Становится проще**: распространение шаблона, поиск причины ошибки и тестирование негативных сценариев.
**Становится сложнее**: каждый профиль обязан определить required/optional поля и defaults.
**Закрывает дверь на**: молчаливое игнорирование неверно указанного пути к производственному ресурсу.
@@ -0,0 +1,37 @@
# ADR-0005: DDD-границы внутри модульного Typst-монолита
**Дата**: 2026-08-26
**Статус**: Принято
## Контекст
Шаблон должен расширяться новыми видами документов, но обычное использование должно оставаться простым. Один монолитный `show` с ветвлением по типу документа быстро свяжет корпоративные данные, file paths, domain-правила и пагинацию. Полноценные микросервисы или отдельные пакеты для каждого bounded context, напротив, избыточны для локальной Typst-библиотеки.
## Рассматриваемые варианты
1. **Одна функция с `if kind == ...`** — минимальный старт, но любое расширение меняет общее ядро и повышает риск регрессии.
2. **Модульный монолит с DDD-границами и profile contract** — изоляция без инфраструктурной сложности.
3. **Отдельный Typst package для каждого вида документа** — сильная физическая изоляция, но дублирование foundation и сложное совместное версионирование.
## Решение
Выбрали **модульный монолит** со слоями Domain → Application и адаптерами Infrastructure/Presentation. Domain не импортирует presentation или infrastructure. Новый вид документа добавляется новым `DocumentProfile`, а не новой веткой в `document()`.
Разрешённое направление зависимостей:
```text
Facade → Application → Domain
│ ▲
├→ Infrastructure
└→ Presentation → Shared Components
```
Presentation и Infrastructure могут создавать domain-значения или читать их, но не изменяют domain-инварианты.
## Последствия
**Становится проще**: добавление договора или другого профиля, независимые fixtures и локализация `show/state`.
**Становится сложнее**: необходимо поддерживать явные contracts и проверять import graph.
**Закрывает дверь на**: доступ domain-модулей к JSON, `image`, `page`, `context` и глобальным renderer-state.
@@ -0,0 +1,32 @@
# ADR-0006: Трёхуровневая стратегия регрессионного тестирования
**Дата**: 2026-08-26
**Статус**: Принято
## Контекст
Шаблон содержит хрупкую пагинацию, сложные таблицы, подписи, формулы, кириллическую нумерацию и show rules. Успешная компиляция не обнаруживает тихий перенос строки, наложение печати или изменение количества страниц. Чистый pixel-perfect diff, в свою очередь, слишком чувствителен к версии renderer и системным шрифтам.
## Рассматриваемые варианты
1. **Проверять только exit code компилятора** — быстро, но не защищает макет.
2. **Использовать только pixel-perfect snapshots** — ловит всё, но создаёт шум при допустимых изменениях окружения.
3. **Совместить unit, semantic и visual проверки** — больше инфраструктуры, зато дефекты классифицируются точнее.
## Решение
Выбрали **три уровня тестов**:
1. Domain unit tests через `typst eval` и `assert`.
2. Compile/semantic tests: exit code, diagnostics, A4, количество страниц, наличие обязательных текстовых маркеров и PDF metadata.
3. Visual regression: rasterize через Poppler, сравнивать контрольные области и полный perceptual diff с документированным порогом.
Snapshots создаются только из синтетического `test-company`; реальные подписи и печати не включаются в публичные тестовые изображения. Новая версия Typst всегда проверяется отдельным прогоном до обновления snapshots.
## Последствия
**Становится проще**: находить как логические, так и визуальные регрессии и безопасно менять отдельные profiles.
**Становится сложнее**: требуется Python/Poppler test runtime и процедура осознанного обновления эталонов.
**Закрывает дверь на**: автоматическое принятие новых snapshots при обычном тестовом запуске.
@@ -0,0 +1,39 @@
# ADR-0007: Минимальный корень и три режима одного документа
**Дата**: 2026-08-31
**Статус**: Устарело — заменено [ADR-0009](0009-single-main-and-public-docs.md)
## Контекст
> Этот ADR сохраняется как история промежуточного решения. Три entrypoint-файла были удалены после проверки на реальных отчётах: пользователю удобнее выбирать режим в одном `main.typ`.
В текущем корне служебные каталоги конкурируют с `chapters/` и `assets/`, а `main.typ` смешивает демонстрационные данные, настройку и сборку. Автору после форка нужен короткий маршрут без изучения DDD-слоёв, тестов и примеров.
Одновременно должны поддерживаться три выпуска одного содержания и четыре вида документов. Обратная совместимость со старыми путями не требуется.
## Рассматриваемые варианты
1. **Оставить служебные каталоги в корне** — удобно разработчику, но перегружает основной сценарий автора.
2. **Удалить тесты и документацию** — очищает корень, но делает шаблон хрупким и плохо сопровождаемым.
3. **Перенести внутреннее устройство в `.template/`** — сохраняет разработку и визуально отделяет её от пользовательских файлов.
4. **Создать отдельный entrypoint для каждого типа и режима** — явно, но приводит минимум к двенадцати корневым файлам и дублированию конфигурации.
## Решение
Выбрали **один скрытый каталог `.template/`**, общий `document.typ` и три корневые точки входа:
- `main.typ` передаёт `mode: "final"`;
- `draft.typ` передаёт `mode: "draft"`;
- `clean-copy.typ` передаёт `mode: "clean-copy"`.
Все entrypoints импортируют `render(mode:)` из `document.typ`. Report, letter, commercial-offer и contract starters реализуют одинаковый контракт, поэтому выбор типа документа не меняет entrypoints.
В starter явно записываются все семантически важные параметры, включая осознанные `none`, `false` и `()`. Низкоуровневые параметры layout остаются внутри библиотеки.
## Последствия
**Становится проще**: первый fork, переключение режима, выбор starter и обновление внутренней реализации.
**Становится сложнее**: `document.typ` является обязательным стабильным контрактом, а каждый starter должен проходить contract-tests.
**Закрывает дверь на**: compatibility-файлы в корне и отдельные копии полной конфигурации для каждого режима.
@@ -0,0 +1,35 @@
# ADR-0008: Версионируемая рабочая область VS Code и обучение автора
**Дата**: 2026-08-31
**Статус**: Принято
## Контекст
Основные пользователи шаблона пишут документы, но могут никогда не работать с кодом, Git и Typst. Устные инструкции и личные настройки редактора не воспроизводятся в новом форке. Одновременно каталог `.vscode/` не должен отвлекать автора от текста.
Часть расширений доступна в публичном Marketplace, а Typst Typewriter и Zotst распространяются внутри компании как локальные VSIX. Запись идентификатора расширения в рекомендациях VS Code не распространяет сам установочный пакет.
## Рассматриваемые варианты
1. **Не хранить настройки редактора** — корень формально проще, но каждый сотрудник вручную повторяет настройку и получает различное поведение.
2. **Настроить всё глобально на рабочих станциях** — удобно на одном компьютере, но не переносится вместе с форком и требует администрирования.
3. **Версионировать `.vscode/` и скрыть его в проводнике** — настройки синхронизируются через Git, оставаясь вне повседневной области автора.
4. **Положить локальные VSIX в шаблон** — обеспечивает автономную установку, но смешивает бинарные пакеты с исходниками и затрудняет централизованное обновление.
## Решение
Выбран вариант **версионировать `.vscode/`, но скрывать его из Explorer**:
- `extensions.json` содержит десять согласованных идентификаторов, включая два внутренних;
- `settings.json` включает автосохранение, языки проверки орфографии, TODO-маркеры и защитные настройки Git;
- `tasks.json` предоставляет обычную и приватную сборку, выбор одного из четырёх публичных примеров и компиляцию учебного каталога;
- внутренние VSIX хранятся в корпоративном хранилище, а README объясняет их установку;
- README и видимый `docs/` обучают Git в терминах истории документа, контрольных точек и параллельных версий.
## Последствия
**Становится проще**: первый запуск, одинаковая среда во всех форках, живой предпросмотр, проверка русского текста и совместная работа через Git.
**Становится сложнее**: изменения `.vscode/` требуют такого же review, как изменения шаблона; сопровождающий должен отдельно публиковать совместимые VSIX.
**Закрывает дверь на**: неявные обязательные глобальные настройки и распространение внутренних бинарных расширений внутри Git-шаблона.
@@ -0,0 +1,35 @@
# ADR-0009: Один main.typ, видимая документация и явная приватная сборка
**Дата**: 2026-08-31
**Статус**: Принято
> Часть решения об отдельной private build task заменена условным import из [ADR-0010](0010-private-folder-and-employees.md). Один `main.typ` и видимая публичная документация остаются действующими.
## Контекст
Проверка шаблона на реальных отчётах показала, что авторы ожидают менять компанию, стадию, режим и список глав в одном файле. Три корневых entrypoint-файла и скрытая пользовательская справка создавали лишний выбор. Одновременно Typst 0.15 не умеет безопасно проверять существование private path.
## Рассматриваемые варианты
1. **Сохранить `document.typ` и три entrypoints** — технически чисто, но пользователь должен понимать разделение ролей четырёх файлов.
2. **Один `main.typ` и tracked private placeholders с заменой** — просто, но реальная подпись становится изменением уже отслеживаемого файла.
3. **Один `main.typ`, public `docs/`, internal placeholders и private task** — минимальная поверхность без риска добавить реальный media в Git.
## Решение
Выбран третий вариант:
- `main.typ` содержит `company-id`, `document-mode`, metadata и `#include`;
- `docs/` видим и содержит executable examples;
- examples одновременно являются источниками задачи выбора типа;
- обычная сборка использует internal placeholders;
- задача приватной сборки проверяет `private-assets.zip`, копирует PNG в `.private/` и передаёт `--input private-assets=true`;
- прежний ADR-0007 считается устаревшим.
## Последствия
**Становится проще**: первый запуск, переключение режима, поиск примеров, выбор типа и выпуск с приватными изображениями.
**Становится сложнее**: main-файлы четырёх примеров частично повторяют setup-код; PowerShell tool становится security boundary для ZIP.
**Закрывает дверь на**: отдельные root entrypoints для режимов, скрытую public-документацию и замену tracked placeholders реальными файлами.
@@ -0,0 +1,26 @@
# ADR-0010: Папка `.private`, справочник сотрудников и частичные подписи
**Дата**: 2026-08-31
**Статус**: Принято
## Контекст
ZIP installer и отдельная build task скрывали второй переключатель private media от автора и не поддерживали реальные фамильные имена PNG. В проектах подписи поступают постепенно, а для каждого изображения уже подобрано индивидуальное вертикальное смещение. Чистый fork при этом обязан собираться без приватного каталога.
## Рассматриваемые варианты
1. **Оставить ZIP и `sys.inputs`** — безопасно для clean fork, но preview и обычная task не совпадают, а схема имён жёстко привязана к ролям.
2. **Автоматически сканировать `.private`** — желаемый UX, но Typst 0.15 не предоставляет file-exists и падает при попытке открыть отсутствующий PNG.
3. **Условный import и явная карта доступности** — один параметр в `main.typ`, отсутствие записи означает пустое место, offsets живут рядом с приватными PNG.
## Решение
Выбран вариант 3. Публичный tracked-справочник хранит идентификатор, ФИО, обычную должность и фиксированное имя PNG. Игнорируемый `.private/settings.typ` хранит доступность и offset. `main.typ` импортирует его только при literal `use-private-assets = true`. Все build/preview пути используют один entrypoint.
## Последствия
**Становится проще**: копировать `.private` целиком, менять роль сотрудника в одной строке, видеть реальные подписи в preview, работать при частично полученных PNG и публиковать clean fork с `false`.
**Становится сложнее**: при получении нового PNG нужно вручную включить запись; включённый, но отсутствующий файл по-прежнему вызывает точную ошибку Typst.
**Закрывает дверь на**: автоматическое определение файлов, role-based имена `responsible.png`, отдельную private build task и ZIP installer.