mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 12:04:02 +00:00
feat(bot): add /dashboard command and MINI_APP_URL config
- Add /dashboard command to BotFather registration alongside /app - Add new MINI_APP_URL env var for dashboard URL (separate from CORS origins) - Pass MINI_APP_URL and BOT_API_URL in CD workflow - Update Terraform with new variable for future infrastructure deployments
This commit is contained in:
@@ -13,6 +13,9 @@ TELEGRAM_WEBHOOK_SECRET=your-webhook-secret
|
|||||||
TELEGRAM_WEBHOOK_PATH=/webhook/telegram
|
TELEGRAM_WEBHOOK_PATH=/webhook/telegram
|
||||||
|
|
||||||
# Mini app
|
# Mini app
|
||||||
|
# URL for /app and /dashboard commands (e.g., https://your-app.cloud.run)
|
||||||
|
MINI_APP_URL=https://your-miniapp-domain.com
|
||||||
|
# CORS origins for mini app API (comma-separated)
|
||||||
MINI_APP_ALLOWED_ORIGINS=http://localhost:5173
|
MINI_APP_ALLOWED_ORIGINS=http://localhost:5173
|
||||||
|
|
||||||
# Parsing / AI
|
# Parsing / AI
|
||||||
|
|||||||
6
.github/workflows/cd.yml
vendored
6
.github/workflows/cd.yml
vendored
@@ -234,15 +234,18 @@ jobs:
|
|||||||
} >> "$GITHUB_OUTPUT"
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Deploy bot service
|
- name: Deploy bot service
|
||||||
|
id: bot-api
|
||||||
run: |
|
run: |
|
||||||
gcloud run deploy "household-${SERVICE_SUFFIX}-bot-api" \
|
gcloud run deploy "household-${SERVICE_SUFFIX}-bot-api" \
|
||||||
--image "${{ steps.images.outputs.bot_image }}" \
|
--image "${{ steps.images.outputs.bot_image }}" \
|
||||||
--region "${GCP_REGION}" \
|
--region "${GCP_REGION}" \
|
||||||
--project "${{ vars.GCP_PROJECT_ID }}" \
|
--project "${{ vars.GCP_PROJECT_ID }}" \
|
||||||
--set-env-vars "DB_SCHEMA=${DB_SCHEMA}" \
|
--set-env-vars "DB_SCHEMA=${DB_SCHEMA},MINI_APP_URL=${{ vars.MINI_APP_URL }}" \
|
||||||
--allow-unauthenticated \
|
--allow-unauthenticated \
|
||||||
--quiet
|
--quiet
|
||||||
|
|
||||||
|
echo "url=$(gcloud run services describe "household-${SERVICE_SUFFIX}-bot-api" --region "${GCP_REGION}" --project "${{ vars.GCP_PROJECT_ID }}" --format 'value(status.url)')" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Route traffic to latest bot revision
|
- name: Route traffic to latest bot revision
|
||||||
run: |
|
run: |
|
||||||
gcloud run services update-traffic "household-${SERVICE_SUFFIX}-bot-api" \
|
gcloud run services update-traffic "household-${SERVICE_SUFFIX}-bot-api" \
|
||||||
@@ -257,6 +260,7 @@ jobs:
|
|||||||
--image "${{ steps.images.outputs.mini_image }}" \
|
--image "${{ steps.images.outputs.mini_image }}" \
|
||||||
--region "${GCP_REGION}" \
|
--region "${GCP_REGION}" \
|
||||||
--project "${{ vars.GCP_PROJECT_ID }}" \
|
--project "${{ vars.GCP_PROJECT_ID }}" \
|
||||||
|
--set-env-vars "BOT_API_URL=${{ steps.bot-api.outputs.url }}" \
|
||||||
--allow-unauthenticated \
|
--allow-unauthenticated \
|
||||||
--quiet
|
--quiet
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface BotRuntimeConfig {
|
|||||||
assistantRateLimitBurstWindowMs: number
|
assistantRateLimitBurstWindowMs: number
|
||||||
assistantRateLimitRolling: number
|
assistantRateLimitRolling: number
|
||||||
assistantRateLimitRollingWindowMs: number
|
assistantRateLimitRollingWindowMs: number
|
||||||
|
miniAppUrl?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePort(raw: string | undefined): number {
|
function parsePort(raw: string | undefined): number {
|
||||||
@@ -103,6 +104,7 @@ export function getBotRuntimeConfig(env: NodeJS.ProcessEnv = process.env): BotRu
|
|||||||
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)
|
||||||
|
const miniAppUrl = parseOptionalValue(env.MINI_APP_URL)
|
||||||
|
|
||||||
const purchaseTopicIngestionEnabled = databaseUrl !== undefined
|
const purchaseTopicIngestionEnabled = databaseUrl !== undefined
|
||||||
|
|
||||||
@@ -174,6 +176,9 @@ export function getBotRuntimeConfig(env: NodeJS.ProcessEnv = process.env): BotRu
|
|||||||
if (schedulerSharedSecret !== undefined) {
|
if (schedulerSharedSecret !== undefined) {
|
||||||
runtime.schedulerSharedSecret = schedulerSharedSecret
|
runtime.schedulerSharedSecret = schedulerSharedSecret
|
||||||
}
|
}
|
||||||
|
if (miniAppUrl !== undefined) {
|
||||||
|
runtime.miniAppUrl = miniAppUrl
|
||||||
|
}
|
||||||
const openaiApiKey = parseOptionalValue(env.OPENAI_API_KEY)
|
const openaiApiKey = parseOptionalValue(env.OPENAI_API_KEY)
|
||||||
if (openaiApiKey !== undefined) {
|
if (openaiApiKey !== undefined) {
|
||||||
runtime.openaiApiKey = openaiApiKey
|
runtime.openaiApiKey = openaiApiKey
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export const enBotTranslations: BotTranslationCatalog = {
|
|||||||
pending_members: 'List pending household join requests',
|
pending_members: 'List pending household join requests',
|
||||||
approve_member: 'Approve a pending household member',
|
approve_member: 'Approve a pending household member',
|
||||||
app: 'Open the Kojori mini app',
|
app: 'Open the Kojori mini app',
|
||||||
|
dashboard: 'Open the household dashboard',
|
||||||
keyboard: 'Toggle persistent dashboard button'
|
keyboard: 'Toggle persistent dashboard button'
|
||||||
},
|
},
|
||||||
help: {
|
help: {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export const ruBotTranslations: BotTranslationCatalog = {
|
|||||||
pending_members: 'Показать ожидающие заявки на вступление',
|
pending_members: 'Показать ожидающие заявки на вступление',
|
||||||
approve_member: 'Подтвердить участника дома',
|
approve_member: 'Подтвердить участника дома',
|
||||||
app: 'Открыть мини-приложение Kojori',
|
app: 'Открыть мини-приложение Kojori',
|
||||||
|
dashboard: 'Открыть дашборд дома',
|
||||||
keyboard: 'Вкл/выкл кнопку дашборда'
|
keyboard: 'Вкл/выкл кнопку дашборда'
|
||||||
},
|
},
|
||||||
help: {
|
help: {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export type TelegramCommandName =
|
|||||||
| 'pending_members'
|
| 'pending_members'
|
||||||
| 'approve_member'
|
| 'approve_member'
|
||||||
| 'app'
|
| 'app'
|
||||||
|
| 'dashboard'
|
||||||
| 'keyboard'
|
| 'keyboard'
|
||||||
|
|
||||||
export interface BotCommandDescriptions {
|
export interface BotCommandDescriptions {
|
||||||
@@ -28,6 +29,7 @@ export interface BotCommandDescriptions {
|
|||||||
pending_members: string
|
pending_members: string
|
||||||
approve_member: string
|
approve_member: string
|
||||||
app: string
|
app: string
|
||||||
|
dashboard: string
|
||||||
keyboard: string
|
keyboard: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -313,7 +313,13 @@ if (purchaseRepositoryClient && householdConfigurationRepositoryClient) {
|
|||||||
if (runtime.financeCommandsEnabled) {
|
if (runtime.financeCommandsEnabled) {
|
||||||
const financeCommands = createFinanceCommandsService({
|
const financeCommands = createFinanceCommandsService({
|
||||||
householdConfigurationRepository: householdConfigurationRepositoryClient!.repository,
|
householdConfigurationRepository: householdConfigurationRepositoryClient!.repository,
|
||||||
financeServiceForHousehold
|
financeServiceForHousehold,
|
||||||
|
...(runtime.miniAppUrl
|
||||||
|
? {
|
||||||
|
miniAppUrl: runtime.miniAppUrl,
|
||||||
|
botUsername: bot.botInfo?.username
|
||||||
|
}
|
||||||
|
: {})
|
||||||
})
|
})
|
||||||
|
|
||||||
financeCommands.register(bot)
|
financeCommands.register(bot)
|
||||||
@@ -343,9 +349,9 @@ if (householdConfigurationRepositoryClient) {
|
|||||||
promptRepository: telegramPendingActionRepositoryClient.repository
|
promptRepository: telegramPendingActionRepositoryClient.repository
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
...(runtime.miniAppAllowedOrigins[0]
|
...(runtime.miniAppUrl
|
||||||
? {
|
? {
|
||||||
miniAppUrl: runtime.miniAppAllowedOrigins[0]
|
miniAppUrl: runtime.miniAppUrl
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
logger: getLogger('household-setup')
|
logger: getLogger('household-setup')
|
||||||
@@ -399,9 +405,9 @@ const reminderJobs = runtime.reminderJobsEnabled
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
reminderService,
|
reminderService,
|
||||||
...(runtime.miniAppAllowedOrigins[0]
|
...(runtime.miniAppUrl
|
||||||
? {
|
? {
|
||||||
miniAppUrl: runtime.miniAppAllowedOrigins[0]
|
miniAppUrl: runtime.miniAppUrl
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
...(bot.botInfo?.username
|
...(bot.botInfo?.username
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ const DEFAULT_COMMAND_NAMES = [
|
|||||||
const PRIVATE_CHAT_COMMAND_NAMES = [
|
const PRIVATE_CHAT_COMMAND_NAMES = [
|
||||||
...DEFAULT_COMMAND_NAMES,
|
...DEFAULT_COMMAND_NAMES,
|
||||||
'anon',
|
'anon',
|
||||||
'cancel'
|
'cancel',
|
||||||
|
'app',
|
||||||
|
'dashboard'
|
||||||
] as const satisfies readonly TelegramCommandName[]
|
] as const satisfies readonly TelegramCommandName[]
|
||||||
const GROUP_CHAT_COMMAND_NAMES = DEFAULT_COMMAND_NAMES
|
const GROUP_CHAT_COMMAND_NAMES = DEFAULT_COMMAND_NAMES
|
||||||
const GROUP_MEMBER_COMMAND_NAMES = [
|
const GROUP_MEMBER_COMMAND_NAMES = [
|
||||||
|
|||||||
@@ -166,6 +166,9 @@ module "bot_api_service" {
|
|||||||
length(var.bot_mini_app_allowed_origins) == 0 ? {} : {
|
length(var.bot_mini_app_allowed_origins) == 0 ? {} : {
|
||||||
MINI_APP_ALLOWED_ORIGINS = join(",", var.bot_mini_app_allowed_origins)
|
MINI_APP_ALLOWED_ORIGINS = join(",", var.bot_mini_app_allowed_origins)
|
||||||
},
|
},
|
||||||
|
var.bot_mini_app_url == null ? {} : {
|
||||||
|
MINI_APP_URL = var.bot_mini_app_url
|
||||||
|
},
|
||||||
{
|
{
|
||||||
SCHEDULER_OIDC_ALLOWED_EMAILS = google_service_account.scheduler_invoker.email
|
SCHEDULER_OIDC_ALLOWED_EMAILS = google_service_account.scheduler_invoker.email
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ bot_assistant_rate_limit_burst = 5
|
|||||||
bot_assistant_rate_limit_burst_window_ms = 60000
|
bot_assistant_rate_limit_burst_window_ms = 60000
|
||||||
bot_assistant_rate_limit_rolling = 50
|
bot_assistant_rate_limit_rolling = 50
|
||||||
bot_assistant_rate_limit_rolling_window_ms = 86400000
|
bot_assistant_rate_limit_rolling_window_ms = 86400000
|
||||||
|
bot_mini_app_url = "https://household-dev-mini-app-abc123-ew.a.run.app"
|
||||||
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"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -139,6 +139,13 @@ variable "bot_assistant_rate_limit_rolling_window_ms" {
|
|||||||
nullable = true
|
nullable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "bot_mini_app_url" {
|
||||||
|
description = "Optional URL for /app and /dashboard bot commands"
|
||||||
|
type = string
|
||||||
|
default = null
|
||||||
|
nullable = true
|
||||||
|
}
|
||||||
|
|
||||||
variable "bot_mini_app_allowed_origins" {
|
variable "bot_mini_app_allowed_origins" {
|
||||||
description = "Optional allow-list of mini app origins for bot CORS handling"
|
description = "Optional allow-list of mini app origins for bot CORS handling"
|
||||||
type = list(string)
|
type = list(string)
|
||||||
|
|||||||
Reference in New Issue
Block a user