feat: 首次推送到Gitea - 完整项目代码 + 安全加固 + 知识库
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `comments` DROP FOREIGN KEY `comments_user_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `forum_posts` DROP FOREIGN KEY `forum_posts_user_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `forum_topics` DROP FOREIGN KEY `forum_topics_user_id_fkey`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `bot_adversarial_learnings` ALTER COLUMN `updated_at` DROP DEFAULT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `bot_persona_assignments` ALTER COLUMN `updated_at` DROP DEFAULT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `bot_persona_experiments` MODIFY `significance_level` DOUBLE NOT NULL DEFAULT 0.1,
|
||||
ALTER COLUMN `updated_at` DROP DEFAULT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `bot_persona_metrics` MODIFY `avg_replies` DOUBLE NOT NULL DEFAULT 0,
|
||||
MODIFY `avg_likes` DOUBLE NOT NULL DEFAULT 0,
|
||||
MODIFY `computed_score` DOUBLE NOT NULL DEFAULT 0,
|
||||
ALTER COLUMN `updated_at` DROP DEFAULT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `bot_persona_variants` MODIFY `weight` DOUBLE NOT NULL DEFAULT 0.5,
|
||||
MODIFY `engagement_score` DOUBLE NOT NULL DEFAULT 0,
|
||||
ALTER COLUMN `updated_at` DROP DEFAULT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `collections` ADD COLUMN `is_public` BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN `public_slug` VARCHAR(100) NULL,
|
||||
ADD COLUMN `view_count` INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `notifications` MODIFY `type` ENUM('COMMENT_REPLY', 'COMMENT_LIKE', 'TOPIC_REPLY', 'MENTION', 'BEST_ANSWER', 'POST_LIKE', 'TOPIC_LIKE', 'SYSTEM', 'DIGEST') NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `tools` ADD COLUMN `screenshots` JSON NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `user_achievements` ALTER COLUMN `updated_at` DROP DEFAULT;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `feedbacks` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`type` VARCHAR(20) NOT NULL DEFAULT 'suggestion',
|
||||
`content` TEXT NOT NULL,
|
||||
`contact` VARCHAR(255) NULL,
|
||||
`page_url` VARCHAR(500) NULL,
|
||||
`user_id` VARCHAR(50) NULL,
|
||||
`status` VARCHAR(20) NOT NULL DEFAULT 'pending',
|
||||
`admin_note` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
|
||||
INDEX `feedbacks_status_created_at_idx`(`status`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `api_keys` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`key_hash` VARCHAR(64) NOT NULL,
|
||||
`key_prefix` VARCHAR(8) NOT NULL,
|
||||
`tier` VARCHAR(20) NOT NULL DEFAULT 'free',
|
||||
`rate_limit` INTEGER NOT NULL DEFAULT 100,
|
||||
`last_used_at` DATETIME(3) NULL,
|
||||
`request_count` INTEGER NOT NULL DEFAULT 0,
|
||||
`is_active` BOOLEAN NOT NULL DEFAULT true,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`expires_at` DATETIME(3) NULL,
|
||||
|
||||
UNIQUE INDEX `api_keys_key_hash_key`(`key_hash`),
|
||||
INDEX `api_keys_user_id_idx`(`user_id`),
|
||||
INDEX `api_keys_key_prefix_idx`(`key_prefix`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `bot_daily_stats_bot_id_date_idx` ON `bot_daily_stats`(`bot_id`, `date`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `bot_memories_bot_id_created_at_idx` ON `bot_memories`(`bot_id`, `created_at`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `collections_public_slug_key` ON `collections`(`public_slug`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `collections_is_public_view_count_idx` ON `collections`(`is_public`, `view_count`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `forum_posts_topic_id_is_hidden_created_at_idx` ON `forum_posts`(`topic_id`, `is_hidden`, `created_at`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `forum_topics_category_id_updated_at_idx` ON `forum_topics`(`category_id`, `updated_at`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `forum_topics_created_at_idx` ON `forum_topics`(`created_at`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `skills_status_view_count_idx` ON `skills`(`status`, `view_count`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `skills_status_created_at_idx` ON `skills`(`status`, `created_at`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `tools_status_view_count_idx` ON `tools`(`status`, `view_count`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `tools_status_created_at_idx` ON `tools`(`status`, `created_at`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `users_is_bot_idx` ON `users`(`is_bot`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `users_role_idx` ON `users`(`role`);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `comments` ADD CONSTRAINT `comments_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `forum_topics` ADD CONSTRAINT `forum_topics_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `forum_posts` ADD CONSTRAINT `forum_posts_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `bot_persona_variants` ADD CONSTRAINT `bot_persona_variants_bot_id_fkey` FOREIGN KEY (`bot_id`) REFERENCES `bot_configs`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `bot_persona_variants` ADD CONSTRAINT `bot_persona_variants_experiment_id_fkey` FOREIGN KEY (`experiment_id`) REFERENCES `bot_persona_experiments`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `bot_persona_assignments` ADD CONSTRAINT `bot_persona_assignments_variant_id_fkey` FOREIGN KEY (`variant_id`) REFERENCES `bot_persona_variants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `bot_persona_metrics` ADD CONSTRAINT `bot_persona_metrics_variant_id_fkey` FOREIGN KEY (`variant_id`) REFERENCES `bot_persona_variants`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `bot_adversarial_learnings` ADD CONSTRAINT `bot_adversarial_learnings_bot_id_fkey` FOREIGN KEY (`bot_id`) REFERENCES `bot_configs`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `bot_cross_forum_affinities` ADD CONSTRAINT `bot_cross_forum_affinities_bot_id_fkey` FOREIGN KEY (`bot_id`) REFERENCES `bot_configs`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `user_achievements` ADD CONSTRAINT `user_achievements_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `user_achievements` ADD CONSTRAINT `user_achievements_achievement_key_fkey` FOREIGN KEY (`achievement_key`) REFERENCES `achievements`(`key`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `forum_topic_subscriptions` ADD CONSTRAINT `forum_topic_subscriptions_topic_id_fkey` FOREIGN KEY (`topic_id`) REFERENCES `forum_topics`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `forum_topic_subscriptions` ADD CONSTRAINT `forum_topic_subscriptions_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `api_keys` ADD CONSTRAINT `api_keys_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- 行业智库元数据列:主题帖标记为智库帖,存版本/议题等
|
||||
ALTER TABLE `forum_topics` ADD COLUMN `thinktank` JSON NULL;
|
||||
+66
-3
@@ -53,6 +53,7 @@ model Tool {
|
||||
pricingModel PricingModel @default(freemium) @map("pricing_model")
|
||||
pricingDetail String? @map("pricing_detail") @db.VarChar(200)
|
||||
features Json?
|
||||
screenshots Json? // Array of { url: string, alt?: string } - max 5 screenshots
|
||||
tags Json?
|
||||
viewCount Int @default(0) @map("view_count")
|
||||
commentCount Int @default(0) @map("comment_count")
|
||||
@@ -71,6 +72,8 @@ model Tool {
|
||||
collectionItems CollectionItem[]
|
||||
comments Comment[]
|
||||
|
||||
@@index([status, viewCount]) // for published tools sorted by views
|
||||
@@index([status, createdAt]) // for recent published tools
|
||||
@@index([categoryId, status])
|
||||
@@fulltext([name, description])
|
||||
@@map("tools")
|
||||
@@ -137,6 +140,8 @@ model Skill {
|
||||
commentCount Int @default(0) @map("comment_count")
|
||||
avgRating Float @default(0) @map("avg_rating")
|
||||
|
||||
@@index([status, viewCount]) // for published skills sorted by views
|
||||
@@index([status, createdAt]) // for recent published skills
|
||||
@@index([categoryId, status])
|
||||
@@map("skills")
|
||||
}
|
||||
@@ -229,7 +234,12 @@ model User {
|
||||
achievements UserAchievement[]
|
||||
topicSubscriptions ForumTopicSubscription[]
|
||||
|
||||
apiKeys ApiKey[]
|
||||
|
||||
|
||||
@@unique([oauthProvider, oauthId])
|
||||
@@index([isBot]) // for filtering bot users
|
||||
@@index([role]) // for role-based queries
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
@@ -371,6 +381,9 @@ model Collection {
|
||||
name String @db.VarChar(50)
|
||||
description String? @db.Text
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
isPublic Boolean @default(false) @map("is_public")
|
||||
publicSlug String? @unique @map("public_slug") @db.VarChar(100)
|
||||
viewCount Int @default(0) @map("view_count")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@ -378,6 +391,7 @@ model Collection {
|
||||
items CollectionItem[]
|
||||
|
||||
@@index([userId])
|
||||
@@index([isPublic, viewCount])
|
||||
@@map("collections")
|
||||
}
|
||||
|
||||
@@ -526,7 +540,7 @@ model Comment {
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
tool Tool? @relation(fields: [toolId], references: [id], onDelete: Cascade)
|
||||
skill Skill? @relation(fields: [skillId], references: [id], onDelete: Cascade)
|
||||
parent Comment? @relation("CommentReplies", fields: [parentId], references: [id])
|
||||
@@ -583,6 +597,7 @@ enum NotifType {
|
||||
POST_LIKE
|
||||
TOPIC_LIKE
|
||||
SYSTEM
|
||||
DIGEST
|
||||
}
|
||||
|
||||
model ForumCategory {
|
||||
@@ -622,9 +637,12 @@ model ForumTopic {
|
||||
lastReplyAt DateTime? @map("last_reply_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
// 行业智库元数据:{ kind:"thinktank", industry:<板块slug>, version: n, lastTopic, lastRoundAt }
|
||||
// 主题帖 topic.content = 最新"打法"(1 楼),楼层 post = 每周研讨对话原文/真人问答
|
||||
thinktank Json? @map("thinktank")
|
||||
|
||||
category ForumCategory @relation(fields: [categoryId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
posts ForumPost[]
|
||||
likes ForumTopicLike[]
|
||||
tags ForumTopicTag[]
|
||||
@@ -634,6 +652,8 @@ model ForumTopic {
|
||||
|
||||
@@index([categoryId, lastReplyAt])
|
||||
@@index([categoryId, isPinned, createdAt])
|
||||
@@index([categoryId, updatedAt]) // for recent topics by category
|
||||
@@index([createdAt]) // for chronological queries
|
||||
@@index([userId])
|
||||
@@index([isFeatured, lastReplyAt])
|
||||
@@index([isHidden])
|
||||
@@ -656,12 +676,13 @@ model ForumPost {
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
likes ForumPostLike[]
|
||||
replyTo ForumPost? @relation("PostReplies", fields: [replyToId], references: [id], onDelete: SetNull)
|
||||
replies ForumPost[] @relation("PostReplies")
|
||||
|
||||
@@index([topicId, createdAt])
|
||||
@@index([topicId, isHidden, createdAt]) // for filtered post queries
|
||||
@@index([userId])
|
||||
@@index([replyToId])
|
||||
@@index([isHidden])
|
||||
@@ -836,6 +857,8 @@ model BotConfig {
|
||||
botPersonaVariants BotPersonaVariant[] @relation("BotVariants")
|
||||
adversarialLearnings BotAdversarialLearning[] @relation("BotAdversarialLearnings")
|
||||
|
||||
crossForumAffinities BotCrossForumAffinity[]
|
||||
|
||||
@@map("bot_configs")
|
||||
}
|
||||
|
||||
@@ -873,6 +896,7 @@ model BotDailyStat {
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@unique([botId, date])
|
||||
@@index([botId, date]) // for bot daily stats queries
|
||||
@@index([date])
|
||||
@@map("bot_daily_stats")
|
||||
}
|
||||
@@ -1076,6 +1100,8 @@ model BotCrossForumAffinity {
|
||||
reason String? @db.VarChar(100)
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
bot BotConfig @relation(fields: [botId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([botId, forumSlug])
|
||||
@@index([botId, affinity])
|
||||
@@map("bot_cross_forum_affinities")
|
||||
@@ -1132,3 +1158,40 @@ model ForumTopicSubscription {
|
||||
@@index([userId, createdAt])
|
||||
@@map("forum_topic_subscriptions")
|
||||
}
|
||||
|
||||
model Feedback {
|
||||
id Int @id @default(autoincrement())
|
||||
type String @default("suggestion") @db.VarChar(20)
|
||||
content String @db.Text
|
||||
contact String? @db.VarChar(255)
|
||||
pageUrl String? @map("page_url") @db.VarChar(500)
|
||||
userId String? @map("user_id") @db.VarChar(50)
|
||||
status String @default("pending") @db.VarChar(20)
|
||||
adminNote String? @map("admin_note") @db.Text
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@index([status, createdAt])
|
||||
@@map("feedbacks")
|
||||
}
|
||||
|
||||
model ApiKey {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int @map("user_id")
|
||||
name String @db.VarChar(100)
|
||||
keyHash String @unique @map("key_hash") @db.VarChar(64)
|
||||
keyPrefix String @map("key_prefix") @db.VarChar(8)
|
||||
tier String @default("free") @db.VarChar(20)
|
||||
rateLimit Int @default(100) @map("rate_limit")
|
||||
lastUsedAt DateTime? @map("last_used_at")
|
||||
requestCount Int @default(0) @map("request_count")
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
expiresAt DateTime? @map("expires_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId])
|
||||
@@index([keyPrefix])
|
||||
@@map("api_keys")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user