mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 12:04:02 +00:00
refactor(config): remove single-household deploy legacy
This commit is contained in:
13
.env.example
13
.env.example
@@ -6,11 +6,6 @@ PORT=3000
|
|||||||
# Database
|
# Database
|
||||||
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:54322/postgres
|
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:54322/postgres
|
||||||
|
|
||||||
# Optional Supabase
|
|
||||||
SUPABASE_URL=https://your-project-ref.supabase.co
|
|
||||||
SUPABASE_PUBLISHABLE_KEY=your-supabase-publishable-key
|
|
||||||
SUPABASE_SERVICE_ROLE_KEY=your-supabase-service-role-key
|
|
||||||
|
|
||||||
# Telegram
|
# Telegram
|
||||||
TELEGRAM_BOT_TOKEN=your-telegram-bot-token
|
TELEGRAM_BOT_TOKEN=your-telegram-bot-token
|
||||||
TELEGRAM_WEBHOOK_SECRET=your-webhook-secret
|
TELEGRAM_WEBHOOK_SECRET=your-webhook-secret
|
||||||
@@ -23,14 +18,6 @@ MINI_APP_ALLOWED_ORIGINS=http://localhost:5173
|
|||||||
OPENAI_API_KEY=your-openai-api-key
|
OPENAI_API_KEY=your-openai-api-key
|
||||||
PARSER_MODEL=gpt-4.1-mini
|
PARSER_MODEL=gpt-4.1-mini
|
||||||
|
|
||||||
# Optional monitoring
|
|
||||||
SENTRY_DSN=
|
|
||||||
|
|
||||||
# Optional GCP / deploy
|
|
||||||
GCP_PROJECT_ID=your-gcp-project-id
|
|
||||||
GCP_REGION=europe-west1
|
|
||||||
CLOUD_RUN_SERVICE_BOT=household-bot
|
|
||||||
|
|
||||||
# Scheduler
|
# Scheduler
|
||||||
SCHEDULER_SHARED_SECRET=your-scheduler-shared-secret
|
SCHEDULER_SHARED_SECRET=your-scheduler-shared-secret
|
||||||
SCHEDULER_OIDC_ALLOWED_EMAILS=scheduler-invoker@your-project.iam.gserviceaccount.com
|
SCHEDULER_OIDC_ALLOWED_EMAILS=scheduler-invoker@your-project.iam.gserviceaccount.com
|
||||||
|
|||||||
@@ -5,9 +5,6 @@ export interface BotRuntimeConfig {
|
|||||||
telegramWebhookSecret: string
|
telegramWebhookSecret: string
|
||||||
telegramWebhookPath: string
|
telegramWebhookPath: string
|
||||||
databaseUrl?: string
|
databaseUrl?: string
|
||||||
telegramHouseholdChatId?: string
|
|
||||||
telegramPurchaseTopicId?: number
|
|
||||||
telegramFeedbackTopicId?: number
|
|
||||||
purchaseTopicIngestionEnabled: boolean
|
purchaseTopicIngestionEnabled: boolean
|
||||||
financeCommandsEnabled: boolean
|
financeCommandsEnabled: boolean
|
||||||
anonymousFeedbackEnabled: boolean
|
anonymousFeedbackEnabled: boolean
|
||||||
@@ -60,19 +57,6 @@ function requireValue(value: string | undefined, key: string): string {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseOptionalTopicId(raw: string | undefined): number | undefined {
|
|
||||||
if (!raw) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsed = Number(raw)
|
|
||||||
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
||||||
throw new Error(`Invalid Telegram topic id value: ${raw}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseOptionalValue(value: string | undefined): string | undefined {
|
function parseOptionalValue(value: string | undefined): string | undefined {
|
||||||
const trimmed = value?.trim()
|
const trimmed = value?.trim()
|
||||||
return trimmed && trimmed.length > 0 ? trimmed : undefined
|
return trimmed && trimmed.length > 0 ? trimmed : undefined
|
||||||
@@ -93,9 +77,6 @@ function parseOptionalCsv(value: string | undefined): readonly string[] {
|
|||||||
|
|
||||||
export function getBotRuntimeConfig(env: NodeJS.ProcessEnv = process.env): BotRuntimeConfig {
|
export function getBotRuntimeConfig(env: NodeJS.ProcessEnv = process.env): BotRuntimeConfig {
|
||||||
const databaseUrl = parseOptionalValue(env.DATABASE_URL)
|
const databaseUrl = parseOptionalValue(env.DATABASE_URL)
|
||||||
const telegramHouseholdChatId = parseOptionalValue(env.TELEGRAM_HOUSEHOLD_CHAT_ID)
|
|
||||||
const telegramPurchaseTopicId = parseOptionalTopicId(env.TELEGRAM_PURCHASE_TOPIC_ID)
|
|
||||||
const telegramFeedbackTopicId = parseOptionalTopicId(env.TELEGRAM_FEEDBACK_TOPIC_ID)
|
|
||||||
const schedulerSharedSecret = parseOptionalValue(env.SCHEDULER_SHARED_SECRET)
|
const schedulerSharedSecret = parseOptionalValue(env.SCHEDULER_SHARED_SECRET)
|
||||||
const schedulerOidcAllowedEmails = parseOptionalCsv(env.SCHEDULER_OIDC_ALLOWED_EMAILS)
|
const schedulerOidcAllowedEmails = parseOptionalCsv(env.SCHEDULER_OIDC_ALLOWED_EMAILS)
|
||||||
const miniAppAllowedOrigins = parseOptionalCsv(env.MINI_APP_ALLOWED_ORIGINS)
|
const miniAppAllowedOrigins = parseOptionalCsv(env.MINI_APP_ALLOWED_ORIGINS)
|
||||||
@@ -128,15 +109,6 @@ export function getBotRuntimeConfig(env: NodeJS.ProcessEnv = process.env): BotRu
|
|||||||
if (databaseUrl !== undefined) {
|
if (databaseUrl !== undefined) {
|
||||||
runtime.databaseUrl = databaseUrl
|
runtime.databaseUrl = databaseUrl
|
||||||
}
|
}
|
||||||
if (telegramHouseholdChatId !== undefined) {
|
|
||||||
runtime.telegramHouseholdChatId = telegramHouseholdChatId
|
|
||||||
}
|
|
||||||
if (telegramPurchaseTopicId !== undefined) {
|
|
||||||
runtime.telegramPurchaseTopicId = telegramPurchaseTopicId
|
|
||||||
}
|
|
||||||
if (telegramFeedbackTopicId !== undefined) {
|
|
||||||
runtime.telegramFeedbackTopicId = telegramFeedbackTopicId
|
|
||||||
}
|
|
||||||
if (schedulerSharedSecret !== undefined) {
|
if (schedulerSharedSecret !== undefined) {
|
||||||
runtime.schedulerSharedSecret = schedulerSharedSecret
|
runtime.schedulerSharedSecret = schedulerSharedSecret
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,23 +25,20 @@ Required in your environment `*.tfvars`:
|
|||||||
- `environment`
|
- `environment`
|
||||||
- `bot_api_image`
|
- `bot_api_image`
|
||||||
- `mini_app_image`
|
- `mini_app_image`
|
||||||
- `bot_household_id`
|
|
||||||
- `bot_household_chat_id`
|
|
||||||
- `bot_purchase_topic_id`
|
|
||||||
|
|
||||||
Recommended:
|
Recommended:
|
||||||
|
|
||||||
- `database_url_secret_id = "database-url"`
|
- `database_url_secret_id = "database-url"`
|
||||||
- `telegram_bot_token_secret_id = "telegram-bot-token"`
|
- `telegram_bot_token_secret_id = "telegram-bot-token"`
|
||||||
- `openai_api_key_secret_id = "openai-api-key"`
|
- `openai_api_key_secret_id = "openai-api-key"`
|
||||||
- optional `supabase_url_secret_id = "supabase-url"`
|
|
||||||
- optional `supabase_publishable_key_secret_id = "supabase-publishable-key"`
|
|
||||||
- `bot_feedback_topic_id`
|
|
||||||
- `bot_mini_app_allowed_origins`
|
- `bot_mini_app_allowed_origins`
|
||||||
- `scheduler_timezone`
|
- `scheduler_timezone`
|
||||||
- `scheduler_paused = true`
|
- `scheduler_paused = true`
|
||||||
- `scheduler_dry_run = true`
|
- `scheduler_dry_run = true`
|
||||||
|
|
||||||
|
Household chat/topic bindings are no longer deployment config. Configure them in Telegram with
|
||||||
|
`/setup`, `/bind_purchase_topic`, `/bind_feedback_topic`, and `/bind_payments_topic` after deploy.
|
||||||
|
|
||||||
### Secret Manager values
|
### Secret Manager values
|
||||||
|
|
||||||
Create the secret resources via Terraform, then add secret versions for:
|
Create the secret resources via Terraform, then add secret versions for:
|
||||||
|
|||||||
@@ -54,10 +54,6 @@ If `create_workload_identity = true`, Terraform also grants the GitHub deploy se
|
|||||||
|
|
||||||
Keep bot runtime config that is not secret in your `*.tfvars` file:
|
Keep bot runtime config that is not secret in your `*.tfvars` file:
|
||||||
|
|
||||||
- `bot_household_id`
|
|
||||||
- `bot_household_chat_id`
|
|
||||||
- `bot_purchase_topic_id`
|
|
||||||
- optional `bot_feedback_topic_id`
|
|
||||||
- `bot_mini_app_allowed_origins`
|
- `bot_mini_app_allowed_origins`
|
||||||
- optional `bot_parser_model`
|
- optional `bot_parser_model`
|
||||||
|
|
||||||
|
|||||||
@@ -72,10 +72,6 @@ Recommended approach:
|
|||||||
- Use `terraform.tfvars` per environment (`dev.tfvars`, `prod.tfvars`)
|
- Use `terraform.tfvars` per environment (`dev.tfvars`, `prod.tfvars`)
|
||||||
- Keep `project_id` separate for dev/prod when possible
|
- Keep `project_id` separate for dev/prod when possible
|
||||||
- Keep non-secret bot config in `*.tfvars`:
|
- Keep non-secret bot config in `*.tfvars`:
|
||||||
- `bot_household_id`
|
|
||||||
- `bot_household_chat_id`
|
|
||||||
- `bot_purchase_topic_id`
|
|
||||||
- optional `bot_feedback_topic_id`
|
|
||||||
- optional `bot_parser_model`
|
- optional `bot_parser_model`
|
||||||
- optional `bot_mini_app_allowed_origins`
|
- optional `bot_mini_app_allowed_origins`
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ locals {
|
|||||||
runtime_secret_ids = toset(compact([
|
runtime_secret_ids = toset(compact([
|
||||||
var.telegram_webhook_secret_id,
|
var.telegram_webhook_secret_id,
|
||||||
var.scheduler_shared_secret_id,
|
var.scheduler_shared_secret_id,
|
||||||
var.supabase_url_secret_id,
|
|
||||||
var.supabase_publishable_key_secret_id,
|
|
||||||
var.database_url_secret_id,
|
var.database_url_secret_id,
|
||||||
var.telegram_bot_token_secret_id,
|
var.telegram_bot_token_secret_id,
|
||||||
var.openai_api_key_secret_id
|
var.openai_api_key_secret_id
|
||||||
|
|||||||
@@ -90,18 +90,6 @@ module "bot_api_service" {
|
|||||||
{
|
{
|
||||||
NODE_ENV = var.environment
|
NODE_ENV = var.environment
|
||||||
},
|
},
|
||||||
var.bot_household_id == null ? {} : {
|
|
||||||
HOUSEHOLD_ID = var.bot_household_id
|
|
||||||
},
|
|
||||||
var.bot_household_chat_id == null ? {} : {
|
|
||||||
TELEGRAM_HOUSEHOLD_CHAT_ID = var.bot_household_chat_id
|
|
||||||
},
|
|
||||||
var.bot_purchase_topic_id == null ? {} : {
|
|
||||||
TELEGRAM_PURCHASE_TOPIC_ID = tostring(var.bot_purchase_topic_id)
|
|
||||||
},
|
|
||||||
var.bot_feedback_topic_id == null ? {} : {
|
|
||||||
TELEGRAM_FEEDBACK_TOPIC_ID = tostring(var.bot_feedback_topic_id)
|
|
||||||
},
|
|
||||||
var.bot_parser_model == null ? {} : {
|
var.bot_parser_model == null ? {} : {
|
||||||
PARSER_MODEL = var.bot_parser_model
|
PARSER_MODEL = var.bot_parser_model
|
||||||
},
|
},
|
||||||
@@ -118,12 +106,6 @@ module "bot_api_service" {
|
|||||||
TELEGRAM_WEBHOOK_SECRET = var.telegram_webhook_secret_id
|
TELEGRAM_WEBHOOK_SECRET = var.telegram_webhook_secret_id
|
||||||
SCHEDULER_SHARED_SECRET = var.scheduler_shared_secret_id
|
SCHEDULER_SHARED_SECRET = var.scheduler_shared_secret_id
|
||||||
},
|
},
|
||||||
var.supabase_url_secret_id == null ? {} : {
|
|
||||||
SUPABASE_URL = var.supabase_url_secret_id
|
|
||||||
},
|
|
||||||
var.supabase_publishable_key_secret_id == null ? {} : {
|
|
||||||
SUPABASE_PUBLISHABLE_KEY = var.supabase_publishable_key_secret_id
|
|
||||||
},
|
|
||||||
var.database_url_secret_id == null ? {} : {
|
var.database_url_secret_id == null ? {} : {
|
||||||
DATABASE_URL = var.database_url_secret_id
|
DATABASE_URL = var.database_url_secret_id
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,13 +11,6 @@ mini_app_image = "europe-west1-docker.pkg.dev/my-gcp-project/household-bot/mini
|
|||||||
database_url_secret_id = "database-url"
|
database_url_secret_id = "database-url"
|
||||||
telegram_bot_token_secret_id = "telegram-bot-token"
|
telegram_bot_token_secret_id = "telegram-bot-token"
|
||||||
openai_api_key_secret_id = "openai-api-key"
|
openai_api_key_secret_id = "openai-api-key"
|
||||||
# supabase_url_secret_id = "supabase-url"
|
|
||||||
# supabase_publishable_key_secret_id = "supabase-publishable-key"
|
|
||||||
|
|
||||||
bot_household_id = "11111111-1111-4111-8111-111111111111"
|
|
||||||
bot_household_chat_id = "-1001234567890"
|
|
||||||
bot_purchase_topic_id = 777
|
|
||||||
bot_feedback_topic_id = 778
|
|
||||||
bot_parser_model = "gpt-4.1-mini"
|
bot_parser_model = "gpt-4.1-mini"
|
||||||
bot_mini_app_allowed_origins = [
|
bot_mini_app_allowed_origins = [
|
||||||
"https://household-dev-mini-app-abc123-ew.a.run.app"
|
"https://household-dev-mini-app-abc123-ew.a.run.app"
|
||||||
|
|||||||
@@ -56,20 +56,6 @@ variable "scheduler_shared_secret_id" {
|
|||||||
default = "scheduler-shared-secret"
|
default = "scheduler-shared-secret"
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "supabase_url_secret_id" {
|
|
||||||
description = "Optional Secret Manager ID for SUPABASE_URL"
|
|
||||||
type = string
|
|
||||||
default = null
|
|
||||||
nullable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "supabase_publishable_key_secret_id" {
|
|
||||||
description = "Optional Secret Manager ID for SUPABASE_PUBLISHABLE_KEY"
|
|
||||||
type = string
|
|
||||||
default = null
|
|
||||||
nullable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "database_url_secret_id" {
|
variable "database_url_secret_id" {
|
||||||
description = "Optional Secret Manager ID for DATABASE_URL"
|
description = "Optional Secret Manager ID for DATABASE_URL"
|
||||||
type = string
|
type = string
|
||||||
@@ -83,34 +69,6 @@ variable "telegram_bot_token_secret_id" {
|
|||||||
default = "telegram-bot-token"
|
default = "telegram-bot-token"
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "bot_household_id" {
|
|
||||||
description = "Optional HOUSEHOLD_ID value for bot runtime"
|
|
||||||
type = string
|
|
||||||
default = null
|
|
||||||
nullable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "bot_household_chat_id" {
|
|
||||||
description = "Optional TELEGRAM_HOUSEHOLD_CHAT_ID value for bot runtime"
|
|
||||||
type = string
|
|
||||||
default = null
|
|
||||||
nullable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "bot_purchase_topic_id" {
|
|
||||||
description = "Optional TELEGRAM_PURCHASE_TOPIC_ID value for bot runtime"
|
|
||||||
type = number
|
|
||||||
default = null
|
|
||||||
nullable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "bot_feedback_topic_id" {
|
|
||||||
description = "Optional TELEGRAM_FEEDBACK_TOPIC_ID value for bot runtime"
|
|
||||||
type = number
|
|
||||||
default = null
|
|
||||||
nullable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "bot_parser_model" {
|
variable "bot_parser_model" {
|
||||||
description = "Optional PARSER_MODEL override for bot runtime"
|
description = "Optional PARSER_MODEL override for bot runtime"
|
||||||
type = string
|
type = string
|
||||||
|
|||||||
@@ -19,16 +19,9 @@ const server = {
|
|||||||
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
||||||
PORT: z.coerce.number().int().min(1).max(65535).default(3000),
|
PORT: z.coerce.number().int().min(1).max(65535).default(3000),
|
||||||
DATABASE_URL: z.string().url(),
|
DATABASE_URL: z.string().url(),
|
||||||
HOUSEHOLD_ID: z.string().uuid().optional(),
|
|
||||||
SUPABASE_URL: z.string().url().optional(),
|
|
||||||
SUPABASE_PUBLISHABLE_KEY: z.string().min(1).optional(),
|
|
||||||
SUPABASE_SERVICE_ROLE_KEY: z.string().min(1).optional(),
|
|
||||||
TELEGRAM_BOT_TOKEN: z.string().min(1),
|
TELEGRAM_BOT_TOKEN: z.string().min(1),
|
||||||
TELEGRAM_WEBHOOK_SECRET: z.string().min(1),
|
TELEGRAM_WEBHOOK_SECRET: z.string().min(1),
|
||||||
TELEGRAM_WEBHOOK_PATH: z.string().min(1).default('/webhook/telegram'),
|
TELEGRAM_WEBHOOK_PATH: z.string().min(1).default('/webhook/telegram'),
|
||||||
TELEGRAM_HOUSEHOLD_CHAT_ID: z.string().min(1).optional(),
|
|
||||||
TELEGRAM_PURCHASE_TOPIC_ID: z.coerce.number().int().positive().optional(),
|
|
||||||
TELEGRAM_FEEDBACK_TOPIC_ID: z.coerce.number().int().positive().optional(),
|
|
||||||
MINI_APP_ALLOWED_ORIGINS: z
|
MINI_APP_ALLOWED_ORIGINS: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
@@ -39,10 +32,6 @@ const server = {
|
|||||||
.transform((value) => parseOptionalCsv(value)),
|
.transform((value) => parseOptionalCsv(value)),
|
||||||
OPENAI_API_KEY: z.string().min(1).optional(),
|
OPENAI_API_KEY: z.string().min(1).optional(),
|
||||||
PARSER_MODEL: z.string().min(1).default('gpt-4.1-mini'),
|
PARSER_MODEL: z.string().min(1).default('gpt-4.1-mini'),
|
||||||
SENTRY_DSN: z.string().url().optional(),
|
|
||||||
GCP_PROJECT_ID: z.string().min(1).optional(),
|
|
||||||
GCP_REGION: z.string().min(1).default('europe-west1'),
|
|
||||||
CLOUD_RUN_SERVICE_BOT: z.string().min(1).default('household-bot'),
|
|
||||||
SCHEDULER_SHARED_SECRET: z.string().min(1).optional()
|
SCHEDULER_SHARED_SECRET: z.string().min(1).optional()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user