Initial commit
This commit is contained in:
commit
c534d5ce80
163 files changed
+11500
No files matched your search
@@ -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 лицензирование.
|
||||
Reference in new issue
Block a user