mirror of
https://github.com/d0zingcat/alert-message-center.git
synced 2026-05-21 23:16:49 +00:00
103 lines
4.0 KiB
TypeScript
103 lines
4.0 KiB
TypeScript
import { pgTable, text, integer, primaryKey, boolean, jsonb, timestamp } from 'drizzle-orm/pg-core';
|
||
import { relations } from 'drizzle-orm';
|
||
|
||
// Topics: 类似于 Kafka 的 Topic 或 告警的 Tag,例如 "payment-service", "prod-env"
|
||
export const topics = pgTable('topics', {
|
||
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
|
||
slug: text('slug').notNull().unique(), // 告警发送时使用的 key
|
||
name: text('name').notNull(),
|
||
description: text('description'),
|
||
status: text('status', { enum: ['pending', 'approved', 'rejected'] }).default('approved').notNull(),
|
||
createdBy: text('created_by').references(() => users.id),
|
||
approvedBy: text('approved_by').references(() => users.id),
|
||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||
});
|
||
|
||
export const topicsRelations = relations(topics, ({ many, one }) => ({
|
||
subscriptions: many(subscriptions),
|
||
creator: one(users, {
|
||
fields: [topics.createdBy],
|
||
references: [users.id],
|
||
relationName: 'creator',
|
||
}),
|
||
approver: one(users, {
|
||
fields: [topics.approvedBy],
|
||
references: [users.id],
|
||
relationName: 'approver',
|
||
}),
|
||
}));
|
||
|
||
export const users = pgTable('users', {
|
||
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
|
||
name: text('name').notNull(),
|
||
feishuUserId: text('feishu_user_id').notNull(), // 必须有飞书 ID 才能私聊 (open_id 或 user_id)
|
||
email: text('email').unique(),
|
||
isAdmin: boolean('is_admin').default(false),
|
||
personalToken: text('personal_token').notNull().unique().$defaultFn(() => crypto.randomUUID().replace(/-/g, '')),
|
||
});
|
||
|
||
export const usersRelations = relations(users, ({ many }) => ({
|
||
subscriptions: many(subscriptions),
|
||
createdTopics: many(topics, { relationName: 'creator' }),
|
||
approvedTopics: many(topics, { relationName: 'approver' }),
|
||
}));
|
||
|
||
// Subscriptions: 用户直接订阅 Topic
|
||
export const subscriptions = pgTable('subscriptions', {
|
||
userId: text('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
|
||
topicId: text('topic_id').notNull().references(() => topics.id, { onDelete: 'cascade' }),
|
||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||
}, (t) => ({
|
||
pk: primaryKey({ columns: [t.userId, t.topicId] }),
|
||
}));
|
||
|
||
export const subscriptionsRelations = relations(subscriptions, ({ one }) => ({
|
||
user: one(users, {
|
||
fields: [subscriptions.userId],
|
||
references: [users.id],
|
||
}),
|
||
topic: one(topics, {
|
||
fields: [subscriptions.topicId],
|
||
references: [topics.id],
|
||
}),
|
||
}));
|
||
|
||
// API Tasks: 记录 webhook 请求的处理状态
|
||
export const alertTasks = pgTable('alert_tasks', {
|
||
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
|
||
topicSlug: text('topic_slug'),
|
||
senderId: text('sender_id').references(() => users.id), // 记录是谁发送的 (通过 personal_token)
|
||
status: text('status', { enum: ['pending', 'processing', 'completed', 'failed'] }).default('pending').notNull(),
|
||
recipientCount: integer('recipient_count').default(0),
|
||
successCount: integer('success_count').default(0),
|
||
payload: jsonb('payload'), // 存储 webhook body
|
||
error: text('error'),
|
||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||
updatedAt: timestamp('updated_at').defaultNow().notNull(),
|
||
});
|
||
|
||
// Logs for each recipient in a task (optional detail)
|
||
export const alertLogs = pgTable('alert_logs', {
|
||
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
|
||
taskId: text('task_id').notNull().references(() => alertTasks.id, { onDelete: 'cascade' }),
|
||
userId: text('user_id'), // Optional, in case user is deleted later
|
||
status: text('status', { enum: ['sent', 'failed'] }).notNull(),
|
||
error: text('error'),
|
||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||
});
|
||
|
||
export const alertTasksRelations = relations(alertTasks, ({ many, one }) => ({
|
||
logs: many(alertLogs),
|
||
sender: one(users, {
|
||
fields: [alertTasks.senderId],
|
||
references: [users.id],
|
||
}),
|
||
}));
|
||
|
||
export const alertLogsRelations = relations(alertLogs, ({ one }) => ({
|
||
task: one(alertTasks, {
|
||
fields: [alertLogs.taskId],
|
||
references: [alertTasks.id],
|
||
}),
|
||
}));
|