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

+251
View File
@@ -0,0 +1,251 @@
# Архитектура шаблона документов Scientia
## Системный контекст
```text
┌────────────────────┐ редактирует ┌──────────────────────────────────┐
│ Автор документа │ ────────────▶ │ 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, но обратной зависимости нет.
## Целевая структура
```text
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`.
## Ключевые интерфейсы
```typst
// Единственный пользовательский вход.
#let company-id = "scientia" // scientia | technology | too
#let document-mode = "final" // final | draft | clean-copy
#let use-private-assets = false // true, если скопирована .private
```
```typst
// Порядок и состав глав видны внизу main.typ.
#include "chapters/00-introduction.typ"
#pagebreak()
#include "chapters/10-main.typ"
```
```typst
// Отсутствующая .private не читается при false.
#let private-settings = if use-private-assets {
import "/.private/settings.typ": settings
settings
} else {
empty-private-settings
}
```
```typst
#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 лицензирование.