Environment Variables / Переменные окружения
Обзор
В проекте используется двухуровневая система секретов:
┌─────────────────────────────────────────────────────────────────────┐
│ DOPPLER (Уровень 1) │
│ Глобальные секреты │
├─────────────────────────────────────────────────────────────────────┤
│ CRYPTO_KEY / CRYPTO_SALT — ключ и соль шифрования для D1 │
│ OPENAI_API_KEY — API ключи внешних сервисов │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ CLOUDFLARE D1 (Уровень 2) │
│ Per-integration секреты и данные │
├─────────────────────────────────────────────────────────────────────┤
│ integ-db (binding: INTEG_DB) │
│ ├── creds — зашифрованные секреты интеграций │
│ │ ├── sofa/NETHUNT_API_KEY │
│ │ ├── sofa/SAAS_ASSISTANT_ID │
│ │ └── rozetka/CRM_TOKEN │
│ │ │
│ └── {integration}_* — данные интеграций (создаются вами) │
│ ├── sofa_calls │
│ ├── sofa_leads │
│ └── rozetka_orders │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ CLOUDFLARE KV (Кэш и флаги) │
├─────────────────────────────────────────────────────────────────────┤
│ integ-kv (binding: INTEG_KV) │
│ ├── sofa:rate_limit:user123 │
│ ├── sofa:cache:lead:456 │
│ └── rozetka:feature_flags │
└─────────────────────────────────────────────────────────────────────┘Когда использовать что?
| Хранилище | Используй для | Примеры |
|---|---|---|
| Doppler | Глобальные API ключи, ключи шифрования | OPENAI_API_KEY, CRYPTO_KEY, CRYPTO_SALT |
| D1 creds | Секреты конкретной интеграции | NETHUNT_API_KEY, CRM_TOKEN |
| D1 {name}_data | Персистентные данные интеграции | Звонки, лиды, заказы |
| KV | Кэш, rate limiting, feature flags | TTL-based кэш, счётчики |
Doppler секреты — полная таблица
Обязательные переменные
| Переменная | Описание | Где взять |
|---|---|---|
CRYPTO_KEY | Ключ шифрования credentials в D1 | openssl rand -hex 32 |
CRYPTO_SALT | Соль для шифрования (16+ символов) | Любая строка 16+ символов |
CLOUDFLARE_INTEG_DB_ID | ID D1 базы данных | Cloudflare Dashboard или placeholder |
CLOUDFLARE_INTEG_KV_ID | ID KV namespace | Cloudflare Dashboard или placeholder |
💡 Примечание: ID для D1 и KV хранятся в Doppler для каждого окружения. Скрипт
generate:envподставляет их вwrangler.toml.
Опциональные переменные
| Переменная | Описание | Где взять |
|---|---|---|
DATABASE_URL | PostgreSQL connection string | Neon / локальный Postgres |
OPENAI_API_KEY | API ключ OpenAI | OpenAI Platform |
CLAUDE_API_KEY | API ключ Anthropic | Anthropic Console |
GROQ_API_KEY | API ключ Groq | Groq Console |
QDRANT_URL | URL Qdrant сервера | Qdrant Cloud |
QDRANT_API_KEY | API ключ Qdrant | Qdrant Cloud |
SAAS_API_URL | URL SaaS API | api.dev.happ.tools (dev) / api.happ.tools (prod) |
SAAS_ACCESS_TOKEN | Токен доступа к SaaS API | Сгенерированный токен |
DEBUG | Включить debug логирование | true / false |
Примеры значений по окружениям
Local (для локальной разработки)
# Cloudflare resource IDs — placeholder для локальной разработки
CLOUDFLARE_INTEG_DB_ID=00000000-0000-0000-0000-000000000001
CLOUDFLARE_INTEG_KV_ID=00000000000000000000000000000002
# Шифрование — ОБЯЗАТЕЛЬНО
CRYPTO_KEY=a75a9de60aeebfc889967594f6aa94cfd745737486a441a83dc51c10928c89a1
CRYPTO_SALT=integ-core
# PostgreSQL (если используется)
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/integ
# Опционально
OPENAI_API_KEY=sk-...
GROQ_API_KEY=gsk_...💡 D1 и KV: Для локальной разработки wrangler создаёт SQLite базы в
data/miniflare/. Placeholder ID используются для генерации правильных имён файлов.
Dev / Prod (Cloudflare)
# Cloudflare resource IDs — реальные ID из Cloudflare Dashboard
CLOUDFLARE_INTEG_DB_ID=<uuid-d1-database>
CLOUDFLARE_INTEG_KV_ID=<uuid-kv-namespace>
# Шифрование — УНИКАЛЬНЫЕ для каждого окружения!
CRYPTO_KEY=<уникальный-ключ-для-окружения>
CRYPTO_SALT=<уникальная-соль-для-окружения>
# PostgreSQL (Neon)
DATABASE_URL=postgres://user:pass@ep-xxx.neon.tech/integ?sslmode=require
# LLM
OPENAI_API_KEY=sk-...💡 D1/KV для dev/prod: ID ресурсов хранятся в Doppler и подставляются скриптом
generate:env.
Создание ресурсов на Cloudflare (dev/prod)
Создание D1 на Cloudflare
- Перейдите в Cloudflare Dashboard → Workers & Pages → D1 SQL Databases
- Нажмите Create database
- Имя базы:
integ-db-devилиinteg-db-prod - После создания скопируйте Database ID (UUID)
- Укажите ID в
wrangler.toml.tplили CI/CD
# Или через CLI:
wrangler d1 create integ-db-dev
# → Created database 'integ-db-dev' with id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxПрименение миграций:
Все миграции (включая системную таблицу creds) применяются автоматически через код при вызове POST /{integration}/setup. SQL-файлы миграций не используются.
# После создания базы и деплоя — вызовите setup для применения миграций
curl -X POST https://integ.dev.happ.tools/sofa/setupСоздание KV на Cloudflare
- Перейдите в Cloudflare Dashboard → Workers & Pages → KV
- Нажмите Create a namespace
- Имя namespace:
integ-kv-devилиinteg-kv-prod - После создания скопируйте Namespace ID
- Укажите ID в
wrangler.toml.tplили CI/CD
# Или через CLI:
wrangler kv namespace create integ-kv-dev
wrangler kv namespace create integ-kv-prod
# → Created namespace "integ-kv-dev" with id: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyyЛокальная разработка
При локальной разработке (pnpm start <integration>):
- D1 база — автоматически создаётся SQLite файл в
data/miniflare/ - KV — автоматически создаётся SQLite файл в
data/miniflare/ - Секреты — читаются из
.dev.vars(генерируется из Doppler)
# Генерация .dev.vars из Doppler
pnpm generate:env local
# База данных и KV создаются автоматически при первом запуске
pnpm start sofaЛокальные файлы
data/miniflare/v3/
├── d1/miniflare-D1DatabaseObject/
│ └── 7ac1b8d7...sqlite ← integ-db (SHA256 от placeholder ID)
└── kv/miniflare-KVNamespaceObject/
└── ...sqlite ← integ-kvХеши файлов:
# D1: placeholder ID
echo -n "00000000-0000-0000-0000-000000000001" | shasum -a 256
# → 7ac1b8d7010bb6cd3a3e84e7f90136b880bbc899e428ece49333372911ab9052
# KV: placeholder ID
echo -n "00000000000000000000000000000002" | shasum -a 256Важно: Для локальной разработки не нужно создавать базы на Cloudflare — всё работает локально!
Cloudflare Bindings (wrangler.toml)
Важно:
wrangler.tomlгенерируется автоматически из шаблонов вtemplates/. Не редактируйте его напрямую!
D1 Database
| Binding | Database | Описание |
|---|---|---|
INTEG_DB | integ-db | Единая база данных (credentials + данные) |
# Генерируется автоматически из templates/wrangler.integration.toml.tpl
[[d1_databases]]
binding = "INTEG_DB"
database_name = "integ-db"
database_id = "{{D1_DB_ID}}" # Подставляется из CLOUDFLARE_INTEG_DB_IDKV Namespace
| Binding | Namespace | Описание |
|---|---|---|
INTEG_KV | integ-kv | KV для кэширования |
[[kv_namespaces]]
binding = "INTEG_KV"
id = "{{KV_ID}}" # Подставляется из CLOUDFLARE_INTEG_KV_IDСтруктура таблиц в D1
integ-db
├── creds # Системная таблица (создаётся автоматически)
│ ├── integration_name # "sofa", "rozetka"
│ ├── key # "NETHUNT_API_KEY"
│ └── encrypted_value # Зашифрованное значение
│
└── {integration}_{table} # Таблицы данных (создаёте вы)
├── sofa_calls # Примеры
├── sofa_leads
└── rozetka_ordersСоздание таблицы для интеграции:
Все миграции определяются в коде интеграции (в файле конфигурации src/config/migrations.ts) и применяются автоматически при вызове POST /{integration}/setup. SQL-файлы миграций не используются.
// src/config/migrations.ts — пример миграции для таблицы sofa_calls
export const migrations = [
{
name: "create_sofa_calls",
sql: `CREATE TABLE IF NOT EXISTS sofa_calls (
id TEXT PRIMARY KEY,
phone TEXT NOT NULL,
status TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now'))
)`,
},
];# Применить миграции (после деплоя)
curl -X POST https://integ.dev.happ.tools/sofa/setup
curl -X POST https://integ.happ.tools/sofa/setupPer-integration переменные (D1 creds)
Уникальные переменные для каждой интеграции хранятся зашифрованными в D1.
Добавление секретов через CLI
# Добавить секрет для интеграции sofa
pnpm cli creds set --integration sofa --key NETHUNT_API_KEY --value "your-api-key"
# Просмотреть секреты
pnpm cli creds list --integration sofaИспользование в коде
import { Creds } from "@happ-integ/creds";
const creds = new Creds({
d1: env.INTEG_DB,
masterKey: env.CRYPTO_KEY,
salt: env.CRYPTO_SALT,
});
// Получить credentials
const secrets = await creds.get<{
NETHUNT_EMAIL: string;
NETHUNT_API_KEY: string;
}>("sofa");
console.log(secrets.NETHUNT_EMAIL);Примеры использования KV
// Rate limiting
await env.INTEG_KV.put(`sofa:rate_limit:${userId}`, "1", { expirationTtl: 60 });
// Кэширование
await env.INTEG_KV.put(`sofa:cache:lead:${id}`, JSON.stringify(lead), { expirationTtl: 300 });
// Feature flags
const flags = await env.INTEG_KV.get("sofa:feature_flags", "json");Конфигурация по окружениям
| Окружение | Doppler Config | Источник secrets |
|---|---|---|
| Local | local | .dev.vars файлы |
| Dev | dev | Cloudflare Workers Secrets |
| Production | prod | Cloudflare Workers Secrets |
Команды
# Генерация .env и wrangler.toml из Doppler
pnpm generate:env local # для локальной разработки
pnpm generate:env dev # для dev окружения
pnpm generate:env prod # для production
# Запуск локально
doppler run -- pnpm dev
# Деплой
pnpm --filter integ-sofa deploy:dev
pnpm --filter integ-sofa deploy:prodQuick Reference — где что брать
| Переменная | Local | Dev/Prod |
|---|---|---|
CLOUDFLARE_INTEG_DB_ID | Placeholder UUID | Cloudflare Dashboard |
CLOUDFLARE_INTEG_KV_ID | Placeholder UUID | Cloudflare Dashboard |
CRYPTO_KEY | openssl rand -hex 32 | openssl rand -hex 32 |
CRYPTO_SALT | Любая строка 16+ символов | Любая строка 16+ символов |
DATABASE_URL | postgresql://...@localhost | Neon Console |
OPENAI_API_KEY | OpenAI Platform | OpenAI Platform |
GROQ_API_KEY | Groq Console | Groq Console |
💡 D1/KV ID: Все ID хранятся в Doppler и подставляются скриптом
generate:env.
Связанные документы
- SECRETS.md — управление секретами
- SETUP.md — начальная настройка проекта
- DEVELOPMENT.md — локальная разработка
- DOPPLER_SETUP.md — настройка Doppler