Crimson.Lab

Лаборатория Кримсона

26 August 2026

Дневник питания - оффлайн и без сервера

logo

Врач попросил вести дневник питания - время и что съел. Все готовые приложения хотят регистрацию, подписку, и именно времени приёма пищи - нет у многих. Написал своё: eat.x-crm.in - открыл, записал, закрыл. Бесплатно, с синхронизацией через гугл аккаунт.

Что умеет

Без сервера - это как?

Буквально: бэкенда нет. Статика лежит на GitHub Pages, а синхронизация ходит из браузера напрямую в Google Drive API - в скрытую папку приложения (appDataFolder), которую не видно среди файлов Диска и до которой другие приложения не дотянутся.

Авторизация - Google Identity Services, token flow: никакого client_secret, никакого промежуточного сервера, который читает ваши данные. Access token живёт около часа и продлевается только по клику - при запуске приложение не открывает никаких окон и вообще не ходит в сеть.

Источник истины - локальная база. Облако лишь реплика: слияние по правилу last-write-wins на каждую запись, удаления разносятся tombstone-ами и вычищаются через 30 дней. Одновременная правка на двух устройствах не превращается в кашу - побеждает более поздняя версия.

Приватность

Данные хранятся ровно в двух местах: в вашем браузере и (если включили синхронизацию) в скрытой папке вашего Google Диска. Промежуточных серверов нет, аналитики нет, cookies нет. Отозвать доступ можно в настройках Google-аккаунта - приложение при этом продолжит работать локально.

Не залогинившись, получаете то же самое минус синхронизация - для дневника «на неделю для врача» и этого хватает.

Под капотом

React 19 + TypeScript + Vite, vite-plugin-pwa (Workbox), IndexedDB через idb. Логика слияния - чистые функции, покрытые тестами через node --test без Jest. Деплой - GitHub Actions на поддомен, public/CNAME в артефакте.

Исходники открыты: github.com/william-aqn/eat. Форкается в свой вариант за вечер: словарь нового языка - один файл, замена облака - один адаптер (RemoteStore), палитра - CSS-переменные в :root.

Ссылки

tags: pwa - react - indexeddb - google-drive - local-first