Files
laude/CHANGELOG.md

11 KiB
Raw Blame History

Changelog

Все заметные изменения проекта документируются здесь. Формат основан на Keep a Changelog, проект следует Semantic Versioning.

Unreleased

[0.5.2] — 2026-05-19

Большая внутренняя итерация: тройной независимый аудит (~220 находок), закрыты топ-приоритеты. Тестов 53, ESLint и Prettier чистые, typecheck OK.

Added

  • Prettier + ESLint + EditorConfig. Конфиги, скрипты npm run format / format:check / lint, CI-готовые правила. Вся src/ единообразно отформатирована.
  • Error Boundary на двух уровнях: вокруг всего App и вокруг роутов. Крах одной страницы (например, malformed history в HistoryHeatmap) больше не блэнкит окно — показывается локализованный fallback с кнопкой «Попробовать снова». Stack trace только в dev.
  • IPC validation layer (src/main/validate.ts) — hand-rolled схемы для всех renderer-supplied payload (intervalMinutes ∈ [1,1440], reps ∈ [1,9999], multiplier ∈ [0,1000], string-cap 200 chars, enum-валидация для theme/lang/notify-mode/stat, regex для HH:MM, дедупликация quietHours.days). Compromised renderer больше не может засунуть reps: NaN или intervalMinutes: -1 в стор.
  • Schema migrations framework. __schemaVersion в persisted-state, MIGRATIONS map для будущих структурных правок.
  • Modal focus trap + focus restore + aria-labelledby. Tab/Shift-Tab больше не вываливаются на нижний слой; на закрытии фокус возвращается на триггер.
  • Sidebar mobile drawer: Esc закрывает, focus trap внутри, focus restore на гамбургер, role="dialog" + aria-modal.
  • Tray menu i18n — пункты меню следуют settings.language.
  • Bilingual heatmap. Title, легенда, weekday-лейблы и tooltip с плюрализацией (1 повтор / 2 повтора / 5 повторов) — всё через i18n. 7 новых ключей weekday.short.*.
  • CHANGELOG.md по формату Keep a Changelog.

Fixed

  • Critical: данные больше не теряются на corrupt JSON. Раньше catch → makeInitial() молча затирал упражнения/историю. Теперь файл уезжает в app-state.json.corrupt-<timestamp>.
  • Atomic write через .tmp + rename + retry на EBUSY/EPERM (антивирус, OneDrive). Раньше обрыв питания мог дать truncate.
  • HIGH security: GSI server теперь верифицирует auth.token через timingSafeEqual против per-install токена. Раньше эндпоинт был полностью неаутентифицирован — любой локальный процесс мог подделать match-end.
  • HIGH security: shell.openExternal allowlist — только http/https/mailto. Раньше file:/javascript:/steam: уходили в OS handler.
  • HIGH security: dev IPC simulateMatchEnd убран из production билдов (gate на !app.isPackaged + import.meta.env.MODE).
  • HIGH security: GSI server reject Origin/Sec-Fetch-Site — блокирует CSRF от browser-вкладок. Body cap 256 KB (OOM-вектор закрыт). Require application/json. Generic 400 без error-echo.
  • isQuietAt wrap-around + day filter. С 22:00 → 07:00, days=[Mon..Fri] теперь правильно проверяется день начала окна (старт Fri 22:00 → активно ночью Sat 02:00).
  • DST drift в history.ts. Календарная арифметика (setDate) вместо ms-арифметики — на границе DST дни больше не дублируются.
  • Scheduler: broadcastState() после fire, защита от двойной регистрации powerMonitor listeners.
  • Settings IPC chatter. QuietTimesRow держит локальное состояние, IPC летит только на onBlur. Раньше скрабинг времени давал ~5 IPC, каждый переписывал app-state.json.
  • Dashboard «До следующего» показывает при паузе вместо обманчиво тикающего таймера.
  • HistoryHeatmap percentile-bucketing (p25/p50/p85) вместо относительной шкалы — outlier-день больше не схлопывает все нормальные дни в самый слабый бакет.
  • ReminderApp: Enter теперь корректно передаёт adjusted reps (раньше всегда planned). key={exercise.id+nextFireAt} сбрасывает степпер на новом fire. Степпер capped at 5× planned. Space не работает когда фокус на кнопке. Esc закрывает MatchSummary.
  • i18n.translate — split/join вместо regex (var-значения с регулярными метасимволами теперь интерполируются буквально).
  • icon.tsx lookup сужен до ICON_CHOICES — произвольное имя больше не зарезолвится в Lucide.default.
  • UpdaterCard NaN guard на download-progress (electron-updater даёт undefined в ранних событиях).
  • format.ts guard от NaN/Infinity в formatCountdown.
  • updateExercise/updateChallenge стрипают id из patch — рендер не может перезаписать identity.
  • clearHistory(undefined) теперь no-op (нужен явный boundary).

Removed

  • .gitea/workflows/*.yml — без runners оставляли queued runs. Релизим через release.ps1. has_actions на репо выключен.

0.5.1 — 2026-05-18

Fixed

  • Auto-update архитектурно переписан. Раньше publish.url включал ${version} и запекался в каждый билд — установленные копии видели только свой собственный релиз. Введён фиксированный …/releases/download/update-channel, который никогда не меняется.
  • Hourly auto-проверка работает в silent-режиме: транзитные сетевые ошибки (504, TLS drops) больше не показывают красный баннер «Ошибка проверки». Только ручной клик «Проверить» поднимает ошибку.
  • Boot-check ретраит 3 раза с backoff 30s/2m/5m.
  • В Up to date показывается «проверено N мин назад».
  • release.ps1 теперь публикует в три-четыре места одной командой: vX.Y.Z, update-channel, и переданные -BridgeTags для миграции пользователей со старых версий.
  • upload-release-assets.ps1 ретраит curl до 4 раз с backoff на 504 / TLS-сбрасывание; до ретрая проверяет, не залился ли файл на самом деле (Gitea часто принимает body, но таймаутит ответ).
  • Скрипты — ASCII-only (PS5.1 без BOM падает на em-dash).

Removed

  • .gitea/workflows/*.yml — Gitea Actions без настроенных runners оставляли queued runs в репозитории. Релизим через release.ps1.

0.5.0 — 2026-05-18

Added

  • История + стрики. Каждое выполненное упражнение пишется в app-state.json (cap 10k записей, trim oldest 10% на overflow). Heatmap-календарь 12 недель на Dashboard, ежедневный счётчик «сделано сегодня», серия дней подряд (с grace-периодом за вчера).
  • Тихие часы. Окно времени, в которое напоминания подавляются. Поддержка wrap-around (22:00 → 08:00) и фильтра по дням недели.
  • Частичное выполнение. Степпер /+ в окне напоминания: можно отметить «сделал 5 из 10», в историю запишется честное число.
  • README.md на русском — описание, фичи, установка, dev-команды, архитектура, стек.

Changed

  • markDone(id, actualReps?) принимает фактическое число повторений.

Tests

  • +18 тестов (5 для тихих часов, 13 для истории/стриков). Всего 51.

0.4.0 — 2026-05-17

Added

  • Английская локализация. Самописная i18n: плоский словарь ~200 ключей × 2 языка + хук useT() + плюрализация (CLDR rules для RU: one/few/many).
  • Селектор языка в Settings, переключение мгновенное.

[0.3.x] — 2026-05-17

Серия мелких релизов с дизайн-итерациями (Apple iOS / macOS aesthetic): шрифты Plus Jakarta Sans + Bricolage Grotesque, светлая/тёмная/системная тема, vibrancy sidebar, iOS-grouped lists, spring-анимации.

0.2.0 — 2026-05-16

Added

  • Dota 2 Game State Integration: локальный HTTP-сервер парсит callbacks от Steam, после Победа/Поражение показывает «причитающиеся» повторения (например 10 смертей × 3 = 30 приседаний).

[0.1.x] — 2026-05-15 .. 2026-05-16

Первые публичные сборки: ядро напоминаний (упражнения, интервалы, иконки), системный трей, автозапуск с Windows, native-уведомления, NSIS-инсталлятор, auto-update через electron-updater.