Repository navigation
v0.2.0
Производительность списков и выгрузки. Аудит выявил три подтверждённые проблемы — все три исправлены в #43.
База данных
В схеме не было ни одного индекса, а SQLite, в отличие от PostgreSQL, не индексирует внешние ключи автоматически. Каждая выборка стадий и рисков расчёта, полей шаблона и поиск активного шаблона шли полным сканом таблицы.
Индексы добавлены строго под запросы, которые есть в коде — лишние только замедляют запись:
| Модель | Индекс |
|---|---|
Stage, Risk |
[calculationId, order] |
FormField, StageTemplate, RiskTemplate |
[templateId, order] |
Calculation |
[createdAt], [templateId], [status, createdAt] |
FormTemplate |
[isActive] |
EXPLAIN QUERY PLAN подтверждает SEARCH USING INDEX вместо SCAN.
Списки
Экраны «Все расчёты», «Архитектор» и «Админ» читали таблицу целиком и вдобавок тянули каждую стадию со всеми полями, включая длинный requirements, ради двух чисел в колонке «Трудозатраты». Теперь читается одна страница (50 строк) и только отображаемые поля.
На экране архитектора разделение на «ожидают согласования» и «остальные» делалось фильтрацией полного массива в памяти — заменено двумя запросами. Очередь согласования по-прежнему показывается целиком, постранично идёт только архив под ней.
API
/api/calculations, /api/templates и /api/users принимают ?page и ?limit (потолок 200). Тело ответа осталось массивом, поэтому существующие вызовы не ломаются, но добавлены заголовки X-Total-Count / X-Page / X-Page-Size / X-Total-Pages — ограничение выдачи видно клиенту, а не происходит молча.
Изменение поведения: по умолчанию эти эндпоинты теперь отдают 50 записей вместо всей таблицы. Отсюда минорная версия, а не патч.
Выгрузка
Экспорт docx/xlsx/pdf/zip оборачивал результат в new Uint8Array(buffer), что для Node Buffer копирует все байты — вторая полная копия многомегабайтного документа в памяти. Заменено представлением поверх той же памяти.
Сборка
Исправлена сборка Docker-образа (#46): npm ci запускал скрипт prepare, а тот прогонял format и typecheck в слое, где ещё нет исходников, и обрывал установку. В GitHub Actions это было не видно, потому что раннер сам выставляет CI=true. Также синхронизирован package-lock.json (#45).
Образ
Собран локально как ghcr.io/onixus/evacal:v0.2.0 / :latest, digest sha256:b4ab990cc881450564c83327d3d7e91659e175f30c3e988b720b290ab0978ac9.
В GHCR не опубликован: GitHub Actions в репозитории сейчас не запускается — «recent account payments have failed or your spending limit needs to be increased». По той же причине у этого релиза нет прогонов CI; все шаги CI (lint, typecheck, тесты, build) прогонялись локально — 274 теста зелёные.
Образ проверен вживую: migrate создаёт схему на чистом томе, приложение отвечает 200 на /, /login, /?page=2 и /api/calculations, индексы в БД контейнера на месте.
Опубликовать образ после починки биллинга:
docker login ghcr.io -u onixus
docker push ghcr.io/onixus/evacal:v0.2.0
docker push ghcr.io/onixus/evacal:latest