Раздельные frontend и backend
Репозиторий поддерживает совмещённый запуск и два отдельных процесса. Боты пока
остаются в backend: обновление frontend не перезапускает ботов, обновление backend
по-прежнему перезапускает их. Существующие Dockerfile и railway.toml сохраняют
прежний production-путь; новые конфиги сами по себе не переключают Railway.
Локальная разработка и сборка
| Команда | Назначение |
|---|---|
npm run dev | Прежний совмещённый сервер разработки на порту 5000 |
npm run dev:split | Отдельные Vite и backend, открывать frontend на порту 5173 |
npm run dev:frontend | Только Vite; backend уже должен работать отдельно |
npm run dev:backend | Только API и боты в режиме разработки |
npm run build | Сборка клиента, затем сервера |
npm run build:client | Только интерфейс в dist/ |
npm run build:server | Только сервер в dist/server/ |
npm start | Совмещённый запуск собранного приложения |
npm run start:frontend | Собранный интерфейс и прокси |
npm run start:backend | API и боты без SPA |
Для раздельной готовой сборки после npm run build открыть два терминала:
# Первый терминал; только локальная тестовая БД и Redis.
npm run start:backend
# Второй терминал; BACKEND_URL не попадает в браузерную сборку.
$env:BACKEND_URL = 'http://127.0.0.1:5000'
npm run start:frontend
Открывать http://localhost:5173, обращаться к API через тот же адрес. Нельзя
одновременно запускать два backend с боевыми токенами: это не способ проверки
split-режима. Использовать изолированную БД и тестовые токены.
dev:split принимает FRONTEND_PORT и BACKEND_PORT; если BACKEND_PORT не
задан, используется PORT или 5000. Для отдельного dev:backend порт задаётся
через PORT. В dev:frontend можно явно указать BACKEND_URL.
Vite при build:client очищает dist/, поэтому при ручном запуске двух сборок
нужен порядок «client, затем server», как в npm run build.
Одна точка входа
Frontend отдаёт SPA и проксирует серверные запросы, включая API, WebSocket, локальные медиа и серверные маршруты админки. Браузер использует относительные URL, cookies остаются на одном origin; отдельный публичный адрес API, CORS и копирование токенов в frontend не требуются. Пути авторизации и админки должны сохранять маршрутизацию backend и его проверки доступа.
BACKEND_URL задаётся только процессу frontend и содержит HTTP(S) origin без
секретов и пути. Backend сохраняет PostgreSQL, Redis, хранилища, ключи и Python.
В frontend не передавать DATABASE_URL, REDIS_URL, SESSION_SECRET и токены ботов.
Подготовленные конфиги Railway
| Сервис | Config File Path | Dockerfile | Запуск |
|---|---|---|---|
| frontend | /railway.frontend.toml | Dockerfile.frontend | node frontend/index.mjs |
| backend | /railway.backend.toml | Dockerfile.backend | node dist/server/index.js |
Оба сервиса используют корень репозитория /: здесь общие package-lock, shared
и lib. Не выставлять Root Directory в /client или /server. Старый
/railway.toml остаётся для совмещённого развёртывания.
При проверке 10 ноября 2026 Railway API отказался принимать выбор .toml
через railwayConfigFile, предложив Infrastructure as Code. Для тестовых
сервисов настройки применены непосредственно: Dockerfile Path из таблицы,
Start Command из таблицы, Healthcheck Path /api/health, Timeout 60 секунд,
Restart Policy ON_FAILURE. Watch Paths берутся из соответствующего .toml.
Эти файлы остаются справочными конфигурациями; нельзя считать их автоматически
подключёнными. Переход на .railway/railway.ts требует отдельной проверки.
Backend-образ выставляет APP_MODE=backend. Для backend задать постоянный
PORT=5000 и HOST=::, чтобы слушать IPv6, необходимый приватной сети Railway
в окружениях с IPv6-only DNS (на Linux dual stack также принимает IPv4). Для
frontend задать BACKEND_URL=http://backend.railway.internal:5000, заменив
backend действительным внутренним именем сервиса. Оба сервиса должны быть
в одном environment. Frontend использует предоставленный Railway PORT.
Публичный адрес направляется на frontend; backend остаётся внутренним, кроме
отдельно необходимых Telegram webhook или внешних API-интеграций.
Healthcheck /api/health frontend проходит через proxy: успешная раздача HTML
при недоступном backend не считается готовностью сервиса.
Для проверки образов при работающем Docker Engine:
docker build -f Dockerfile.frontend -t botcraft-frontend .
docker build -f Dockerfile.backend -t botcraft-backend .
Проверка Node.js локально не заменяет сборку Linux-образов. Если Docker Engine
недоступен, использовать результат GitHub workflow split-runtime, который
собирает оба Linux-образа без deploy. Успешная сборка образа ещё не заменяет
проверку приватной сети и переменных в staging.
Watch paths включают общие исходники, package-lock, конфиги и Dockerfile каждого
сервиса. Frontend следит также за scripts/vite*.ts, которые импортирует его
конфигурация сборки. Backend намеренно следит за client/utils/** и
client/components/editor/sidebar/parsePythonCodeToJson.ts: генератор пока
импортирует эти утилиты. Остальные изменения только интерфейса не должны
перезапускать backend. Изменения package-lock и shared/lib пересобирают оба.
При добавлении зависимости сборки соответствующий watch path нужно обновить.
Порядок переключения и откат
Production: действующая схема
С 10 ноября 2026 существующий сервис переименован в bot builder frontend
(a8481b49-5ca6-45bc-a1a5-3e1e8b80a79b) и обслуживает интерфейс. Его домен
telegram-bot-builder-e3u-production.up.railway.app не удалять, не переименовывать
и не переносить. API и боты работают в bot builder backend
(0885223e-f309-411f-ba48-7007b1ae2ac2), внутренний адрес
http://botcraft-backend.railway.internal:5000.
В окружении production ea4610c5-7c0c-4c5b-9daf-02f45459ac95 пользователь
применил настройки обоих сервисов 10 ноября 2026. Используется проверенный коммит
998b5436066272ff6d9287e1fafb0f6b7332e2b0. Переменные backend скопированы
из текущего процесса без изменения ключей сессий, шифрования, БД и Redis.
Публичный адрес медиа также остаётся прежним. Дальнейшие обновления обоих
сервисов должны идти из main без закрепления на отдельном коммите.
Связи заданы ссылками Railway, которые сохраняют зависимости на схеме:
| Сервис | Переменная | Значение |
|---|---|---|
| frontend | BACKEND_URL | http://${{"bot builder backend".RAILWAY_PRIVATE_DOMAIN}}:${{"bot builder backend".PORT}} |
| backend | DATABASE_URL | ${{Postgres-QrUo.DATABASE_URL}} |
| backend | REDIS_URL | ${{Redis.REDIS_URL}} |
| backend | S3_ENDPOINT_URL | ${{tbb-uploads.ENDPOINT}} |
| backend | S3_BUCKET | ${{tbb-uploads.BUCKET}} |
| backend | S3_ACCESS_KEY_ID | ${{tbb-uploads.ACCESS_KEY_ID}} |
| backend | S3_SECRET_ACCESS_KEY | ${{tbb-uploads.SECRET_ACCESS_KEY}} |
S3_REGION=ams и S3_FORCE_PATH_STYLE=false сохранены: регион, возвращаемый
Railway для клиента (auto), отличается от прежнего значения приложения.
При переводе на ссылки проверено совпадение всех разрешённых адресов и ключей;
дополнительный перезапуск не требовался.
После зелёных проверок GitHub изменения сливаются в main. Каждый сервис
собирается своим Dockerfile и использует собственные watch paths; чистое
изменение компонента интерфейса не должно запускать backend. Исключения для
общих утилит генератора перечислены выше. Перед удалением старой рабочей ветки
проверить, что оба источника Railway уже используют main.
Перенос тома 63c860b4-7af2-4a07-a632-8539477d7c43 с /app/uploads
выполнен: том подключён к backend, frontend не имеет тома. До переноса там было
около 324 МиБ, включая
резервные копии; в /app/bots — около 160 МиБ сгенерированных файлов.
Содержимое /app/bots не находится в этом томе: сгенерированные файлы
восстанавливаются при запуске ботов, исходная копия также сохранена в архиве.
Незашифрованные архивы с токенами нельзя размещать в публично раздаваемом
/uploads. Перед переключением создан и проверен зашифрованный AES-256-GCM
архив /app/uploads/.migration/bots-20261110.tar.enc; ключ получается из
STORAGE_ENCRYPTION_KEY, контрольная сумма SHA-256:
b4144e0cc4485a1fc7d84da871dea3ae70898b4d2f299db7eec63c5f2150c47d.
Во время миграции архив проверен и восстановлен в /app/bots перед запуском
API. Сверка после переноса: все 123 файла загрузок совпали по SHA-256,
339272085 байт без архива миграции; подтверждено восстановление 29 из 29 ботов.
Первый запуск не прошёл healthcheck: команда восстановления с && exec
выполнила только первый процесс. API запущен после исправления команды.
Backend-развёртывание eedc8619-4ea1-49e1-998e-6cd09529e61b успешно;
в процессе восстановления сервер импортирован после проверки архива одним
процессом Node. Для следующих обновлений в настройках сервиса возвращена
обычная команда node dist/server/index.js и исходные watch paths.
В этом API обычный redeploy повторил старую конфигурацию снимка, поэтому
изменение команды применялось новым развёртыванием из исходников.
Watch paths могут пропустить повторный deploy того же коммита.
Проверка /api/health через прежний домен возвращает 200 и готовую БД.
Секреты backend удалены из frontend: оставлены только PORT, NODE_ENV,
BACKEND_URL. Четыре ранее ошибочных экземпляра (токены 47, 2, 33, 26)
сохранили прежние статусы; это не новые ошибки миграции.
Откат должен вернуть том, прежний образ и переменные старому сервису.
Переменные для отката следует брать из backend, поскольку frontend больше
не хранит доступ к БД, Redis и S3.
Общий вариант перехода
- Сначала проверить два процесса локально и в изолированном окружении: вход,
выход, прямые
/projects/..., админку, файлы и WebSocket. Боевые боты не дублировать в тестовой среде. - Оставить действующий сервис совмещённым и поднять frontend на временном адресе с proxy к нему. Совмещённый сервер может выступать backend для proxy.
- Проверить cookie и callback Telegram на будущем публичном адресе; во время перехода сохранить прежний SESSION_SECRET и серверное хранилище сессий.
- Для пользовательского домена переключить цель на frontend, сохранив само
имя домена. Стандартный домен
*.up.railway.appпривязан к сервису: перенос того же имени между сервисами не обещается. Если нужен неизменный адрес, сначала подготовить пользовательский домен или оставить старую точку входа. - После проверки публичного frontend применить backend-настройки из таблицы
и
APP_MODE=backend. Не создавать второй исполняющий ботов экземпляр с той же БД и токенами ради переноса. - Для отката вернуть действующему сервису
/railway.tomlи прежние переменные, дождаться healthcheck, затем вернуть пользовательский домен на него. Frontend отключать после возврата трафика. Миграция данных не требуется.
Протокол API менять совместимо со старыми открытыми вкладками. Само разделение не гарантирует снижения RAM: измерять отдельно frontend, backend и ботов.
Основания конфигурации
- Railway: Config as Code — Dockerfile path, watch patterns и healthcheck.
- Railway: shared monorepo — общая корневая директория и отдельные команды сервисов.
- Railway: private networking — внутренние DNS и связь в одном environment.