docs(v0.5.2): update CHANGELOG + README badge
This commit is contained in:
86
CHANGELOG.md
86
CHANGELOG.md
@@ -6,10 +6,92 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.5.2] — 2026-05-19
|
||||
|
||||
Большая внутренняя итерация: тройной независимый аудит (~220 находок),
|
||||
закрыты топ-приоритеты. Тестов 53, ESLint и Prettier чистые, typecheck OK.
|
||||
|
||||
### Added
|
||||
|
||||
- Prettier + ESLint конфиги, скрипты `npm run format` / `npm run lint`.
|
||||
- `.editorconfig` для единообразного оформления между редакторами.
|
||||
- **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
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Windows desktop приложение, которое напоминает делать упражнения во время работы за компьютером. Опционально подключается к Dota 2 и после каждого матча превращает статистику (смерти, убийства, ассисты) в количество повторений.
|
||||
|
||||
[](https://xn--90adajar8af4h.xn--p1ai/git/AnRil/laude/releases/latest)
|
||||
[](https://xn--90adajar8af4h.xn--p1ai/git/AnRil/laude/releases/latest)
|
||||
[]()
|
||||
[]()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user