mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 12:04:02 +00:00
feat(bot): add multi-household setup flow
This commit is contained in:
27
packages/db/drizzle/0005_free_kang.sql
Normal file
27
packages/db/drizzle/0005_free_kang.sql
Normal file
@@ -0,0 +1,27 @@
|
||||
CREATE TABLE "household_telegram_chats" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"household_id" uuid NOT NULL,
|
||||
"telegram_chat_id" text NOT NULL,
|
||||
"telegram_chat_type" text NOT NULL,
|
||||
"title" text,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "household_topic_bindings" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"household_id" uuid NOT NULL,
|
||||
"role" text NOT NULL,
|
||||
"telegram_thread_id" text NOT NULL,
|
||||
"topic_name" text,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "household_telegram_chats" ADD CONSTRAINT "household_telegram_chats_household_id_households_id_fk" FOREIGN KEY ("household_id") REFERENCES "public"."households"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "household_topic_bindings" ADD CONSTRAINT "household_topic_bindings_household_id_households_id_fk" FOREIGN KEY ("household_id") REFERENCES "public"."households"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "household_telegram_chats_household_unique" ON "household_telegram_chats" USING btree ("household_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "household_telegram_chats_chat_unique" ON "household_telegram_chats" USING btree ("telegram_chat_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "household_topic_bindings_household_role_unique" ON "household_topic_bindings" USING btree ("household_id","role");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "household_topic_bindings_household_thread_unique" ON "household_topic_bindings" USING btree ("household_id","telegram_thread_id");--> statement-breakpoint
|
||||
CREATE INDEX "household_topic_bindings_household_role_idx" ON "household_topic_bindings" USING btree ("household_id","role");
|
||||
1818
packages/db/drizzle/meta/0005_snapshot.json
Normal file
1818
packages/db/drizzle/meta/0005_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,13 @@
|
||||
"when": 1772995779819,
|
||||
"tag": "0004_big_ultimatum",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 5,
|
||||
"version": "7",
|
||||
"when": 1773012360748,
|
||||
"tag": "0005_free_kang",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -18,6 +18,54 @@ export const households = pgTable('households', {
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull()
|
||||
})
|
||||
|
||||
export const householdTelegramChats = pgTable(
|
||||
'household_telegram_chats',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
householdId: uuid('household_id')
|
||||
.notNull()
|
||||
.references(() => households.id, { onDelete: 'cascade' }),
|
||||
telegramChatId: text('telegram_chat_id').notNull(),
|
||||
telegramChatType: text('telegram_chat_type').notNull(),
|
||||
title: text('title'),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
|
||||
},
|
||||
(table) => ({
|
||||
householdUnique: uniqueIndex('household_telegram_chats_household_unique').on(table.householdId),
|
||||
chatUnique: uniqueIndex('household_telegram_chats_chat_unique').on(table.telegramChatId)
|
||||
})
|
||||
)
|
||||
|
||||
export const householdTopicBindings = pgTable(
|
||||
'household_topic_bindings',
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
householdId: uuid('household_id')
|
||||
.notNull()
|
||||
.references(() => households.id, { onDelete: 'cascade' }),
|
||||
role: text('role').notNull(),
|
||||
telegramThreadId: text('telegram_thread_id').notNull(),
|
||||
topicName: text('topic_name'),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
|
||||
},
|
||||
(table) => ({
|
||||
householdRoleUnique: uniqueIndex('household_topic_bindings_household_role_unique').on(
|
||||
table.householdId,
|
||||
table.role
|
||||
),
|
||||
householdThreadUnique: uniqueIndex('household_topic_bindings_household_thread_unique').on(
|
||||
table.householdId,
|
||||
table.telegramThreadId
|
||||
),
|
||||
householdRoleIdx: index('household_topic_bindings_household_role_idx').on(
|
||||
table.householdId,
|
||||
table.role
|
||||
)
|
||||
})
|
||||
)
|
||||
|
||||
export const members = pgTable(
|
||||
'members',
|
||||
{
|
||||
@@ -343,6 +391,8 @@ export const settlementLines = pgTable(
|
||||
)
|
||||
|
||||
export type Household = typeof households.$inferSelect
|
||||
export type HouseholdTelegramChat = typeof householdTelegramChats.$inferSelect
|
||||
export type HouseholdTopicBinding = typeof householdTopicBindings.$inferSelect
|
||||
export type Member = typeof members.$inferSelect
|
||||
export type BillingCycle = typeof billingCycles.$inferSelect
|
||||
export type UtilityBill = typeof utilityBills.$inferSelect
|
||||
|
||||
@@ -2,6 +2,8 @@ import { and, eq } from 'drizzle-orm'
|
||||
import { createDbClient } from './client'
|
||||
import {
|
||||
billingCycles,
|
||||
householdTelegramChats,
|
||||
householdTopicBindings,
|
||||
households,
|
||||
members,
|
||||
presenceOverrides,
|
||||
@@ -68,6 +70,34 @@ async function seed(): Promise<void> {
|
||||
])
|
||||
.onConflictDoNothing()
|
||||
|
||||
await db
|
||||
.insert(householdTelegramChats)
|
||||
.values({
|
||||
householdId: FIXTURE_IDS.household,
|
||||
telegramChatId: '-1001234567890',
|
||||
telegramChatType: 'supergroup',
|
||||
title: 'Kojori Demo Household'
|
||||
})
|
||||
.onConflictDoNothing()
|
||||
|
||||
await db
|
||||
.insert(householdTopicBindings)
|
||||
.values([
|
||||
{
|
||||
householdId: FIXTURE_IDS.household,
|
||||
role: 'purchase',
|
||||
telegramThreadId: '777',
|
||||
topicName: 'Общие покупки'
|
||||
},
|
||||
{
|
||||
householdId: FIXTURE_IDS.household,
|
||||
role: 'feedback',
|
||||
telegramThreadId: '778',
|
||||
topicName: 'Anonymous feedback'
|
||||
}
|
||||
])
|
||||
.onConflictDoNothing()
|
||||
|
||||
await db
|
||||
.insert(billingCycles)
|
||||
.values({
|
||||
@@ -212,6 +242,16 @@ async function seed(): Promise<void> {
|
||||
if (seededCycle.length === 0) {
|
||||
throw new Error('Seed verification failed: billing cycle not found')
|
||||
}
|
||||
|
||||
const seededChat = await db
|
||||
.select({ telegramChatId: householdTelegramChats.telegramChatId })
|
||||
.from(householdTelegramChats)
|
||||
.where(eq(householdTelegramChats.householdId, FIXTURE_IDS.household))
|
||||
.limit(1)
|
||||
|
||||
if (seededChat.length === 0) {
|
||||
throw new Error('Seed verification failed: Telegram household chat not found')
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user