Pricing: при полном отказе всех запросов пробует localStorage-кэш
последнего успешного ответа вместо пустого состояния, пишет туда же при
успехе. Faq: отличает "в кэше правда пусто" от "не смогли загрузить" —
раньше оба случая показывали один и тот же текст "0 protocols found",
что вводило в заблуждение при обычном сетевом сбое.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
.gitignore имел общий паттерн ".env*" (стандартный для Next.js) без
исключения для .env.example — сам шаблон никогда не мог быть закоммичен.
Добавлено исключение !.env.example.
docker-compose.dev-remote.yml требует ${BOT_USERNAME:?...} — жёсткая
зависимость от .env на dev VPS, нигде не задокументированная до этого.
Прод (docker-compose.yml) секретов не требует — там всё захардкожено
(публичные URL/домены, ни одного пароля/токена).
Копии .github/workflows/{build,deploy}.yml. Логин на ghcr.io — через
secrets.GHCR_TOKEN (настоящий GitHub PAT), не secrets.GITHUB_TOKEN —
автотокен Gitea валиден только для самого Gitea. Триггер workflow_run в
deploy.yml поддержан не во всех версиях Gitea Actions — см. комментарий
в файле.
Нужно завести в Gitea секрет GHCR_TOKEN (write:packages) + все остальные
секреты, что уже есть в GitHub Actions (отдельное хранилище).
pnpm по умолчанию хардлинкает пакеты из общего стора (next сам хардлинкает
dist/api/*.js на dist/esm/api/*.js). При переносе слоя node_modules через
registry и разворачивании containerd/overlayfs на dev-хосте пара
хардлинков может разойтись по разным слоям — overlayfs не находит второй
конец линка и падает с "no such file or directory". package-import-method=copy
убирает хардлинки в node_modules целиком.
Builder-стейдж — node:20-alpine, там busybox grep, не понимающий -P/\K
(перловый lookbehind). Локально с GNU grep всё работало, в CI на alpine
падало с exit 2 ещё до sed. Извлекает ENGINE_VERSION чистым POSIX sed
вместо grep -oP.
Добавляет zh-CN, fa, ar, tr, uk, be, vi, uz словари (170 ключей, идентичная
вложенная структура) к существующим en/ru. lib/locales.ts — единый источник
списка локалей/дефолтной локали/RTL-набора вместо захардкоженного ["en","ru"]
в proxy.ts. language-switcher.tsx: переключение языка резало только
двухбуквенные коды регэкспом (/^\/[a-z]{2}/), из-за чего zh-CN никогда не
матчился и путь задваивался — заменено на honest-поиск по списку locales.
app/[lang]/layout.tsx — dir="rtl"/"ltr" на <html> по локали (SSR, в отличие
от реактивного клиентского переключения в netrunner-app). Header.tsx/
Footer.tsx — разбитое на три <span> имя бренда визуально переворачивалось
Flexbox'ом под dir=rtl ("VPNrunnerNet"), исправлено через dir="ltr" на
самом враппере.
BlogPreview/Faq/Pricing и обе blog-страницы: fallback на *_en-коллекцию
PocketBase, если для языка ещё нет переведённого контента (FAQ-ответы,
детали тарифов, посты блога не тянутся автоматически — это отдельный от
статических словарей CMS-контент), плюс i18n-ключи period1m/period6m/
period1y вместо захардкоженных ru/en-подписей периодов в Pricing.tsx.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Раздел документации на сайте (documents_ru/documents_en в PocketBase)
содержал только два обрубленных стаб-документа. Добавлен полный набор
из 12 документов на русском и английском (Core/Security/Network/Legal),
технически сверенных с реальной реализацией протокола (NRXP, ChaCha20-
Poly1305, X25519, TLS-маскировка под JA3/JA4) и с моделью сессий
(HttpOnly-cookie, ротация refresh-токенов) — не маркетинговые обещания,
а описание того, что фактически работает в коде.
Юридические документы (Privacy/Terms/Refund) содержат явные плейсхолдеры
для реквизитов оператора сервиса — сервис ещё не зарегистрирован ни в
одной юрисдикции, поэтому не полагаться на них как на итоговый текст
без замены плейсхолдеров.
scripts/seed-docs.mjs — идемпотентный скрипт наполнения PocketBase
(upsert по title, с alias-картой под старые названия стабов); ничего не
записывает без --apply и без PB_ADMIN_EMAIL/PB_ADMIN_PASSWORD в
окружении — админ-доступ к CMS нигде не хардкожен.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
netrunner-backend dev теперь проксирует Caddy на стандартный порт 443
(VPN-нода, ранее занимавшая его, перенесена на другой порт) — Telegram
Login Widget в браузере требует именно этот порт.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
netrunner-backend's dev stand now terminates TLS via Caddy on :8443
(needed for Telegram Web Apps, which require https://, and its session
cookies are Secure again to match prod). Updated ACCOUNT_ORIGIN/API_URL
here to match — a plain-HTTP fetch to :8080 would no longer receive a
cookie the browser is willing to store.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Telegram Login Widget refuses to run on a raw IP ("Bot domain invalid")
— BotFather's /setdomain only accepts an actual domain name. Switched
every browser-facing URL in the dev compose (ACCOUNT_ORIGIN, API_URL,
PB_PUBLIC_URL, NEXT_PUBLIC_*) to dev.netrunner-vpn.com, which needs a DNS
A-record pointing at 45.76.161.137.
Also dropped the silent BOT_USERNAME fallback to the prod bot's handle —
that fallback is exactly how this surfaced: a prod bot has the prod
domain registered in BotFather, so serving its widget from the dev host
was guaranteed to fail. BOT_USERNAME is now a required env var with a
loud error instead of a quiet wrong default.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Auth: drop localStorage session token entirely, talk to netrunner-backend
via credentials:"include" HttpOnly cookies shared over the common parent
domain, and redirect to the account subdomain (ЛК) after login instead of
a dead local /profile route.
Config: NEXT_PUBLIC_* values used by client components (API_URL,
ACCOUNT_ORIGIN, BOT_USERNAME, PB_URL) get inlined into the JS bundle at
image build time and can't be overridden by docker-compose environment at
container start. Moved these reads into server components (page.tsx) and
thread them down as props, so one built image can genuinely serve both
prod and dev by config alone.
CI/CD: split the old single auto-deploy-to-prod workflow into build.yml
(build+push on every push to main) and deploy.yml with deploy-dev (auto,
same VPS as netrunner-backend's dev environment) and deploy-prod (manual
dispatch only) — mirrors netrunner-backend's pipeline shape. Added
docker-compose.dev-remote.yml pointing at the dev backend.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>