V.O.I.D. — Visual Overview of Income & Debt
Живое приложение: artwem.github.io/void
Личный финансовый трекер-PWA. Расходы по категориям с лимитами, доходы, активы, вклады, инвестиции, годовой отчёт. Ванильный JS без фреймворков и сборки. Данные хранятся локально на устройстве, по желанию синхронизируются с Google Drive.
Возможности
Бюджет
- Категории расходов с месячными лимитами и прогресс-барами
- Группировка категорий по цвету — одинаковый цвет = одна группа с суммарной статистикой
- ⌀-подсказки в редакторе лимитов: среднее за 3/6/12 месяцев, «подставить все» одной кнопкой
- Особые расходы — помечаются отдельно, исключаются из графика «День за днём»
- Быстрое добавление расхода по тапу на категорию, навигация по месяцам
- Суммы с копейками: вводятся как «12,50», хранятся и печатаются до копейки, круглые суммы — без хвоста
День
- Список расходов за день, редактирование, свайп-удаление с отменой
- Шаблоны трат — цветные кнопки быстрого добавления частых расходов
- Несколько расходов в одну категорию группируются с итогом
Доходы
- Источники дохода по месяцам, баланс «доходы − расходы»
- Теги доходов с цветами и фильтром (зарплата, продажи, проценты…)
Аналитика
- Расходы по месяцам, структура месяца, доходы vs расходы, stacked-графики по группам
- «День за днём» — дневные траты со средней линией за 3/6/12 месяцев
- Годовой отчёт: сводные карточки, помесячная таблица, расходы по категориям, доходы по тегам, дельты к прошлому году
Активы
- Банковские счета и кредитки (кредиты вычитаются из итога), снимки на дату, задним числом
- «Всего активов» = счета + вклады + инвестиции, с расшифровкой
- График роста с тумблером «банки / +вклады·инвест», история с колонками и правкой по дате
Вклады
- Ставка или «сумма в конце» (ставка выводится автоматически), капитализация ежемесячно / проценты в конце
- Пополнения со списанием из банка, график начислений с ручными правками по факту
- Закрытие с переносом в банк, проценты — в доходы с выбором тега
- Прогноз «сколько будет к дате»
Инвестиции (брокер / ИИС)
- Ручные снимки стоимости счёта + журнал пополнений и выводов
- Прибыль ₽ и % (стоимость − вложено), годовая доходность (XIRR) по счёту и портфелю, напоминание при устаревшем снимке
- Пополнение/вывод со списанием/зачислением в банк — сверка периодов сходится
Калькулятор
- Рост накоплений с процентами и ежемесячным пополнением, таблицы по годам и месяцам
Настройки и сервис
- Управление категориями, банками, тегами; тёмная тема; приватный режим (суммы блюрятся)
- Синхронизация с Google Drive, резервная копия/восстановление JSON, экспорт Excel
- Push-уведомления: порог лимита, напоминание о снимке активов, закрытие вклада
- Проверка данных: дубли и «призраки» записей, сверка «изменение активов vs доходы − расходы» по периодам
Установка PWA
PWA устанавливается прямо из браузера — App Store не нужен.
iPhone / iPad (Safari)
- Открой приложение в Safari
- Кнопка Поделиться (квадрат со стрелкой вверх)
- «На экран „Домой"» → Добавить
Android (Chrome)
- Открой в Chrome
- ⋮ → «Добавить на главный экран» → Добавить
Компьютер (Chrome / Edge)
- Иконка установки справа в адресной строке → Установить
Telegram Mini App
Весь V.O.I.D. можно открыть внутри Telegram как личный Main Mini App:
- Создай бота через @BotFather.
- Открой Bot Settings → Configure Mini App → Enable Mini App.
- Укажи URL
https://artwem.github.io/void/ и открой Mini App через бота.
Telegram WebView использует отдельное хранилище localStorage: данные из браузерной PWA там автоматически не появятся. Для общих данных повторно введи тот же Apps Script URL и токен синхронизации в настройках Mini App.
Токен бота для запуска Main Mini App в коде не нужен — не помещай его в проект.
Синхронизация с Google Drive
Необязательна — приложение полностью работает офлайн. Данные лежат в файле nto_data.json на твоём Google Drive, без таблиц.
Шаг 1 — Создать Apps Script
- Открой script.google.com
- Создай новый проект, удали код в редакторе
- В приложении: Настройки → Скопировать Apps Script, вставь код → 💾 Сохранить
Шаг 2 — Задеплоить
- Развернуть → Новое развёртывание, тип Веб-приложение
- Выполнять как: Я; доступ: Все (именно «Все», не «Все с аккаунтом Google»)
- Развернуть, подтверди доступ («Дополнительно» → «Перейти»)
- Скопируй URL веб-приложения
Шаг 3 — Подключить в приложении
- Настройки → URL веб-приложения → вставь URL → Сохранить
- ⚡ Проверить подключение → «✓ Подключено»
После подключения:
- Автосинхронизация каждые 15 секунд при изменениях (pull → merge → push, конфликты решаются по времени правки)
- Удаления переносятся между устройствами (tombstones), защита от случайной перезаписи пустыми данными
- Вручную: Загрузить из Drive / Сохранить в Drive
- Суточные копии на Drive (семь последних) с восстановлением из приложения; строка «С других устройств» показывает, что пришло при слиянии
- Ярлыки:
…/void/?add=350&cat=Продукты&comment=кофе открывает заполненную форму траты (iOS Shortcuts, виджеты), ?tab=assets — вкладку
Секретный токен (опционально)
Чтобы URL скрипта нельзя было использовать без ключа: задай значение константы SECRET в начале Code.gs, передеплой, и введи ту же строку в приложении — Настройки → поле токена в блоке синхронизации. Токен хранится только на устройстве.
Что хранится на Drive
| Файл | Описание |
|---|
nto_data.json | Основной файл синхронизации |
nto_data.bak.YYYY-MM-DD.json | Суточные копии, хранятся семь последних (Code.gs ≥ 10.5) |
Обновление скрипта
- Настройки → Скопировать Apps Script, вставь в редактор → Сохранить
- Развернуть → Управление развёртываниями → ✏️ → Новая версия → Развернуть
Структура проекта
void/
├── index.html ← ЕДИНСТВЕННЫЙ источник: HTML + весь JS инлайном
├── css/app.css ← Стили (подключается напрямую, при правке бампать ?v=)
├── sw.js ← Service worker; const V бампается при каждом деплое
├── manifest.json ← PWA-манифест
├── apps-script/Code.gs ← Google Apps Script для синка
└── docs/ ← Спеки и планы фич
⚠️ Весь JS живёт в index.html — секции помечены маркерами // ═══ db.js ═══, // ═══ assets.js ═══ и т.п. Отдельных JS-файлов и шага сборки нет.
Локальная разработка
Без сборки:
python3 -m http.server 8080
# http://localhost:8080
Быстрая проверка синтаксиса инлайн-скриптов:
node -e "const html=require('fs').readFileSync('index.html','utf8');const re=/<script(?![^>]*src)[^>]*>([\s\S]*?)<\/script>/g;let m,ok=true;while((m=re.exec(html))){try{new Function(m[1])}catch(e){ok=false;console.log('FAIL:',e.message)}};console.log(ok?'syntax OK':'ERRORS')"
Деплой на GitHub Pages
- Бампни версию в About (
index.html) и const V в sw.js — это сбрасывает кеш PWA на iOS
- Пуш в
main — Pages собирается автоматически