diff --git a/CLAUDE.md b/CLAUDE.md index f981c3b..2959263 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -91,6 +91,8 @@ ESM-пакет, Node 22+. SDK — `@modelcontextprotocol/sdk` (`McpServer` + `St **Эндпоинты, возвращающие `UpdateTaskResponse`.** `PATCH /tasks/:id` и `PATCH /tasks/:id/pomodoro` отдают не задачу, а обёртку `{ task, nextInstance?, deletedInstanceId? }` — из-за повторяющихся задач, где завершение порождает следующий инстанс. Потребители должны читать `body.task`, а не `body`. На фронте разбор один — `applyUpdateResponse` в `features/tasks/model/task-store.ts`. +**`Task.isOverdue` — это «заморожена», а не «просрочена по дате».** Флаг ставит ночная джоба только повторяющимся задачам с `onMissed: 'freeze'`: инстанс помечается `isOverdue=true`, теряет `recurrence` и становится **иммутабельным** — `task.service.ts` кидает `BadRequestException` на любой PATCH, доступно только удаление. Обычная разовая задача со вчерашним `dueDate` имеет `isOverdue=false` и спокойно редактируется. Поэтому «просроченные» в UI-смысле — это `!completed && dueDate < начало сегодня`, и вычислять их через `isOverdue` нельзя. Единственный источник этого предиката на фронте — `features/tasks/lib/today.ts` (`splitTodayBuckets`), см. `docs/tasks/overdue-recurring-tasks.md`. + # Frontend architecture (FSD-like) `alfy-bot-frontend/src/` устроен как feature-sliced: @@ -109,7 +111,9 @@ ESM-пакет, Node 22+. SDK — `@modelcontextprotocol/sdk` (`McpServer` + `St Авторизация: при старте `main.ts` пробует `authorize()` если есть `Telegram.WebApp.initData` или dev-флаг `VITE_DEV_TELEGRAM_ID`. Router guard в `router/index.ts` редиректит на `/login` любой не-public маршрут при отсутствии токена. Public-маршруты помечены `meta: { public: true }`. -**Секционный блок сайдбара — один компонент на секцию.** `sectionExtraRegistry` в `components/AppLayout.vue` отображает `meta.sectionNav` в **ровно один** компонент (`tasks` → `TasksSidebarSection.vue`). Чтобы добавить в сайдбар ещё один блок, композиция делается внутри секционного компонента, а не расширением реестра до массива. `AppSidebar.vue` рендерит слот `section-extra` **дважды** — в десктопном `