Files
2026-10-09 04:24:38 +00:00

17 KiB
Raw Permalink Blame History

Архитектура шаблона документов Scientia

Системный контекст

┌────────────────────┐  редактирует  ┌──────────────────────────────────┐
│ Автор документа    │ ────────────▶ │ main.typ + chapters/ + assets/  │
└─────────┬──────────┘               └────────────────┬─────────────────┘
          │ читает                                    │ один import фасада
          ▼                                           ▼
┌────────────────────┐               ┌──────────────────────────────────┐
│ docs/              │               │ .template/lib/                  │
│ инструкции и       │               │ domain → application →          │
│ примеры            │               │ infrastructure → presentation   │
└────────────────────┘               └────────────────┬─────────────────┘
                                                      │
┌────────────────────┐  условный import               │ PDF
│ .private/          │ ────────────▶ main.typ ─────────┤
│ PNG + settings.typ │  один boolean                  ▼
                                             ┌────────────────────┐
                                             │ document.pdf       │
                                             └────────────────────┘

┌────────────────────┐  сопровождает  ┌─────────────────────────────────┐
│ Разработчик        │ ─────────────▶ │ .template/development/          │
│ шаблона            │                │ docs + modules + tests + tools  │
└────────────────────┘                └─────────────────────────────────┘

Публичная и developer-документация физически разделены. Автору не требуется открывать .template/, а разработчик не использует docs/ как описание внутренних контрактов.

Архитектурные принципы

  1. Один файл ежедневной настройки. Компания, режим, metadata и #include находятся в main.typ.
  2. Режим — значение, а не entrypoint. final, draft и clean-copy являются вариантами одной переменной.
  3. Публичное видно. Инструкции и примеры находятся в docs/, который VS Code не скрывает.
  4. Разработка скрыта. Библиотека, tests, ADR и tools находятся в .template/.
  5. Пример является исполняемой документацией. Один исходник одновременно обучает, компилируется в CI и устанавливается как тип документа.
  6. Важные параметры явные. Даже отключённые значения показаны как none, false или ().
  7. Приватное не отслеживается. Вся папка .private/, включая настройки offsets, исключена из Git; tracked placeholders никогда не заменяются реальными файлами.
  8. Один переключатель. При false условный import не читает .private; при true обычный preview и обычная build task используют её настройки.
  9. Фасад скрывает реализацию. Пользователь импортирует только /.template/lib/index.typ.
  10. Domain не зависит от layout. Presentation использует domain contracts, но обратной зависимости нет.

Целевая структура

README.md                         # короткий маршрут автора
main.typ                          # единственная точка входа и настройки
chapters/                         # пользовательский текст
assets/                           # изображения, данные и bibliography
docs/                             # публичная документация
├── README.md
├── documents.md
├── formatting.md
├── vscode.md
├── git.md
├── private-assets.md
├── writing-style.md
├── troubleshooting.md
└── examples/
    ├── README.md
    ├── private/
    │   └── settings.typ
    ├── documents/
    │   ├── report/
    │   ├── letter/
    │   ├── commercial-offer/
    │   └── contract/
    └── formatting/
.vscode/                          # tracked workspace configuration
├── extensions.json
├── settings.json
└── tasks.json
.private/                         # ignored settings, private media и backups
├── settings.typ
├── executors/
├── scientia/
├── technology/
└── too/
.template/                        # скрытая реализация
├── lib/
├── companies/
└── development/
    ├── docs/
    ├── modules/
    ├── tests/
    ├── tools/
    └── vscode/

В чистом fork каталог .private/ не обязателен. Обычная компиляция использует placeholders из .template/lib/assets/placeholders/.

Компоненты

Компонент Ответственность Публичный интерфейс
Рабочее пространство автора Один входной файл, главы и ресурсы main.typ, chapters/, assets/
Публичная документация Обучение без знания реализации README.md, docs/*.md
Публичные примеры Исполняемые примеры и источники выбора типа docs/examples/**/main.typ
VS Code workspace Рекомендации, автосохранение и задачи .vscode/*.json
Публичный фасад Единственный пользовательский Typst import .template/lib/index.typ
Document Domain Профиль, context и render options document-profile(), render-options()
Company Domain Реквизиты и firm resources company-profile()
Parties Domain Адресаты, подписанты и стороны recipient(), signer(), party()
Attachments Domain Порядок и идентичность приложений attachment(), attachment-set()
Render Application Resolve, normalize, validate, render render-document()
Company Adapter JSON profiles и resource overrides load-company()
Presentation Foundation, components и четыре renderer profiles.report/letter/commercial_offer/contract
Employee/Private Adapter Справочник сотрудников, private media и offsets report-executor(), private-company-media()
Test Harness Static, compile, semantic и visual gates run-tests.py

Data flow

Обычная сборка

  1. Автор выбирает company-id и document-mode в main.typ.
  2. main.typ создаёт profile, company overrides, bibliography и attachments.
  3. #show: document.with(...) передаёт последующие #include как тело документа.
  4. Facade вызывает application use case.
  5. Application разрешает компанию, нормализует и валидирует profile metadata.
  6. Renderer применяет foundation, нумерацию, media policy и компонует страницы.
  7. При none для подписи или печати final renderer использует круг или крест.
  8. Typst создаёт document.pdf.

Выбор типа документа

  1. Задача VS Code получает report, letter, commercial-offer или contract.
  2. Tool сохраняет текущие main.typ и chapters/ в .private/starter-backups/<timestamp>/.
  3. Tool копирует соответствующий публичный пример из docs/examples/documents/.
  4. Автор проверяет явно перечисленные параметры нового main.typ.

Приватная сборка

  1. Пользователь копирует готовую папку .private с settings.typ и PNG.
  2. В main.typ значение use-private-assets меняется с false на true.
  3. Условный import загружает .private/settings.typ.
  4. Adapter сопоставляет публичный идентификатор сотрудника с фиксированным именем PNG и применяет private offset.
  5. Отсутствующая или отключённая запись возвращает none; строка подписи остаётся пустой.
  6. Обычная build task и Tinymist preview используют один и тот же main.typ.

Ключевые интерфейсы

// Единственный пользовательский вход.
#let company-id = "scientia" // scientia | technology | too
#let document-mode = "final" // final | draft | clean-copy
#let use-private-assets = false // true, если скопирована .private
// Порядок и состав глав видны внизу main.typ.
#include "chapters/00-introduction.typ"
#pagebreak()
#include "chapters/10-main.typ"
// Отсутствующая .private не читается при false.
#let private-settings = if use-private-assets {
  import "/.private/settings.typ": settings
  settings
} else {
  empty-private-settings
}
#show: document.with(
  company: company,
  profile: profiles.report(..),
  options: (
    mode: document-mode,
    watermark: if document-mode == "draft" { "ЧЕРНОВИК" } else { none },
    media-policy: if document-mode == "final" { "placeholder" } else { "reserve-space" },
    diagnostics: true,
  ),
)

Публичная и developer-документация

Слой Расположение Содержит Не содержит
Публичный README.md, docs/ первый запуск, Git, типы, formatting, папку .private, troubleshooting DDD, ADR, snapshots, migration internals
Developer .template/development/docs/, modules/ архитектуру, решения, границы и тестирование обязательный маршрут обычного автора

Корневой README обязан ссылаться на каждую публичную тему. Developer README доступен одной отдельной ссылкой и не конкурирует с пользовательской навигацией.

Публичные примеры

Пример Обязательное покрытие
Report титул, stage/volume, executors, includes, рисунки, таблица, formula, references, bibliography, appendix
Letter recipient, исходящий номер, основной текст, attachment list, signer
Commercial offer recipient, subject, price, tax, сроки, payment, scope appendix
Contract parties, representatives, sections, requisites, signing, appendix
Formatting варианты изображений, grid, простые/сложные таблицы, CSV, формулы, labels, lists

Публичный пример не должен ссылаться на скрытый developer asset. Допустим только импорт фасада /.template/lib/index.typ.

Политика приватных ресурсов

Ресурс Git Поведение
Публичные реквизиты и логотипы tracked Загружаются из .template/companies/
Векторные placeholders tracked Используются обычной сборкой по умолчанию
docs/examples/private/settings.typ tracked Полный безопасный пример с enabled: false
.template/lib/infrastructure/employees.typ tracked ФИО, обычные роли и фиксированные имена PNG
.private/ ignored Настройки доступности, offsets, реальные изображения и backups

Typst 0.15 не предоставляет проверки существования файла. Поэтому отсутствие подписи моделируется отсутствующей записью или enabled: false; только включённая запись создаёт private path.

Технологические решения

Решение Выбор Обоснование
Compiler Typst 0.15.1+ Проверенный baseline и path type
Архитектура Модульный монолит Один процесс сборки без лишней инфраструктуры
Root entry Один main.typ Минимум выбора и все параметры в одном месте
Режимы Переменная document-mode Варианты видны комментариями, нет дублирования файлов
Public docs Видимый docs/ Автор находит примеры в Explorer
Examples Executable documentation Код и объяснение не расходятся
Private activation Literal use-private-assets + conditional import Один понятный параметр, clean fork не читает отсутствующий каталог
Internal boundary .template/ Реализация и developer docs не мешают автору
Testing Python + Typst + Poppler Контракты, PDF semantic и визуальный layout

Режимы отказа

Сбой Влияние Митигация
Автор меняет режим не в main.typ Ожидаемый вариант PDF не получается README и comments показывают единственную переменную
Пример использует скрытый developer asset После очистки development сборка падает Static path audit и compile всех public examples
Выбор типа уничтожает текст Потеря работы Timestamp backup до удаления chapters/
Подпись ещё не получена Private compile падает при прямом path Запись отсутствует или enabled: false, resolver возвращает none
Включённая запись не имеет PNG Ошибка Typst с точным path Включать запись только после копирования PNG; troubleshooting
Реальный файл попадает в Git Утечка подписи .gitignore, ignored .private/, no overwrite tracked placeholders
Сложная таблица переполняет страницу Нарушение layout Formatting example, stress fixture, repeated header tests
Публичная ссылка устарела Автор теряет маршрут Automated Markdown link audit
Изменение Typst меняет layout Тихая регрессия Version gate и snapshot review

Вне области видимости v1

  • Поддержка старых root-файлов document.typ, draft.typ и clean-copy.typ.
  • Автоматическое определение существования private files внутри Typst.
  • Хранение реальных подписей и печатей в Git или Git LFS.
  • Публикация внутренних VSIX в этом репозитории.
  • Юридическая экспертиза договора.
  • Научная верификация пользовательского содержания.
  • Генерация DOCX.
  • Публичная публикация в Typst Universe и open-source лицензирование.