Створюючи Quint Project, ми керувалися двома принципами: абсолютна автономність для користувача та максимальна простота розгортання. Щоб досягти цього, ми об'єднали філософію Local-first із сучасним, але легким технічним стеком.
У цій статті ми заглянемо під капот системи та розберемо її архітектуру, логіку синхронізації та інженерні рішення.
1. Загальна архітектура: все в одному бінарнику
Проєкт чітко розділений на backend та frontend. Проте під час
фінальної збірки вони компілюються в
один єдиний автономний бінарний файл на Go.
Екосистема Golang дозволяє повністю "вшити" (embed) всі
статичні файли інтерфейсу (HTML, CSS, JS) всередину виконуваного
файлу.
Для кінцевого користувача це означає тривіальне оновлення та розгортання: один файл керує і логікою, і базою, і інтерфейсом.
2. Frontend: Ванільний JavaScript та клієнтська автономія
Інтерфейс Quint Project побудований без громіздких сучасних фреймворків. Наш стек: HTML, Vanilla JavaScript, Tailwind CSS та Vite. Node.js використовується виключно на етапі розробки та збірки через Vite — у продакшн йде чистий, легкий та автономний код.
Для розширеного функціоналу використовуються лише точкові бібліотеки:
-
marked+marked-katex-extension— для швидкого рендерингу Markdown та математичних символів. -
dompurify— для безпечної роботи з DOM та захисту даних. -
jszip+file-saver— для генерації ZIP-архівів під час експорту нотаток.
Де зберігаються дані? Усі нотатки та теки спочатку потрапляють у локальну базу даних браузера — IndexedDB. Пошук, додавання та редагування відбуваються миттєво на пристрої клієнта. Завдяки підтримці PWA (Progressive Web App) застосунок можна встановити на десктоп або телефон, і він повноцінно працюватиме взагалі без доступу до інтернету.
3. Backend: Потужність Go та вибір SQLite
Серверна...). частина написана на Go (1.25.0+) із використанням фреймворку Gin та бази даних SQLite.
Чому саме SQLite?
Проєкт розрахований на індивідуальних користувачів та невеликих
команд. Нам було потрібне рішення з нульовими операційними витратами
на обслуговування. SQLite зберігає всю базу в одному файлі, що робить
процес резервного копіювання (бекапу) та перенесення даних
елементарним.
Попри міфи про обмеженість SQLite, у нашій архітектурі вона демонструє високу продуктивність:
- Нульова затримка (Zero Latency): Оскільки архітектура є Local-first, користувач взаємодіє з локальною IndexedDB із субмілісекундним відгуком. Сервер не є перешкодою для інтерфейсу.
- Фонова обробка: Серверний інстанс SQLite працює як координаційний хаб для обміну дельтами даних (push/pull). Він легко обслуговує понад 100 одночасних користувачів.
- Режим WAL (Write-Ahead Logging): Ми ввімкнули режим WAL, що дозволяє базі даних паралельно обробляти пакети синхронізації (записи) від кількох користувачів, не блокуючи при цьому операції читання.
4. Фонова синхронізація без затримок
Синхронізація клієнта із сервером є повністю асинхронною. Коли ви створюєте або змінюєте нотатку, додаток зберігає її локально (відгук миттєвий) і через короткі проміжки часу у фоновому режимі відправляє дельти на сервер. Якщо інтернет зник — дані накопичуються на пристрої та відправляться автоматично при відновленні мережі.
Оновлення з сервера приходять на клієнт у двох випадках: коли змінюється фокус вікна (користувач повернувся до застосунку) або коли пристрій переходить з офлайн-режиму в онлайн.
5. Обмеження для команд
Наразі на одному інстансі встановлено ліміт — до 10 користувачів. Це свідоме архітектурне обмеження, покликане запобігти конфліктам під час одночасного спільного редагування одних і тих самих файлів.
Якщо ваша організація є більшою, ви можете легко розділити її на підкоманди до 10 людей і запустити для кожної свій ізольований інстанс.
6. Ресурсомісткість та розгортання
Завдяки вибору Go та SQLite, Quint Project неймовірно невибагливий до заліза. У тестових режимах один Docker-інстанс споживає до 20 MB оперативної пам'яті. Ви можете хостити його на найдешевшому VPS.
Розгортання відбувається через Docker Compose всього за кілька кроків:
-
1. Скопіюйте шаблон
docker-compose.ymlз нашого файлу README - 2. Налаштуйте власні конфігураційні параметри (порти, змінні оточення).
- 3. Запустіть проєкт командою:
docker compose up -d
(Для ентузіастів також залишається можливість збірки проєкту безпосередньо з вихідного коду).