Last validated: 2026-06-09 by @claude. Next review: 2026-09-07. Status: Active
- У Railway створи New project → Empty project або Deploy from GitHub (спочатку можна лише БД).
- Add service → Database → PostgreSQL.
- Після створення відкрий сервіс Postgres → вкладка Variables (або Connect).
- Скопіюй
DATABASE_URL(або збери зPGHOST,PGUSER,PGPASSWORD,PGDATABASE— Railway часто показує готовий connection string).
Цей URL потрібен тільки бекенду (Node на Railway), не Vercel.
- Add service → GitHub repo → обери репозиторій Hub.
- У налаштуваннях сервісу: Settings → якщо не підхопився Dockerfile, вкажи Dockerfile path:
Dockerfile.api(або використай railway.toml у корені — вже налаштований). - У Variables додай:
| Змінна | Значення |
|---|---|
DATABASE_URL |
Reference до змінної Postgres-сервісу: ${{ Postgres.DATABASE_URL }} або встав вручну скопійований рядок |
BETTER_AUTH_SECRET |
Випадковий рядок ≥32 символів |
BETTER_AUTH_URL |
Публічний HTTPS URL цього API після деплою, напр. https://hub-api-production.up.railway.app (без слеша в кінці) |
ANTHROPIC_API_KEY |
Ключ Claude |
PORT |
Зазвичай Railway підставляє сам; якщо треба — 3000 |
ALLOWED_ORIGINS |
URL фронту на Vercel, напр. https://твій-проєкт.vercel.app (через кому, якщо кілька) |
RESEND_API_KEY |
Опційно, але для листів скидання пароля / верифікації email — ключ Resend. Без нього бекенд стартує з warn у логах. Опційно RESEND_FROM (відправник з верифікованого домену). |
BETTER_AUTH_CROSS_SITE_COOKIES |
Опційно: 0 — не форсити SameSite=None (рідко: один домен через reverse proxy). Якщо не задано, при BETTER_AUTH_URL на https:// кукі налаштовуються для крос-сайтового фронта (Vercel → Railway). |
SENTRY_DSN |
DSN бекенд-проєкту в Sentry (платформа Node.js). Без цієї змінної apps/server/src/sentry.ts стає no-op і помилки не їдуть у Sentry — alert routing у n8n не зрабує. Див. §7. |
SENTRY_ENVIRONMENT |
Опційно: production / staging. Дефолт — NODE_ENV. |
SENTRY_TRACES_SAMPLE_RATE |
Опційно: 0..1. Дефолт 0.1. 0 явно вимикає трейсинг. |
- У Networking увімкни Public networking, скопіюй домен — це і є база для
BETTER_AUTH_URL. - Задеплой. У логах після старту має бути
[db] Schema verifiedі (якщо єSENTRY_DSN){"msg":"sentry_initialized",...}.
У Project → Settings → Environment Variables (Production / Preview / Development):
| Змінна | Значення |
|---|---|
BACKEND_URL |
Публічний URL API (Railway), напр. https://sergeant-production.up.railway.app |
VITE_SENTRY_DSN |
DSN фронт-проєкту в Sentry (платформа javascript-react). Без нього @sentry/react не підвантажується — економія ~30–40 KB у бандлі. |
VITE_SENTRY_ENVIRONMENT |
Опційно: production / preview. Дефолт — MODE. |
VITE_SENTRY_TRACES_SAMPLE_RATE |
Опційно: 0..1. Дефолт 0.1. |
VITE_SENTRY_REPLAY_SAMPLE_RATE |
Опційно: 0..1 для Session Replay. Дефолт 0 (вимкнено); replaysOnErrorSampleRate завжди 1. |
Чому
BACKEND_URL, а неVITE_API_BASE_URL?Safari (ITP) блокує third-party cookie, коли фронт і API на різних доменах. Edge Middleware (
apps/web/middleware.ts) проксіює/api/*наBACKEND_URL, роблячи cookie same-origin. Фронтенд використовує відносні шляхи —VITE_API_BASE_URLвидали (або залиш порожнім), щоб запити йшли через проксі, а не напряму на Railway.
Перезбери фронт після зміни змінних.
Якщо хочеш PostgreSQL на машині без хмари:
docker compose up -dУ .env (локально):
DATABASE_URL=postgresql://hub:hub@localhost:5432/hub
BETTER_AUTH_URL=http://localhost:3000
ALLOWED_ORIGINS=http://localhost:5173Потім pnpm start (API) і pnpm dev (Vite).
GET https://<твій-api>.up.railway.app/readyz(або історичний аліас/health) → тілоok, якщо PostgreSQL доступний; інакше 503 іunhealthy.GET https://<твій-api>.up.railway.app/livez→ завжди200 ok, якщо процес живий (не чіпає БД) — зручно для простого uptime-моніторингу.- У відповідях API є заголовок
X-Request-Id(або передай свійX-Request-Idз клієнта). - Реєстрація в застосунку з прод-фронту: куки й CORS мають відповідати
ALLOWED_ORIGINSі домену API. Safari (ITP) блокує third-party cookie — Edge Middleware уapps/web/middleware.tsпроксіює/api/*через Vercel, роблячи cookie same-origin. Якщо сесія «не тримається» — перевір, щоBACKEND_URLзадано на Vercel іVITE_API_BASE_URLвидалено.
- Healthcheck:\n+ - Uptime:
GET /livezкожні 1–5 хв.\n+ - Readiness (з БД):GET /readyz(або/health) — корисно, якщо хочеш алертити саме проблеми з Postgres.\n+ - Алерт при не 200 або тілі неok. - Логи Railway: шукай за
X-Request-Idз відповіді API або з тіла помилки (requestId), щоб зв’язати клієнт і сервер. - Структуровані рядки
{"msg":"http",...}— фільтруй заstatus >= 500абоpathдля регресій.
Error-алерти йдуть з обох Sentry-проєктів (sergeant-api, sergeant-web) у self-hosted n8n
(Railway) → воркфлоу 03 — Sentry Alert Routing → Telegram (Sergeant_alert_bot).
Як це склеєно (одноразова операція в Sentry/n8n, не в коді репо):
- Sentry → Settings → Developer Settings → Custom Integrations → Internal Integration
n8n Alert Routing:Webhook URL = <n8n-public>/webhook/sentry-alert,Alerts = on, scopesevent:read, project:read, org:read. Інсталюється в орг автоматично. - Per-project (
sergeant-api,sergeant-web) → Settings → Legacy Integrations → WebHooks увімкнути плагін, уCallback URLsвставити той самий<n8n-public>/webhook/sentry-alert. Це дає actionSend a notification via webhooksдля Issue Alert Rules. - Per-project → Alerts → Rules → Create Issue Alert з умовою
A new issue is createdта actionSend a notification via webhooks. Існуюча дефолтна рулза Send a notification for high priority issues не чіпає n8n — webhook action треба додати окремо. - n8n → workflow
03-sentry-alert-routing.json(active=true) парситьbody.data.issue.{level,title,project.name,count,permalink}і шле вTELEGRAM_ALERT_CHAT_ID. Гілки:level=fatal→🚨 FATAL, інші не-info→⚠️ <level>.
Воркфлоу/маніфест джерела істини — в ops/n8n-workflows/;
ADR — docs/04-governance/adr/0026-n8n-workflow-source-of-truth.md.
У git active: false навмисно (per ADR-0026 — активація це окрема операція в середовищі).
Railway шле webhook-події про деплої у self-hosted n8n (Railway) → воркфлоу
15 — Railway Deployment Notify → Telegram (Sergeant_alert_bot).
Як це склеєно (одноразова операція в Railway UI, не в коді репо):
- Railway → відкрий проєкт (
humorous-eagernessдляsergeant-api,grateful-nurturingдля n8n) → Settings → Webhooks. - Натисни Add Webhook, встав URL:
https://n8n-production-09ac.up.railway.app/webhook/railway-deploy. - Опційно вибери події (за замовчуванням Railway шле всі deploy-події).
- Save → з'явиться рядок з кнопкою Test Webhook — натисни, щоб переконатись, що n8n приймає payload. Має прийти exec на 15 з тестовим Telegram-повідомленням.
- Повтори те саме для другого проєкту.
Workflow 15 парсить payload Railway формату:
{
"type": "Deployment.deployed",
"details": {
"status": "SUCCESS",
"branch": "...",
"commitMessage": "...",
"commitHash": "..."
},
"resource": {
"service": { "name": "..." },
"environment": { "name": "..." }
},
"severity": "INFO",
"timestamp": "..."
}Гілки: status ∈ SUCCESS|DEPLOYED|ACTIVE → ✅ success, інакше → ❌ failed.
Telegram-повідомлення містить: service, env, branch, commit hash + msg, duration.
Railway-вебхуки (Project Settings → Webhooks) у GraphQL — це насправді
notificationRule ресурс з channel-config { "type": "WEBHOOK", "url": "<your-url>" }.
Перелік правил воркспейсу:
query {
notificationRules(workspaceId: "<workspace-id>") {
id
eventTypes
severities
projectId
channels {
id
config
}
}
}Важливе обмеження: для створення правил workspace-level PAT (Account Settings → Tokens → New Token зі scope = workspace) має достатньо прав, але
notificationRuleDelete/notificationRuleUpdate з того самого PAT повертають
Not Authorized — Railway навмисно гейтить mutate-операції на dashboard UI.
Канонічні eventTypes (lowercase, <object>.<action>, виявлені через
events(projectId: ...)):
| eventType | severity | значення |
|---|---|---|
Deployment.created |
INFO |
створено deploy |
Deployment.building |
INFO |
почалась збірка |
Deployment.snapshoted |
INFO |
snapshoted |
Deployment.deploying |
INFO |
деплоїться (контейнер стартує) |
Deployment.deployed |
INFO |
успішний деплой (status=SUCCESS) |
Deployment.failed |
WARNING |
build/deploy впав |
Deployment.crashed |
CRITICAL |
контейнер впав після старту |
Deployment.removed |
INFO |
старий деплой знятий |
DEPLOY_* (uppercase, як в legacy webhook payload) — не валідні в API.
Якщо у воркспейсі лишились правила з невірними event-name (DEPLOY_SUCCEEDED,
DEPLOY_FAILED тощо), вичистити їх можна тільки через Railway UI:
Project → Settings → Webhooks → знайти рядок з URL n8n → ⋮ → Delete.
Робити це для кожного зайвого webhook-рядка (по проєктах окремо).