Files
laude/CHANGELOG.md

211 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
Все заметные изменения проекта документируются здесь.
Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/),
проект следует [Semantic Versioning](https://semver.org/lang/ru/).
## [Unreleased]
## [0.5.3] — 2026-05-19
Полировка кастомного тайтлбара и размера окна.
### Added
- **Maximize/Restore.** Средняя кнопка тайтлбара (иконка квадрата)
раньше была «спрятать в трей» — выглядела как нативная Windows
maximize и сбивала с толку. Теперь это настоящий toggle на
весь экран: иконка свапается `Square``Copy` в зависимости
от состояния, aria-label локализован.
- **Double-click по тайтлбару** тоже toggleMaximize — стандартный
Windows-жест.
- **CLAUDE.md** в корне — контекст проекта для будущих сессий
Claude Code (стек, архитектура, команды, тех. долг).
### Fixed
- **Drag-зона тайтлбара.** Окно не двигалось, если хватать его
рядом с кнопками свернуть/закрыть. Класс `titlebar-nodrag` стоял
на обёртке кластера с `flex-1 basis-0`, поэтому пустое место
слева от иконок тоже было no-drag. Перенесли `no-drag` на сами
кнопки — теперь тащить можно отовсюду, кроме самих квадратиков.
### Changed
- **Минимальный размер окна** 900×600 → 1100×700. Гарантирует
срабатывание Tailwind `lg:` (4 hero-stat в один ряд, heatmap
и сетка упражнений помещаются без горизонтального скролла).
## [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.
[Unreleased]: https://xn--90adajar8af4h.xn--p1ai/git/AnRil/laude/compare/v0.5.3...HEAD
[0.5.3]: https://xn--90adajar8af4h.xn--p1ai/git/AnRil/laude/releases/tag/v0.5.3
[0.5.2]: https://xn--90adajar8af4h.xn--p1ai/git/AnRil/laude/releases/tag/v0.5.2
[0.5.1]: https://xn--90adajar8af4h.xn--p1ai/git/AnRil/laude/releases/tag/v0.5.1
[0.5.0]: https://xn--90adajar8af4h.xn--p1ai/git/AnRil/laude/releases/tag/v0.5.0
[0.4.0]: https://xn--90adajar8af4h.xn--p1ai/git/AnRil/laude/releases/tag/v0.4.0
[0.2.0]: https://xn--90adajar8af4h.xn--p1ai/git/AnRil/laude/releases/tag/v0.2.0