Персональный менеджер задач для повседневных дел и личных проектов.
| Версия ТЗ | 0.45 |
| Дата | 2026-09-23 |
| Статус | На обсуждении |
Продвинутый личный таск-менеджер. Ключевая идея — минимальный трением ввод: задача закидывается в систему в одну строку, без выбора проекта, тегов и приоритета. Система сама делает предварительную детализацию, а пользователь позже утверждает или правит её при разборе.
user_id — один пользователь не видит чужого.user_id = NULL (наследие однопользовательской версии) и глобальные настройки забираются первым вошедшим пользователем.Сценарий А — веб-интерфейс (основной). Разбор стека входящих, детализация и утверждение задач, работа с проектами, планирование, просмотр дерева задач.
Сценарий Б — ИИ-агент через MCP. Агент от имени пользователя добавляет задачи (например, из переписки или диалога с LLM). Большинство AI-задач выполняется на стороне агента; сервер предоставляет MCP-интерфейс к данным.
raw) и ожидают детализации.При попадании задачи в стек система самостоятельно предлагает черновые метаданные (0.40: только оформление задачи, без планирования):
Планирование ИИ не делает (решение 2026-09-22, «0% попадания»): проект, приоритет и оценку длительности LLM не предлагает — их заполняет пользователь.
Требования:
approved) только после явного действия пользователя.- [ ] / - [x]) в отображаемом описании кликабельны: клик переключает пункт и сохраняет статус в markdown описания.README.md из репозитория (с подписью-ссылкой на источник). Хост не обязан быть GitHub/GitLab — селф-хостед системы ищутся эвристикой (API github/gitlab/gitea + raw-пути web-интерфейсов, дефолтная ветка HEAD); не нашли — остаётся ссылка. Сырой текст в БД не меняется; кэш прочтённого README — 10 минут. Пользователю подсказывается об опции: в форме создания задачи (подпись редактора) и в пустом описании/инлайн-правке на странице задачи.target="_blank", rel="noopener") — PWA не ловит навигацию в своё окно.Тип задачи: каждая задача имеет тип — разовая или регулярная (повторяющаяся; см. 3.5).
Статусы выполнения:
| Статус | Смысл |
|---|---|
to_do — К выполнению |
Принята в работу, ожидает выполнения |
in_progress — В работе |
Выполняется сейчас |
done — Завершено (закрыто) |
Выполнена |
cancelled — Отменено |
Была актуальной, затем перестала быть актуальной. Не равно удалению — задача сохраняется, т.к. может снова стать актуальной |
deferred — Отложено |
На текущий момент не нужна или не в приоритете; возможно, позже это изменится |
cancelled и deferred — обратимы: задача может быть возвращена в to_do.raw → approved) — отдельная плоскость, не статус выполнения: «сырая» задача из стека получает статус только после утверждения.Дедлайны — двух видов:
Прогнозирование времени выполнения — система оценивает длительность задачи (на основе истории завершённых задач; алгоритм уточняется).
Бюджет — опциональный, на задачу; есть не у каждой задачи:
parent_task_id) в модели данных сохраняется.Проект, с которым пользователь закончил работу, отправляется в архив — один архив на все проекты, отдельных архивов задач нет.
Анти-прокрастинационный режим: пользователь указывает доступное время в часах (например, «3», можно 0.5), система предлагает подходящие задачи; предложение — те же карточки, что в списке задач.
?via=options) и берёт её в работу на странице задачи; закрытие задачи, открытой из выдачи, помечается «выбрал и сделал».create_task — добавить задачу (достаточно текста; метаданные опциональны);update_task, complete_task;list_tasks — фильтры по проекту (id или имени), тегу, статусу, подстроке;get_task — полное описание с вложениями;list_projects / get_project — обнаружение проектов и восстановление контекста проекта (заметка проекта + его открытые задачи);create_project — новый проект (имя, опционально заметка и приоритет); дубликат имени отклоняется с подсказкой; заметка уходит в фоновую суммаризацию; микронаграда как при создании из UI;update_project — переименование, заметка, relevance_status (active/paused), приоритет; адресация по id или имени;archive_project / restore_project — архив вместо удаления (0.45): проект прячется вместе с задачами из активных (история сохраняется), restore возвращает; вызовы идемпотентны; архивные проекты видны через list_projects(include_archived=True). Безвозвратного удаления проектов в MCP нет намеренно;list_tags — справочник тегов (id для параметра tag_ids).instructions: порядок работы, правило привязки задач к проекту, восстановление контекста через get_project после перерыва, запрет придумывать id, автоматика наград/спавна при закрытии;project_name (регистронезависимо) в тудах задач (create_task/update_task/list_tasks) и в тудах управления проектами (update_project/archive_project/ restore_project) наряду с project_id;create_task без проекта содержит подсказку.gnt_..., показывается один раз при создании; в БД только sha256-хэш). Там же ссылка на страницу-инструкцию по MCP (/mcp-help): что реализует, адрес сервера (совпадает с адресом приложения), токен, примеры подключения (Claude Code, универсальный JSON).MCP_TOKEN удалена — старые конфиги агентов получат 401, пока владелец не создаст токен в «Настройках». С 0.42 Bearer-токен принимается и на REST /api/* — им ходит браузерное расширение (3.18).update_task/complete_task) идёт по тому же общему пути, что и в UI: спавн регулярной, XP, монеты, растение (3.5, 3.13); в открытых вкладках — скромный тост о награде (3.14).projects.summary — краткое резюме заметки (суть + полезные признаки для классификации задач). Суммаризация генерируется той же LLM фоном при создании проекта с заметкой и при правке заметки (кэш в БД); без суммаризации в контекст идёт обрезка заметки.profile.locale из SSO-профиля, scope profile).app_settings, ключ language), пустое значение = следовать SSO.Маленькая дополнительная награда за выполнение задач — мотивация без негативных последствий. Принцип только позитив: XP только начисляется, ничего не сгорает и не отнимается; стрики/серии (которые «ломаются» при пропуске) не используются.
xp_events (поле kind разделяет события: task — закрытие, create_task / create_project — создание).task_id = NULL — удаление задачи или проекта награду не отнимает.POST /api/xp/daily — раз в сутки (граница дня UTC) начисляется 50 монет (только монеты, XP нет), повторные визиты в те же сутки молча пропускаются. Тост «+50 монет» только в день первого визита.nearest масштабирование без сглаживания, целочисленный «нативный пиксель» (матрицы 16px × 2 = 32px на клетку). Все спрайты (тайлы травы/дикой земли, изгородь, домик, 13 видов растений × 3 стадии, декорации, кольца редкости, блёстки) генерируются из пиксель-матриц прямо в коде — внешних файлов-ассетов нет. Рендерер (src/game/GardenRenderer.ts) — обычный класс, не оборачивается во Vue-reactive (deep-прокси ломает внутренние identity-проверки Pixi); Pixi загружается динамическим импортом (отдельный чанк). Инвентарь, поповер и drag-ghost — DOM поверх канваса.floor(xp / 2) (заголовок X-Earned-Coins рядом с XP в тосте), и бонусом 25 × L при достижении уровня L. Хранение — таблица coin_events (журнал заработка и трат; баланс = сумма amount). Траты — отрицательные события (source = shop); продажи нет («только позитив»).xp_events, визуально — золото + бейдж.garden_items.item_key) — открытые позже виды не перерисовывают старые растения. Растение привязано к событию XP (переживает удаление задачи).garden_items.x/y = NULL) — место покупки всегда видно пользователю. Из инвентаря декорация перетаскивается на карту; перетаскивание размещённой декорации обратно на полосу инвентаря убирает её с карты (растения в инвентарь вернуть нельзя — сад только растёт).earned_via) и празднуется меткой «выбрал и сделал» + счётчик-ачивкой; XP при этом не меняется.xp_events и дат задач, без новых эндпоинтов.Данные меняются не только из UI: MCP-агенты (3.10) и фоновая автодетализация (3.2) пишут в БД вне HTTP-запроса. Все виды обновляются событиями от сервера — без обновления страницы и переходов между страницами.
GET /api/events (авторизация штатная, 401 — на вход). Транспорт — SSE (text/event-stream), по одному соединению на вкладку (EventSource, авто-reconnect браузером). Keep-alive: при тишине дольше 20 с сервер шлёт кадр ping, чтобы прокси (Vite dev, nginx) не рвал поток.kind + опциональные данные; фронт реагирует refetch'ем (перечитывает данные целиком), а не патчами. Трейлинг-debounce 300 мс коалесцирует бёрсты (закрытие задачи = 2–3 события). Виды подписываются на свои kind'ы: стек/список — task.changed, task.deleted, detail.changed, project.changed, project.deleted; статистика — xp.changed, task.changed; сад — garden.changed, xp.changed, task.changed (рефetch подавляется на время drag по сцене); страница задачи — перечитывается при task.changed/detail.changed своего id.task.changed {id}, task.deleted {id}, detail.changed {id}, project.changed {id}, project.deleted {id}, garden.changed {reason}, xp.changed {amount?, celebrate}, settings.changed, ready (первый кадр), ping. Упрощение: закрытие задачи через MCP не шлёт garden.changed — растение создаётся лениво, refetch по task.changed покрывает.X-Earned-XP, ТЗ 3.13); SSE-эхо и эхо соседней вкладки молчат — окно активности 3 с (localStorage). Соседние вкладки показывают скромный тост «+N XP» без конфетти.Приложение устанавливается на устройство как приложение (Chrome/Android; вопрос оффлайн-режима данных — открытый вопрос 8.4, пока приложение всегда онлайн).
#16161e — фон и theme-color, чтобы не мигало белым при запуске и не зеленела шапка окна), иконки 192/512 + maskable-512, id/start_url = /, язык ru.autoUpdate): precache оболочки — собранные ассеты, шрифты/иконки кита (~6 МБ лимит), /api/*, /auth/*, /mcp/* никогда не кэшируются и не получают fallback на index.html.autoUpdate); SSE-соединение при обновлении рвётся — reconnect покрывает (3.14).devOptions выключен) — PWA проверяется на прод-сборке (dist), не на dev-сервере.POST /auth/webhook (контракт — docs/04-events-and-webhooks.md в репозитории gnexus-auth): HMAC-SHA256 заголовков X-GNexus-*, секрет — GAUTH_WEBHOOK_SECRET (создаётся/ротируется в админке SSO, client.webhook/rotate-secret); секрет не задан — приём выключен (503).user.email_changed, user.profile_updated — синхронизация профиля User (email, name ← profile.display_name, locale, avatar_url) без повторного логина; ключа нет в profile — поле не менялось, не трогаем;user.blocked, user.archived, user.deleted — отзыв всех MCP-токенов пользователя (агент теряет доступ вместе с аккаунтом)./auth/me отдаёт свежие данные из БД, а не из cookie-сессии, поэтому изменения профиля от webhook видны сразу (без повторного логина).webhook.test и будущие) подтверждаются 200 без действий — чтобы SSO не гонял retry'и по незнакомому типу; при недействительной подписи/битом payload — 400./login вне навигационной оболочки: логотип, название и единственная кнопка «Войти» — инициация SSO-флоу (/auth/login с return_to)./auth/me → 401); после логина возвращается на исходный адрес. Истёкшая сессия в API/SSE-коде тоже ведёт на /login, а не на бэкендовый SSO-флоу./auth/logout после очистки сессии редиректит на /login (не оставляет пользователя на JSON-ответе)./auth/me не считается «не залогинен» — оффлайн-оболочка открывается без редиректа.Расширение для Chrome/Firefox (MV3): клик по иконке в трее браузера → попап с двумя вкладками — «Добавить» и «В работе». Быстрый захват входящих (3.1) вне страницы сервиса.
/api/tasks + PATCH project_id, как в веб-форме). Фидбек — анимация-галочка и тост «Задача добавлена (+N XP)»; поле очищается, выбранный проект сохраняется; кнопка «Открыть GNexus Tasks» ведёт на главную.in_progress; название, чип проекта, метка просрочки, теги); клик открывает задачу в сервисе, действий в попапе нет./api/* с Authorization: Bearer <MCP-токен>. Токен вставляется один раз из «Настроек → Токены MCP», хранится в chrome.storage.local; отзыв токена отключает расширение (как и агентов, 3.10).http://localhost:15134; произвольный адрес задаётся в настройках попапа и запрашивает host-разрешение (optional_host_permissions + chrome.permissions.request)./extension): скачивание ZIP-сборки расширения (раздаётся статикой фронта; в Docker-образе фронта собирается из extension/), шаги загрузки unpacked и подключения токена. Из установленного PWA пункт меню скрыт (display-mode: standalone) — по прямому адресу страница показывает пояснение.| Требование | Значение |
|---|---|
| Архитектура | Клиент-серверное; SPA + REST API + MCP |
| Фронтенд | SPA на Vue 3 с gnexus-ui-kit (npm: gnexus-ui-kit@^0.4.0, peer: Vue ^3.4) |
| Бэкенд | Python (FastAPI — предположительно), клиент SSO — gnexus-gauth |
| СУБД | PostgreSQL (рекомендация для VPS) |
| Авторизация | SSO через auth.gnexus.space, библиотека gnexus-gauth (https://git.gnexus.space/git/root/gnexus-auth-client-py.git) |
| Хостинг | VPS, HTTPS |
| AI | Ollama на внешнем сервере (адрес и модель — конфигом, OLLAMA_BASE_URL/OLLAMA_MODEL); контейнера ollama в compose нет |
| Упаковка | В итоге всё пакуется в Docker (docker-compose: API, PostgreSQL, фронт; TLS — внешний reverse-proxy) |
| Мобильность | На старте — только PWA; Android-приложение — вне скоупа стартовой версии (вернуться к нему позже) |
| Приватность | Все данные и LLM-вызовы — на собственном сервере |
| Реактивность | SSE (/api/events): грубозернистые события + refetch, см. 3.14 |
| PWA | манифест + SW (precache оболочки, autoUpdate), оффлайн-оболочка без кэша API, см. 3.15 |
Внешние зависимости проекта (не форкать, обновлять через пакетный менеджер):
gnexus-ui-kit — часто обновляется, использовать только публичный API кита;gnexus-gauth — клиентская библиотека SSO.Мультиюзерность (с 0.34): на задачах, проектах, тегах, документах, XP/монетах, саде и настройках есть user_id (nullable — NULL забирается первым вошедшим, см. 1.2); все запросы API/сервисов/MCP-тулов скоупятся по нему.
User — пользователь SSO: id (= user_id от SSO), email, name (display_name),
avatar_url, locale, created_at
McpToken — персональный MCP-токен (3.10): user_id, token_hash (sha256,
уникален), label, created_at; plaintext показывается один раз
Task
id, title
description markdown — живёт в Document (owner_type = task)
task_type one_time | recurring — тип задачи: разовая / регулярная
status to_do | in_progress | done | cancelled | deferred
detail_state raw | approved — плоскость детализации (стека)
parent_task_id nullable — дерево подзадач
project_id nullable
tag_ids []
priority nullable (заполняется автодетализацией / вручную)
deadline nullable — дедлайн:
strict { date } — «до конкретной даты»
soft { period: week|month|year } — «в течение периода»
recurrence nullable — правило повторения (для task_type = recurring)
time_estimate nullable — прогноз времени (система)
budget nullable — ручной бюджет (деньги и/или время), опционален
estimated_cost nullable — оценка затрат по задаче (сравнивается с бюджетом)
actual_time nullable — фактические затраты (для обучения прогноза)
created_at, approved_at, done_at
Project
id, name
relevance_status active | paused — статус актуальности
is_archived bool — архив (3.8.1): проект и его задачи скрыты
из рабочих видов, восстановимы из «Архива»
priority
note markdown — живёт в Document (owner_type = project):
ссылки, контекст, картинки
Tag — справочник тегов
Document — markdown-текст с полиморфной привязкой к владельцу:
owner_type (task | project), owner_id, body (у задачи —
описание, у проекта — заметка); document всегда один на владельца
Attachment — файлы документов (изображения), document_id, mime.
URL скачивания файла неизменен: /api/attachments/{id}/file —
он зашит в сохранённый markdown-текст
XpEvent — начисление XP за закрытую задачу (идемпотентно по task_id):
amount, rarity (common | rare | epic), via_options
CoinEvent — журнал монет сада (заработок и траты; баланс = Σ amount):
task_id (nullable), level (nullable — бонус уровня),
source (task | level | shop), amount (+/−), item_key (ключ
покупки для трат), created_at
GardenItem — элемент сцены сада: kind (plant | decoration),
ref_id (→ xp_events для растений; уникально в паре с kind),
item_key (вид растения / ключ декорации), x, y (ячейки сетки),
stage (0 росток, 1 куст, 2 цветение)
AppSetting — per-user настройки (валюта, язык): PK (user_id, key), value
AppSettingGlobal — таблица-наследие однопользовательской версии
(бывшая app_settings); источник claim при первом логине,
позже удаляется
История завершённых задач (фактическое время) — источник для прогнозирования длительности.
┌─────────────┐ ┌────────────────────── VPS (docker-compose) ─────────────┐
│ Web SPA │────▶│ API (FastAPI) ──▶ PostgreSQL │
│ Vue 3 + │ │ ▲ │ │
│ gnexus- │ │ │ ├──▶ Сервис автодетализации ──▶ Ollama (модель │
│ ui-kit │ │ │ │ — LLM, модель из конфига) │
└─────────────┘ │ │ ├──▶ Хранилище вложений (файлы) │
▲ │ │ └──▶ MCP-сервер (для ИИ-агентов) │
└─ SSE ───────┤ шина событий (realtime) │
└─────────────────────────────────────────────────────────┘
▲ SSO auth.gnexus.space (клиент gnexus-gauth)
| Этап | Содержание |
|---|---|
| M0 — каркас | Репозиторий, скелет backend + frontend, SSO-интеграция (gnexus-gauth), деплой на VPS |
| M1 — MVP задач | CRUD задач, быстрый ввод, стек входящих, теги, проекты (базово), ручная детализация |
| M2 — детализация | Интеграция Ollama + модель из конфига, автопредзаполнение метаданных, подтверждение/редактирование, Markdown-редактор, вложения из буфера |
| M3 — структура | Подзадачи (parent_task_id), классический список с фильтрами, заметки проектов |
| M4 — умность | Прогнозирование времени, бюджет, выдача задачи |
| M5 — MCP | MCP-сервер, инструменты для агентов |
| M6 — мобильность | PWA (Android-приложение — позже, вне стартового скоупа) |
| M7 — упаковка | Docker (docker-compose: API, PostgreSQL, фронт, Ollama + модель) |
Порядок M4/M5 может меняться — MCP можно поднять раньше ради ИИ-сценария.
qwen3.5:2b-q4_K_M (проверена на M2); меняется конфигом (OLLAMA_MODEL) без правок кода. Ollama — внешний сервер, адрес — OLLAMA_BASE_URL.cancelled / deferred: определения зафиксированы (3.4), но поведение в интерфейсе почти одинаковое — скрыть из активных списков и оставить доступным для возврата. Уточнить при проектировании представлений, нужны ли оба статуса или их поведение сольётся.spawned_at), выход из done сбрасывает done_at. Повторные закрытия и обновления закрытой не дублируют награды и экземпляры — покрыто тестами.