project-max — self-hosted relay for delivering messages from MAX to Telegram and a web app on React/PWA.
- backend on
Fastify; - storing messages and durable queue in
SQLite; - idempotent ingest via
POST /api/mock/messages; - realtime-stream to web via
SSE(/api/stream/messages); - React + Vite frontend with dark adaptive message feed;
- PWA shell:
manifest,service worker, installable frontend; - storing
web pushsubscriptions in the database; - Telegram worker with
retry,backoff, and startup recovery; - structured logging,
healthcheck, rootnpm test.
- real MAX adapter instead of mock ingest;
- real web push sending via
VAPIDprivate key; - production deployment on Raspberry Pi;
- final operational bindings and backup/restore runbook.
- Backend:
Node.js 24,TypeScript,Fastify - Frontend:
React 19,Vite - Storage and queue:
SQLite - Realtime:
SSE - Push shell:
PWA + service worker - Process supervision target:
systemd - Reverse proxy target:
nginx
src/backend— API, ingest, durable queue, Telegram workersrc/frontend— React/Vite client, PWA shell, push onboardingsrc/shared— общие схемы и типыtests— automated smoke/unit testsdeploy— заготовкиsystemdиnginxdocs— архитектура, аудит и handoff-заметки
- Install dependencies:
npm install-
If necessary, create a
.envbased on the.env.example. -
Run the backend:
npm run dev:backend- In a separate terminal, run the frontend:
npm run dev:frontend- Open
http://127.0.0.1:5173.
npm run typecheck
npm run build
npm test
npm run generate:vapid
npm run backup:db -- ./backups/project-max.sqlite
npm run restore:db -- ./backups/project-max.sqlite --force
npm run bridge:send -- --file ./message.json
npm run verify:prod-env -- --file ./.env.production.example --allow-placeholdersSee .env.example.
Key variables:
BACKEND_HOST,BACKEND_PORTMAX_BRIDGE_TOKENDATABASE_PATHDELIVERY_BASE_BACKOFF_MS,DELIVERY_MAX_BACKOFF_MS,DELIVERY_LOCK_TIMEOUT_MS,DELIVERY_MAX_ATTEMPTSTELEGRAM_BOT_TOKEN,TELEGRAM_CHAT_ID,TELEGRAM_API_BASE_URLTELEGRAM_WORKER_POLL_MS,TELEGRAM_BATCH_SIZEWEB_PUSH_PUBLIC_KEY,WEB_PUSH_PRIVATE_KEY,WEB_PUSH_SUBJECTLOG_LEVEL
Important:
- without
TELEGRAM_BOT_TOKENandTELEGRAM_CHAT_ID, the Telegram worker remains disabled; - without a complete set of
WEB_PUSH_PUBLIC_KEY+WEB_PUSH_PRIVATE_KEY+WEB_PUSH_SUBJECT, the push worker remains disabled; - without
WEB_PUSH_PUBLIC_KEY, the frontend will honestly show that the backend push config is not yet ready; - for real web push, you will still need HTTPS and a private VAPID key on the server side.
GET /— краткий runtime summaryGET /health— healthcheck
GET /api/messages?limit=50— последние сообщения из БДGET /api/stream/messages—SSEstream (stream.ready,message.created,message.updated)POST /api/mock/messages— local mock ingest
POST /api/bridge/max/messages— secure bridge ingest viax-bridge-token
See also docs/max-bridge-contract.md.
Example of mock ingest:
{
"source": "max-mock",
"sourceChatId": "local-dev",
"sourceMessageId": "demo-1",
"author": { "username": "@alice" },
"text": "Hello from mock ingest",
"attachments": [],
"sentAt": "2026-04-22T20:00:00.000Z",
"rawPayload": { "channel": "mock" }
}GET /api/push/configGET /api/push/subscriptionsPOST /api/push/subscriptions
- durable jobs are created for
web,telegram, andpushwhen a new message is received; - the queue is idempotent and does not create duplicate jobs;
- the Telegram worker automatically polls pending jobs;
- on error,
retry with backoffis enabled; - stale locks are restored on backend startup.
- MAX source is currently mock-only;
node:sqlitein the current Node 24 still gives anExperimentalWarning;- the frontend currently shows a single aggregated status from the
messagestable, rather than a separate status matrix for all channels; - service worker and manifest are already present, but real push notification delivery is not yet enabled without a private VAPID key and a push sender.
deploy/systemd/project-max-backend.servicedeploy/nginx/project-max.confdocs/rpi-access.md
These are templates for Raspberry Pi, not a confirmed live deployment.
docs/architecture.mddocs/max-bridge-contract.mddocs/technical-audit.mddocs/deployment-checklist.mddocs/runbook.mdPLAN.mddocs/rpi-access.md
project-max — self-hosted relay для доставки сообщений из MAX в Telegram и веб-приложение на React/PWA.
- backend на
Fastify; - хранение сообщений и durable queue в
SQLite; - idempotent ingest через
POST /api/mock/messages; - realtime-поток в веб через
SSE(/api/stream/messages); - React + Vite frontend с тёмной адаптивной лентой сообщений;
- PWA shell:
manifest,service worker, installable frontend; - хранение
web pushsubscriptions в БД; - Telegram worker с
retry,backoffи startup recovery; - structured logging,
healthcheck, rootnpm test.
- реальный MAX adapter вместо mock ingest;
- реальная отправка web push через
VAPIDprivate key; - production deployment на Raspberry Pi;
- финальная эксплуатационная обвязка и backup/restore runbook.
- Backend:
Node.js 24,TypeScript,Fastify - Frontend:
React 19,Vite - Storage and queue:
SQLite - Realtime:
SSE - Push shell:
PWA + service worker - Process supervision target:
systemd - Reverse proxy target:
nginx
src/backend— API, ingest, durable queue, Telegram workersrc/frontend— React/Vite client, PWA shell, push onboardingsrc/shared— общие схемы и типыtests— automated smoke/unit testsdeploy— заготовкиsystemdиnginxdocs— архитектура, аудит и handoff-заметки
- Установить зависимости:
npm install-
При необходимости создать
.envна основе.env.example. -
Запустить backend:
npm run dev:backend- В отдельном терминале запустить frontend:
npm run dev:frontend- Открыть
http://127.0.0.1:5173.
npm run typecheck
npm run build
npm test
npm run generate:vapid
npm run backup:db -- ./backups/project-max.sqlite
npm run restore:db -- ./backups/project-max.sqlite --force
npm run bridge:send -- --file ./message.json
npm run verify:prod-env -- --file ./.env.production.example --allow-placeholdersСмотри .env.example.
Ключевые переменные:
BACKEND_HOST,BACKEND_PORTMAX_BRIDGE_TOKENDATABASE_PATHDELIVERY_BASE_BACKOFF_MS,DELIVERY_MAX_BACKOFF_MS,DELIVERY_LOCK_TIMEOUT_MS,DELIVERY_MAX_ATTEMPTSTELEGRAM_BOT_TOKEN,TELEGRAM_CHAT_ID,TELEGRAM_API_BASE_URLTELEGRAM_WORKER_POLL_MS,TELEGRAM_BATCH_SIZEWEB_PUSH_PUBLIC_KEY,WEB_PUSH_PRIVATE_KEY,WEB_PUSH_SUBJECTLOG_LEVEL
Важно:
- без
TELEGRAM_BOT_TOKENиTELEGRAM_CHAT_IDTelegram worker остаётся выключенным; - без полного набора
WEB_PUSH_PUBLIC_KEY+WEB_PUSH_PRIVATE_KEY+WEB_PUSH_SUBJECTpush worker остаётся выключенным; - без
WEB_PUSH_PUBLIC_KEYfrontend честно покажет, что backend push config ещё не готов; - для реального web push всё равно потребуется HTTPS и private VAPID key на стороне сервера.
GET /— краткий runtime summaryGET /health— healthcheck
GET /api/messages?limit=50— последние сообщения из БДGET /api/stream/messages—SSEstream (stream.ready,message.created,message.updated)POST /api/mock/messages— локальный mock ingest
POST /api/bridge/max/messages— защищённый bridge ingest черезx-bridge-token
Смотри также docs/max-bridge-contract.md.
Пример mock ingest:
{
"source": "max-mock",
"sourceChatId": "local-dev",
"sourceMessageId": "demo-1",
"author": { "username": "@alice" },
"text": "Hello from mock ingest",
"attachments": [],
"sentAt": "2026-04-22T20:00:00.000Z",
"rawPayload": { "channel": "mock" }
}GET /api/push/configGET /api/push/subscriptionsPOST /api/push/subscriptions
- при новом сообщении создаются durable jobs для
web,telegram,push; - queue идемпотентна и не плодит дубликаты;
- Telegram worker автоматически опрашивает pending jobs;
- при ошибке включается
retry with backoff; - stale locks восстанавливаются на старте backend.
- источник MAX пока mock-only;
node:sqliteв текущем Node 24 всё ещё даётExperimentalWarning;- frontend пока показывает один агрегированный статус из таблицы
messages, а не отдельную матрицу статусов по всем каналам; - service worker и manifest уже есть, но реальная доставка push-уведомлений ещё не подключена без private VAPID key и отправителя push.
deploy/systemd/project-max-backend.servicedeploy/nginx/project-max.confdocs/rpi-access.md
Это шаблоны для Raspberry Pi, а не подтверждённый live deployment.
docs/architecture.mddocs/max-bridge-contract.mddocs/technical-audit.mddocs/deployment-checklist.mddocs/runbook.mdPLAN.mddocs/rpi-access.md