Skip to content

About

Копия бэкенда ИТД на elysia js (вайбкод)

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

itd-backend

Backend-клон социальной сети ИТД (итд.com). Эндпоинты, модели ответов и формат ошибок повторяют контракт, который ожидает itd-sdk (и официальный веб-клиент), поэтому SDK работает с этим сервером без изменений — достаточно указать ITDConfig(url='http://localhost:3000/api').

Стек: Bun · ElysiaJS (TypeScript) · TypeBox · PostgreSQL + Drizzle ORM · Redis (ioredis) · Swagger/OpenAPI (@elysiajs/swagger) · uuid (v7) · bcrypt.

Быстрый старт

Docker

JWT_SECRET=$(openssl rand -hex 32) ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=change-me-please docker compose up --build

API: http://localhost:3000/api, документация: http://localhost:3000/swagger. Контейнер сам применяет миграции и сид (пины, версии приложений, ченджлог, приветственное объявление, админ из ADMIN_EMAIL/ADMIN_PASSWORD).

Локально

Нужны Bun ≥ 1.3, PostgreSQL ≥ 14 (с расширением pg_trgm) и Redis ≥ 6.

bun install
cp .env.example .env            # поправьте DATABASE_URL / REDIS_URL
bun run db:migrate
bun run db:seed
bun run dev                     # http://localhost:3000

В разработке письма не отправляются: одноразовые коды пишутся в лог, а при DEV_EXPOSE_OTP=true ещё и возвращаются в ответе (otp). Чтобы регистрироваться без кода, выставьте EMAIL_VERIFICATION=false.

Пример с itd-sdk

from itd import ITDConfig, init_client, Me, Post
from itd.core.auth import CredentialsAuth

client = init_client('local', config=ITDConfig(url='http://localhost:3000/api'),
                     auth=CredentialsAuth('me@example.com', 'my-password-123', 'captcha-not-required'))
print(Me().username)
Post.new('Привет из SDK #итд').like()

Возможности

Область Что реализовано
Аутентификация регистрация с подтверждением email кодом, вход, refresh_token в HttpOnly-cookie с ротацией и grace-окном, JWT access на 15 минут (sid, sub, roles, iss: auth-service), выход, выход везде, смена/сброс пароля, вход по QR (подтверждение только с мобильной сессии), список и отзыв сессий с разбором устройства
Профили создание профиля после регистрации, emoji-аватар = клан, баннер, био, приватность (закрытый аккаунт, кто пишет на стене, кто видит лайки, last seen), онлайн/последний визит, пины (значки), удаление аккаунта с восстановлением в течение 30 дней
Социальный граф подписки (для закрытых аккаунтов — заявки с принятием/отклонением), блокировки, подписчики/подписки с пагинацией, статус подписки пачкой, топ кланов, рекомендации «кого читать»
Посты текст со спанами (bold/italic/…/link), автоматические хэштеги и упоминания, вложения, опросы, посты на чужой стене, репосты с комментарием, закреп, редактирование 48 часов, удаление с восстановлением, лайки, «доминирующее эмодзи» (клан, который чаще лайкал пост)
Ленты популярное (рейтинг + снапшоты в Redis для стабильной пагинации), подписки, клан; стена пользователя с закреплённым постом; лайкнутые посты (с учётом приватности); посты по хэштегу
Комментарии комментарии и ответы (один уровень), превью ответов, сортировки, лайки, редактирование, удаление автором/владельцем поста с восстановлением
Уведомления 12 типов SDK, дедупликация, настройки (старый и новый формат), прочтение, счётчик, SSE-стрим через Redis pub/sub (работает при нескольких инстансах)
Прочее загрузка файлов (проверка типа по сигнатуре, размеры изображений, local/S3), поиск пользователей и хэштегов (pg_trgm), жалобы, верификация, подписка «НУКСТА» с тестовой оплатой и автопродлением, просмотры/взаимодействия (/v1/i, /v1/x, в т.ч. deflate), платформа (версии, ченджлог, объявления), сезонный ивент (портал, профили, магазин, кликухи, красные ручки/корректоры), админка

Совместимость с itd-sdk

  • базовый путь /api, те же методы и URL (posts/{id}/like, v1/auth/refresh, users/me/pins, …);
  • формат ошибок {"error": {"code", "message"}} с теми же кодами и текстами, по которым SDK выбирает исключения (USERNAME_TAKEN, EDIT_WINDOW_EXPIRED, NOT_PINNED, «Вы уже отправляли жалобу на этот контент», …); ошибки токена — в «старом» формате {"error": "token expired"};
  • ошибки валидации — 422 + VALIDATION_ERROR (плюс errors/violations по полям);
  • лимиты отдают x-ratelimit-limit / x-ratelimit-remaining, превышение — {"error": "Too Many Requests"} или RATE_LIMIT_EXCEEDED с retryAfter;
  • в каждом посте есть vs-токен для отчётов о просмотрах.

Проверено прогоном самого SDK (tests/sdk, 96 проверок: модели, списки, SSE, QR-вход, оплата, все основные классы исключений):

EMAIL_VERIFICATION=false bun run dev &
ITD_API=http://localhost:3000/api bun run test:sdk

Архитектура

src/
  index.ts              запуск сервера, фоновые задачи, graceful shutdown
  app.ts                сборка Elysia-приложения (swagger, cors, лимиты, модули под /api)
  config.ts             конфигурация из переменных окружения
  db/                   схема Drizzle, клиент, миграции, сид
  redis.ts              клиенты Redis (команды + отдельное соединение для pub/sub)
  plugins/              обработчик ошибок, контекст запроса, auth-макросы, лимиты по IP
  services/             общая логика: пользователи и отношения, рендер постов и комментариев,
                        уведомления, realtime (pub/sub), кэш статистики, ленты, присутствие
  modules/<домен>/      маршруты + сервис домена: auth, users, posts, comments, hashtags,
                        search, files, notifications, reports, platform, subscription,
                        verification, dwell, event, admin, uploads
  schemas/              TypeBox-модели ответов (они же — схемы OpenAPI)
  jobs/                 периодические задачи с распределённой блокировкой
drizzle/                SQL-миграции
tests/                  bun:test (интеграционные, на реальных PostgreSQL и Redis) + tests/sdk

Маршруты объявляют требования к авторизации макросами: account: true (валидный токен), user: true (есть активный профиль), optionalUser: true, admin: true. Ответы описаны TypeBox-моделями: они валидируют и нормализуют выдачу и формируют Swagger.

Для чего Redis

Ключи Назначение
rl:ip:*, rl:act:* token bucket по IP для эндпоинтов и скользящие окна (минута/час) для действий: лайки 30/200, комментарии 5/75, подписки 5/20, репосты 5/25, посты 5/25
ps:{postId} кэш счётчиков постов для POST /posts/stats (клиенты опрашивают его каждые несколько секунд); записи обновляются атомарно через Lua
feed:popular:* версионированные снапшоты популярной ленты (курсор <версия>.<смещение>)
sess:revoked:*, sess:grace:* отозванные сессии (access-токены перестают работать сразу), grace-окно ротации refresh-токена
flow:*, qr:* одноразовые коды (хранятся только хэши) и состояния QR-входа
ch:user:*, ch:qr:* pub/sub каналы для SSE уведомлений и статусов QR
lastseen:*, online:* присутствие: последний визит и открытые SSE-соединения
cache:*, lock:* кэш трендов и кланов, блокировки фоновых задач

Переменные окружения

Полный список с комментариями — в .env.example. Главное:

Переменная По умолчанию Описание
DATABASE_URL postgres://itd:itd@localhost:5432/itd PostgreSQL
REDIS_URL redis://localhost:6379 Redis
JWT_SECRET — обязателен при NODE_ENV=production
PUBLIC_URL http://localhost:3000 база для ссылок на файлы, QR и оплату
EMAIL_VERIFICATION true регистрация с подтверждением кодом
COOKIE_SECURE true в production флаг Secure для refresh_token
CORS_ORIGINS — разрешённые origin (в production без него CORS выключен)
TRUST_PROXY false брать IP/страну из заголовков прокси
STORAGE_DRIVER local local (раздача из /uploads) или s3
RATE_LIMIT_MULTIPLIER 1 масштаб всех лимитов
TURNSTILE_SECRET — включает проверку Cloudflare Turnstile
EVENT_ENABLED false сезонный ивент

Тесты

createdb itd_test             # имя базы обязано заканчиваться на _test: тесты очищают таблицы
bun test                      # настройки берутся из .env.test

71 интеграционный тест на настоящих PostgreSQL и Redis: OTP-регистрация, ротация и отзыв токенов, сессии, QR-вход, профили и приватность, подписки и заявки, блокировки, посты, ленты и курсоры, закрепы, лайки и доминирующее эмодзи, репосты, редактирование и восстановление со счётчиками, опросы, комментарии, уведомления и SSE, файлы, жалобы, оплата и автопродление, верификация, просмотры (в т.ч. сжатые deflate), лимиты, баны, очистка аккаунтов, ивент.

Упрощения

  • письма (коды подтверждения) пишутся в лог — для продакшена подключите транспорт в src/lib/mailer.ts;
  • оплата «НУКСТА» тестовая: ссылка confirmationUrl ведёт на страницу-заглушку, которая подтверждает платёж;
  • модерации изображений нет; запрещённые слова — из BANNED_WORDS и таблицы banned_words (админка);
  • геолокация по IP — только код страны из CF-IPCountry при TRUST_PROXY=true;
  • механика сезонного ивента воспроизведена в упрощённом, но согласованном виде (баланс, магазин, стикеры, шторы, окна, кликухи, красные ручки и корректоры).

About

Копия бэкенда ИТД на elysia js (вайбкод)

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages