Два дефекта отображения синка: 1. SPA: new URL(path, '') бросал TypeError при пустом VITE_API_BASE → health-проба всегда null → «индекс недоступен», хотя бэкенд synced. Фолбэк base на window.location.origin (vite-proxy/nginx шлёт /v1 на api). vite.config — фикс-порт 5174 (strictPort) + proxy /v1 → :3030, наружу один ssh-проброс. 2. health.current_block брался из последней строки permission_history → «висел» на блоке последней смены прав (6303) в тихие периоды и читался как зависание. Теперь current = block_num tip-записи стрима (getParserHead) = докуда реально обработал парсер; растёт у головы в реальном времени. Побочно чинит C6: beyond_index сравнивал at с устаревшим current_block_time (31 мая) и ложно отбраковывал свежие запросы.
Верификатор документов Coopenomics v1
Монорепа доказательного верификатора документов: проверка целостности, криптоподписи (secp256k1/SHA-256) и исторической привязки ключа к аккаунту в блокчейне Coopenomics.
Структура (pnpm workspace)
| Пакет | Назначение |
|---|---|
packages/shared (@verifier/shared) |
Контракт .sig v2.0 + чистые проверки C1–C5 (браузер + Node). Не публикуется. |
apps/api (@verifier/api) |
Fastify + Kysely + Postgres. Demux-индексер permissions (native-delta из @coopenomics/parser2) + REST /v1/active-permission/*. |
apps/spa (@verifier/spa) |
Vue 3 + Vite + Tailwind v4 + Reka UI. Загрузка PDF+.sig/ZIP, оркестрация C1–C8, вердикт. |
Проверки
| # | Проверка | Где |
|---|---|---|
| C1 | Целостность (SHA-256(pdf) == doc_hash) |
shared, локально |
| C2 | meta_hash (канонизация JCS) |
shared, локально |
| C3 | Композитный хэш | shared, локально |
| C4 | Подпись secp256k1 | shared, локально |
| C5 | Наличие сертификата | shared, локально |
| C6 | Историческая привязка ключа к аккаунту | api /v1/active-permission/check |
| C7 | Самоподписанность (⚠ предупреждение) | spa |
| C8 | Доказательство в цепи (опц.) | spa через публичный RPC |
Разработка
pnpm install
docker compose up -d # postgres:5433 + redis:6380
pnpm -r build
pnpm dev:api # :3030
pnpm dev:spa # :5173
Дизайн-язык SPA
Минималистичный пространственный дизайн на плоскостях, один ведущий цвет — бордо #9f1239
(бренд кооперативной экономики). Бордо только в chrome; вердикт — отдельная семантика
(✅ зелёный / ❌ красный / ⚠ amber). Reka UI + Tailwind v4 + Radix Colors. Эталоны: Linear, Vercel, Raycast, Resend.
Локальный бутстрап против цепи mono-ai-N
Индексация permissions с genesis для проверки C6 на живых документах.
Предусловие: поднята цепь mono (docker compose up в ~/mono-ai-N) — nodeos отдаёт
chain API на :8888 и state-history (SHiP) на :8070.
bash deploy/bootstrap/bootstrap-local.sh
Скрипт достаёт chain_id из get_info, поднимает изолированные postgres+redis,
parser2 Parser (SHiP→Redis) и verifier-api (consumer+REST, миграции авто), стримит логи.
- Parser читает SHiP с genesis → Redis Stream; verifier-api потребляет native-delta
permission. - Прогресс:
curl http://localhost:3030/v1/health(current_block/head_block/status). - Перезапуск безопасен — parser2 резюмится по позиции в Redis, upsert идемпотентен
(натуральный ключ),
sync_progressхранит прогресс. Репарсинга с нуля при рестарте нет. - Полный реиндекс (осознанно):
docker compose -f deploy/bootstrap/docker-compose.bootstrap.yaml down -v.
SPA направить на этот api: VITE_API_BASE=http://localhost:3030.
Деплой
Автономные пайплайны из одной репы: deploy-api.yml (docker image → ssh) и deploy-spa.yml
(vite build → nginx static). Деплой одного приложения не триггерит другое.