@coopenomics/docs-factory 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Anthony Fu <https://github.com/antfu>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,162 @@
1
- # Temporary Holding Version
1
+ # @coopenomics/docs-factory
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Фабрика документов цифрового кооператива. Собирает юридически значимые документы
4
+ по шаблонам из цепи и данным пайщиков: модель документа → HTML (Nunjucks) → PDF
5
+ (WeasyPrint 67). Хэш документа — SHA-256 PDF; повторная сборка по метаданным даёт
6
+ тот же документ байт в байт.
7
+
8
+ Пакет вынесен из монорепозитория `C9S/mono` 29.10.2026 (шаг 6а фабрики v2).
9
+ Прежнее имя `@coopenomics/factory` устарело.
10
+
11
+ ## Что внутри
12
+
13
+ - **Сборщики всех видов документов** цифрового кооператива — 92 вида (`src/Actions`).
14
+ Сборщик — объявление: какие данные прочитать на блок документа и как собрать
15
+ из них модель (`defineBuilder`, `src/Builder`).
16
+ - **Версии сборщиков** `major.minor`. Версия пишется в `meta.builder` нового
17
+ документа; пересборка идёт ровно той версией, что записана в мете. Все версии
18
+ вида документа — в одном файле: `Factory` (1.0) и дописанные в конец
19
+ `Factory_1_1`, `Factory_2_0`. Выпущенная версия заморожена: исправление —
20
+ новый `minor` в конце файла.
21
+ - **Шаблоны и реестр шаблонов** (`src/Templates`) с номерами редакций; ключ
22
+ `x-builder` в схеме редакции объявляет, под какой `major` сборщика она написана.
23
+ - **Порт хранилища** `IFactoryStorage` и реализации: PostgreSQL
24
+ (`PostgresFactoryStorage`, Kysely) и память (`MemoryFactoryStorage`).
25
+ - **Порт данных цепи** `IChainDataSource`: шаблоны, таблицы и действия на блок.
26
+
27
+ ## Установка
28
+
29
+ ```bash
30
+ pnpm add @coopenomics/docs-factory cooptypes
31
+ ```
32
+
33
+ `cooptypes` — зависимость приложения (`peerDependencies`): фабрика берёт тот
34
+ выпуск, что стоит у приложения.
35
+
36
+ Для PDF нужен WeasyPrint 67 в `/venv/bin/python3` и системный шрифт Arial —
37
+ как в образе контроллера (`components/controller/Dockerfile` в `C9S/mono`).
38
+
39
+ ## Использование
40
+
41
+ ```ts
42
+ import { Generator, PostgresFactoryStorage } from '@coopenomics/docs-factory'
43
+
44
+ const generator = new Generator(chainDataSource) // реализация IChainDataSource
45
+ await generator.connect(new PostgresFactoryStorage({ host, port, user, password, database }))
46
+
47
+ // Новая сборка: версия сборщика — по объявлению действующей редакции шаблона
48
+ const document = await generator.generate({ registry_id: 1, coopname: 'voskhod', username: 'ant', lang: 'ru' })
49
+
50
+ // Пересборка по метаданным подписанного документа — тем же сборщиком
51
+ const same = await generator.generate({ ...document.meta }, { skip_save: true })
52
+ ```
53
+
54
+ Таблицы хранилища на узле создаёт миграция контроллера; отдельному приложению —
55
+ `await storage.ensureSchema()`.
56
+
57
+ ## Разработка
58
+
59
+ Тесты и эталоны запускаются только в CI (workflow `Factory`, `.github/workflows/factory.yml`)
60
+ на каждый пуш. Локально — сборка и проверки сборщиков:
61
+
62
+ | Команда | Что делает |
63
+ |---|---|
64
+ | `pnpm build` | сборка (unbuild) с проверкой типов |
65
+ | `pnpm lint` | ESLint |
66
+ | `pnpm check` | полнота экспорта сборщиков, чтения на блок, заморозка версий |
67
+ | `node scripts/x-builder-check.mjs` | `x-builder` не меняется внутри редакции (после `pnpm build`) |
68
+ | `node scripts/golden-coverage.mjs` | у каждого вида документа есть эталон |
69
+
70
+ Эталоны — `test/golden/<номер>/<случай>.{html,meta.json,pdf.sha256}`. Пересоздать —
71
+ пуш в ветку `ci/update`, забрать артефакт `factory-golden`, закоммитить; только
72
+ при осознанной смене вывода. Правила для сборщиков — `CLAUDE.md`.
73
+
74
+ Совместная правка с монорепозиторием: в `C9S/mono` — `pnpm factory:link`
75
+ (подключает этот чекаут, ожидается в `~/docs-factory`) и `pnpm factory:unlink`.
76
+
77
+ ## Выпуск
78
+
79
+ 1. Поднять `version` в `package.json` (семантическая версия), коммит в `main`.
80
+ 2. Тег `vX.Y.Z` (предварительный — `vX.Y.Z-dev.N`) в `C9S/docs-factory`.
81
+ 3. Workflow `Release`: проверки Factory → сверка тега с версией → публикация в npm
82
+ (предварительная — с меткой `next`) → робот открывает PR в `C9S/mono` → `dev`
83
+ с новой точной версией во всех `package.json` и `pnpm-lock.yaml`.
84
+
85
+ Монорепозиторий поднимает версию только этим PR: гейт `pnpm check` держит
86
+ точную и одну версию, контроллер при старте сверяет установленную фабрику с
87
+ объявленной.
88
+
89
+ ## Приватные данные документа: `doc_data`
90
+
91
+ Зарезервированный механизм для документов, содержащих персональные данные (ФИО экспедитора, паспорт, госномер, телефон и т.п.), которые **не должны попадать в блокчейн**.
92
+
93
+ ### Поток
94
+
95
+ 1. Контроллер собирает приватный payload и вызывает `generator.saveDocData(payload, registry_id)` — возвращается `{ hash }` (sha256, идемпотентный).
96
+ 2. `hash` передаётся on-chain в Action под зарезервированным именем `doc_data_hash`.
97
+ 3. При сборке и пересборке фабрика подгружает payload из хранилища (`getDocData(hash)`) и подставляет в модель документа как `doc_data`.
98
+ 4. Шаблон документа использует приватные поля как `{{ doc_data.<field> }}`.
99
+
100
+ ### Пример
101
+
102
+ Контроллер:
103
+
104
+ ```ts
105
+ const { hash } = await generator.saveDocData({
106
+ expeditor_full_name: 'Иванов Иван Иванович',
107
+ passport: '4509 123456',
108
+ phone: '+79991234567',
109
+ vehicle_registration_number: 'А123ВВ77',
110
+ }, 1103)
111
+
112
+ // в Action документа 1103 (MarketplaceTransportNote):
113
+ await generator.generate({
114
+ registry_id: 1103,
115
+ coopname: 'voskhod',
116
+ username: operatorAccount,
117
+ shipment_id,
118
+ doc_data_hash: hash,
119
+ })
120
+ ```
121
+
122
+ Сборщик (`src/Actions/1103.MarketplaceTransportNote.ts`) объявляет чтение, каркас его выполняет:
123
+
124
+ ```ts
125
+ reads: ({ data, f }) => ({
126
+ docData: () => f.loadDocData<TransportNoteDocData>(data),
127
+ // …
128
+ }),
129
+ assemble: ({ meta, reads: { docData } }) => ({ meta, doc_data: docData, /* … */ }),
130
+ ```
131
+
132
+ Шаблон (`src/Templates/1103.MarketplaceTransportNote.ts`):
133
+
134
+ ```html
135
+ <tr><th>Экспедитор</th><td>{{ doc_data.expeditor_full_name }}</td></tr>
136
+ <tr><th>Госномер</th><td>{{ doc_data.vehicle_registration_number }}</td></tr>
137
+ ```
138
+
139
+ ### Зарезервированные имена шаблона
140
+
141
+ | Имя | Источник | Применение |
142
+ |---|---|---|
143
+ | `meta` | factory | заголовки, дата, lang, hash |
144
+ | `coop` | factory | реквизиты кооператива |
145
+ | `vars` | factory | переменные кооператива |
146
+ | `user` | factory | подписант (по сертификату) |
147
+ | `request` / `program` / `decision` | factory | контекст ЦПП |
148
+ | `branch` | factory | данные КУ |
149
+ | **`doc_data`** | **DocDataService** | **приватные данные документа** |
150
+
151
+ ### Graceful degradation
152
+
153
+ Если приватные данные удалены (например, по запросу пайщика), документ остаётся **верифицируемым по хэшу подписи** (хэш зафиксирован on-chain), но не регенерируется. Это явное архитектурное решение: ценность блокчейн-подписи сохраняется; восстановление PDF — обратимо deprecated.
154
+
155
+ ### Когда применять
156
+
157
+ - **Новые документы** с персональными данными — сразу через `doc_data`.
158
+ - **Существующие документы** (700-1099, 300-304 и т.д.) — остаются без изменений. Паттерн прогрессивный, переводить старые документы при отсутствии необходимости не нужно.
159
+
160
+ ## Лицензия
161
+
162
+ [BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ru)