Commit Graph
9 Commits
Author SHA1 Message Date
nunuchek 88b6e1395e refactor: simplify — мёртвые поля контента, общие хелперы api и тестов, липкая CTA без site в бандле
landing:
- site.ts: убраны неиспользуемые roast, brew, priceDisplay, hero.eyebrow, footer.phone (Footer берёт CONTACT_PHONE)
- form.ts: убраны FORM_TEXT.title/lead, CTAS, CtaPreset
- StickyCta получает тексты пропсами от layout: клиентский чанк больше не тащит все тексты страницы
- LeadForm/useLeadForm: без неиспользуемой подмены sendLead и className; leadPrefill без счётчика seq
- Stamp без мёртвого tone; убраны data-interest, data-hot, класс lead-form (ничем не читались)
- одно LEAD_FIELDS на sendLead и leadFormModel; регэксп typo вынесен из вызова; дубль фона body

api:
- changedFields и Version общие для leads и outbox; countLeads и leadStamps без копий SQL
- errorMessage в system.ts вместо четырёх копий; take() для ожидающих подтверждений
- backup: один Intl.DateTimeFormat на модуль, без невызываемых параметров timeZone/hour
- без мёртвых LOOPBACK '::ffff:127.0.0.1', client.call, Pick<BackupCommands> со всеми ключами
- testing.ts: validLead, addLead, count, leadIds вместо копий в тестах

deploy.sh: deployed_field и цикл по REPOS вместо повторов имён
2026-10-17 17:31:11 +03:00
nunuchek 66d69c1245 feat: ретранслятор Bot API на домашнем сервере и TELEGRAM_API_BASE
С VPS api.telegram.org недоступен. deploy/tg-relay: nginx на адресе
Tailscale домашнего сервера, пропускает только запросы нашего бота из
tailnet, без логов доступа (токен в URL). api: базовый URL Bot API из
TELEGRAM_API_BASE; сетевые сбои polling пишутся в лог раз в 10 минут.
2026-10-17 16:56:52 +03:00
nunuchek 25246ad0c4 fix(api): доверять X-Real-IP со шлюза docker-сети в IPv4-mapped виде
Node отдаёт адрес сокета как ::ffff:172.31.120.1, а TRUSTED_PROXIES
записан без префикса — все посетители попадали в один rate-limit.
2026-10-17 16:17:24 +03:00
nunuchek 249b4bb627 feat(api): ежедневный бэкап, копия в личку, восстановление через бота
backup.ts: db.backup() → gzip в backups/ рядом с базой, имя по времени
Минска (Intl), 14 ежедневных и pre-restore на 30 дней; планировщик
в 03:00 по Минску и при старте, если сегодня копии нет; файл админу,
итог в «Систему». Восстановление: gunzip → integrity_check → версия
схемы → пауза приёма (503) → pre-restore → атомарная подмена файла →
миграции; при сбое возвращаем прежнюю базу. createApp и очередь берут
базу через геттер, чтобы увидеть подменённую.
Бот в личке: /backups с кнопками, /backup, присланный .sqlite.gz,
подтверждение со списком пропадающих заявок, живёт 10 минут.
2026-10-17 16:07:26 +03:00
nunuchek 667c6a6e6d feat(api): Telegram — темы, очередь повторов, «Система», /setup
telegram/client: Bot API на fetch с таймаутом 5 с; ошибки делятся на
повторяемые (сеть, таймаут, 429, 5xx) и конфигурационные (400/403…),
токен не попадает ни в тексты ошибок, ни в tg_last_error.
format: заявка и уточнение по шаблону плана, HTML с экранированием,
источник из utm / referrer, первый визит.
outbox: Notifier с отправкой после ответа и тиком раз в минуту, пауза
1, 2, 4… мин, уточнение только после своей заявки, после 10 попыток —
в «Систему». system: тема «Система» с троттлингом ×N за период.
bot: long polling, только TELEGRAM_ADMIN_ID, /setup создаёт темы и
присылает id в личку. config: всё окружение в одном месте.
2026-10-17 16:07:26 +03:00
nunuchek ea0535001c feat(api): rate-limit, honeypot, коды ошибок
rateLimit.ts: 5 запросов / 10 минут на IP в памяти, фиксированное окно,
чистка устаревших записей по ходу запросов, 429 с Retry-After. IP из
X-Real-IP только от loopback-сокета (плюс TRUSTED_PROXIES для шлюза
docker), иначе адрес сокета; в базу IP не пишем. Honeypot → 201 без
записи и уведомления. isPaused() → 503 на время восстановления базы.
Тесты на каждый код ответа из таблицы плана.
2026-10-17 15:41:04 +03:00
nunuchek c20e40c333 feat(api): уточнения в окне 10 минут
saveLead в одной IMMEDIATE-транзакции: заявка с тем же телефоном
моложе 10 минут → уточнение, если имя, интерес или комментарий
отличаются от последней версии, иначе повтор без записи. Окно от
created_at заявки, уточнения его не продлевают. Ответ 200 duplicate,
notifier получает id уточнения и список изменившихся полей.
2026-10-17 15:39:31 +03:00
nunuchek fa0964b24d feat(api): /api/lead с SQLite и миграциями
db/: better-sqlite3 по DB_PATH (WAL, foreign_keys), миграции через
PRAGMA user_version, схема leads и lead_clarifications по плану.
createApp(deps) с инъекцией базы, часов и notifier (пока no-op, зовётся
после ответа). POST /api/lead: только JSON (415), тело до 16 КБ (413),
validateLead → 400, запись → 201. index.ts: env и graceful shutdown.
2026-10-17 15:38:42 +03:00
nunuchek 04b150f3c3 chore: pnpm workspace — landing, api, shared
apps/landing: Next.js 16 (App Router, standalone), Tailwind 4, ESLint
с запретом импорта из api. apps/api: Hono + better-sqlite3, сборка tsup,
/api/health. packages/shared: исходники TS без сборки. Vitest projects.
2026-10-17 15:33:07 +03:00