mirror of
https://github.com/d0zingcat/alert-message-center.git
synced 2026-05-13 15:09:19 +00:00
feat: make db migration automatically
Signed-off-by: d0zingcat <iamtangli42@gmail.com>
This commit is contained in:
12
CHANGELOG.md
12
CHANGELOG.md
@@ -5,6 +5,18 @@
|
|||||||
本文件的格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
本文件的格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
||||||
并且本项目遵循 [语义化版本 (Semantic Versioning)](https://semver.org/lang/zh-CN/spec/v2.0.0.html)。
|
并且本项目遵循 [语义化版本 (Semantic Versioning)](https://semver.org/lang/zh-CN/spec/v2.0.0.html)。
|
||||||
|
|
||||||
|
## [1.2.3] - 2026-01-15
|
||||||
|
|
||||||
|
### 新增
|
||||||
|
- **自动化数据库迁移**: 引入了自动化数据库初始化与迁移机制。
|
||||||
|
- 添加了 `src/db/migrate.ts` 脚本,使用 Drizzle Migrator 自动应用挂起的迁移。
|
||||||
|
- 更新了 `Dockerfile`,使容器启动时自动执行数据库迁移。
|
||||||
|
- 在 `package.json` 中新增了 `db:migrate:deploy` 脚本。
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- **初始化错误**: 修复了在全新环境下启动时因缺少数据库表导致的 `relation "users" does not exist` 错误。
|
||||||
|
- **迁移历史**: 清理并重新生成了初始迁移文件,确保所有表在全新部署时能正确创建。
|
||||||
|
|
||||||
## [1.2.2] - 2026-01-14
|
## [1.2.2] - 2026-01-14
|
||||||
|
|
||||||
### 变更
|
### 变更
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ WORKDIR /app/apps/server
|
|||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
CMD ["bun", "run", "start"]
|
CMD ["sh", "-c", "bun run db:migrate:deploy && bun run start"]
|
||||||
|
|||||||
@@ -71,15 +71,15 @@ FEISHU_APP_ID="cli_xxx"
|
|||||||
FEISHU_APP_SECRET="xxx"
|
FEISHU_APP_SECRET="xxx"
|
||||||
ADMIN_EMAILS="user1@example.com,user2@example.com" # 管理员列表
|
ADMIN_EMAILS="user1@example.com,user2@example.com" # 管理员列表
|
||||||
|
|
||||||
# 数据库推送
|
# 数据库推送/迁移
|
||||||
cd apps/server && bun run db:push
|
cd apps/server && bun run db:migrate:deploy
|
||||||
|
|
||||||
# 启动开发环境
|
# 启动开发环境
|
||||||
bun run dev
|
bun run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Docker 部署
|
### 3. Docker 部署
|
||||||
项目支持使用 Docker Compose 快速部署:
|
项目支持使用 Docker Compose 快速部署,且**数据库会自动进行初始化与迁移**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 复制并填写环境变量
|
# 复制并填写环境变量
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ CREATE TABLE "alert_logs" (
|
|||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE "alert_tasks" (
|
CREATE TABLE "alert_tasks" (
|
||||||
"id" text PRIMARY KEY NOT NULL,
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
"topic_slug" text NOT NULL,
|
"topic_slug" text,
|
||||||
|
"sender_id" text,
|
||||||
"status" text DEFAULT 'pending' NOT NULL,
|
"status" text DEFAULT 'pending' NOT NULL,
|
||||||
"recipient_count" integer DEFAULT 0,
|
"recipient_count" integer DEFAULT 0,
|
||||||
"success_count" integer DEFAULT 0,
|
"success_count" integer DEFAULT 0,
|
||||||
@@ -19,6 +20,12 @@ CREATE TABLE "alert_tasks" (
|
|||||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "known_group_chats" (
|
||||||
|
"chat_id" text PRIMARY KEY NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"last_active_at" timestamp DEFAULT now()
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
CREATE TABLE "subscriptions" (
|
CREATE TABLE "subscriptions" (
|
||||||
"user_id" text NOT NULL,
|
"user_id" text NOT NULL,
|
||||||
"topic_id" text NOT NULL,
|
"topic_id" text NOT NULL,
|
||||||
@@ -26,6 +33,15 @@ CREATE TABLE "subscriptions" (
|
|||||||
CONSTRAINT "subscriptions_user_id_topic_id_pk" PRIMARY KEY("user_id","topic_id")
|
CONSTRAINT "subscriptions_user_id_topic_id_pk" PRIMARY KEY("user_id","topic_id")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "topic_group_chats" (
|
||||||
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
|
"topic_id" text NOT NULL,
|
||||||
|
"chat_id" text NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
|
"created_by" text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
CREATE TABLE "topics" (
|
CREATE TABLE "topics" (
|
||||||
"id" text PRIMARY KEY NOT NULL,
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
"slug" text NOT NULL,
|
"slug" text NOT NULL,
|
||||||
@@ -33,6 +49,7 @@ CREATE TABLE "topics" (
|
|||||||
"description" text,
|
"description" text,
|
||||||
"status" text DEFAULT 'approved' NOT NULL,
|
"status" text DEFAULT 'approved' NOT NULL,
|
||||||
"created_by" text,
|
"created_by" text,
|
||||||
|
"approved_by" text,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "topics_slug_unique" UNIQUE("slug")
|
CONSTRAINT "topics_slug_unique" UNIQUE("slug")
|
||||||
);
|
);
|
||||||
@@ -43,10 +60,16 @@ CREATE TABLE "users" (
|
|||||||
"feishu_user_id" text NOT NULL,
|
"feishu_user_id" text NOT NULL,
|
||||||
"email" text,
|
"email" text,
|
||||||
"is_admin" boolean DEFAULT false,
|
"is_admin" boolean DEFAULT false,
|
||||||
CONSTRAINT "users_email_unique" UNIQUE("email")
|
"personal_token" text NOT NULL,
|
||||||
|
CONSTRAINT "users_email_unique" UNIQUE("email"),
|
||||||
|
CONSTRAINT "users_personal_token_unique" UNIQUE("personal_token")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
ALTER TABLE "alert_logs" ADD CONSTRAINT "alert_logs_task_id_alert_tasks_id_fk" FOREIGN KEY ("task_id") REFERENCES "public"."alert_tasks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
ALTER TABLE "alert_logs" ADD CONSTRAINT "alert_logs_task_id_alert_tasks_id_fk" FOREIGN KEY ("task_id") REFERENCES "public"."alert_tasks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "alert_tasks" ADD CONSTRAINT "alert_tasks_sender_id_users_id_fk" FOREIGN KEY ("sender_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
ALTER TABLE "subscriptions" ADD CONSTRAINT "subscriptions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
ALTER TABLE "subscriptions" ADD CONSTRAINT "subscriptions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
ALTER TABLE "subscriptions" ADD CONSTRAINT "subscriptions_topic_id_topics_id_fk" FOREIGN KEY ("topic_id") REFERENCES "public"."topics"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
ALTER TABLE "subscriptions" ADD CONSTRAINT "subscriptions_topic_id_topics_id_fk" FOREIGN KEY ("topic_id") REFERENCES "public"."topics"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
ALTER TABLE "topics" ADD CONSTRAINT "topics_created_by_users_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
|
ALTER TABLE "topic_group_chats" ADD CONSTRAINT "topic_group_chats_topic_id_topics_id_fk" FOREIGN KEY ("topic_id") REFERENCES "public"."topics"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "topic_group_chats" ADD CONSTRAINT "topic_group_chats_created_by_users_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "topics" ADD CONSTRAINT "topics_created_by_users_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "topics" ADD CONSTRAINT "topics_approved_by_users_id_fk" FOREIGN KEY ("approved_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
CREATE TABLE "topic_group_webhooks" (
|
|
||||||
"id" text PRIMARY KEY NOT NULL,
|
|
||||||
"topic_id" text NOT NULL,
|
|
||||||
"name" text NOT NULL,
|
|
||||||
"url" text NOT NULL,
|
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
"created_by" text
|
|
||||||
);
|
|
||||||
--> statement-breakpoint
|
|
||||||
ALTER TABLE "alert_tasks" ALTER COLUMN "topic_slug" DROP NOT NULL;--> statement-breakpoint
|
|
||||||
ALTER TABLE "alert_tasks" ADD COLUMN "sender_id" text;--> statement-breakpoint
|
|
||||||
ALTER TABLE "topics" ADD COLUMN "approved_by" text;--> statement-breakpoint
|
|
||||||
ALTER TABLE "users" ADD COLUMN "personal_token" text NOT NULL;--> statement-breakpoint
|
|
||||||
ALTER TABLE "topic_group_webhooks" ADD CONSTRAINT "topic_group_webhooks_topic_id_topics_id_fk" FOREIGN KEY ("topic_id") REFERENCES "public"."topics"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
||||||
ALTER TABLE "topic_group_webhooks" ADD CONSTRAINT "topic_group_webhooks_created_by_users_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
|
||||||
ALTER TABLE "alert_tasks" ADD CONSTRAINT "alert_tasks_sender_id_users_id_fk" FOREIGN KEY ("sender_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
|
||||||
ALTER TABLE "topics" ADD CONSTRAINT "topics_approved_by_users_id_fk" FOREIGN KEY ("approved_by") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
|
||||||
ALTER TABLE "users" ADD CONSTRAINT "users_personal_token_unique" UNIQUE("personal_token");
|
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
"start": "bun run src/index.ts",
|
"start": "bun run src/index.ts",
|
||||||
"db:generate": "drizzle-kit generate",
|
"db:generate": "drizzle-kit generate",
|
||||||
"db:migrate": "drizzle-kit migrate",
|
"db:migrate": "drizzle-kit migrate",
|
||||||
|
"db:migrate:deploy": "bun run src/db/migrate.ts",
|
||||||
"db:push": "drizzle-kit push",
|
"db:push": "drizzle-kit push",
|
||||||
"db:studio": "drizzle-kit studio"
|
"db:studio": "drizzle-kit studio"
|
||||||
},
|
},
|
||||||
|
|||||||
26
apps/server/src/db/migrate.ts
Normal file
26
apps/server/src/db/migrate.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { drizzle } from "drizzle-orm/postgres-js";
|
||||||
|
import { migrate } from "drizzle-orm/postgres-js/migrator";
|
||||||
|
import postgres from "postgres";
|
||||||
|
import * as schema from "./schema";
|
||||||
|
|
||||||
|
const connectionString =
|
||||||
|
process.env.DATABASE_URL ||
|
||||||
|
"postgres://postgres:password@localhost:5432/alert_message_center";
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log("⏳ Running migrations...");
|
||||||
|
const sql = postgres(connectionString, { max: 1 });
|
||||||
|
const db = drizzle(sql, { schema });
|
||||||
|
|
||||||
|
try {
|
||||||
|
await migrate(db, { migrationsFolder: "./drizzle" });
|
||||||
|
console.log("✅ Migrations completed!");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ Migration failed:", error);
|
||||||
|
process.exit(1);
|
||||||
|
} finally {
|
||||||
|
await sql.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Project Context for GitHub Copilot (v1.2.2)
|
# Project Context for GitHub Copilot (v1.2.3)
|
||||||
|
|
||||||
This document provides technical context, architectural decisions, and code conventions for the **Alert Message Center** project. It is intended to help AI assistants understand the codebase.
|
This document provides technical context, architectural decisions, and code conventions for the **Alert Message Center** project. It is intended to help AI assistants understand the codebase.
|
||||||
|
|
||||||
@@ -216,6 +216,7 @@ The database schema is defined in `apps/server/src/db/schema.ts`.
|
|||||||
- GitHub Actions automates building a multi-stage Docker image and pushing it to GitHub Container Registry (GHCR).
|
- GitHub Actions automates building a multi-stage Docker image and pushing it to GitHub Container Registry (GHCR).
|
||||||
- Image path: `ghcr.io/${USER}/alert-message-center`.
|
- Image path: `ghcr.io/${USER}/alert-message-center`.
|
||||||
- Deployment Architecture: A single container runs the Bun server, which serves API requests and static frontend assets (via `hono/bun`'s `serveStatic`).
|
- Deployment Architecture: A single container runs the Bun server, which serves API requests and static frontend assets (via `hono/bun`'s `serveStatic`).
|
||||||
|
- **Database Initialization**: The Docker entrypoint automatically runs `bun run db:migrate:deploy` before starting the server to ensure the schema is up-to-date in new environments.
|
||||||
|
|
||||||
## 8. Core Documents
|
## 8. Core Documents
|
||||||
|
|
||||||
|
|||||||
1
todo.md
1
todo.md
@@ -27,4 +27,5 @@
|
|||||||
- [x] **Long Connection**: WebSocket support for intranet deployments.
|
- [x] **Long Connection**: WebSocket support for intranet deployments.
|
||||||
- [x] **Structured Logging**: Integrated `pino` for better observability.
|
- [x] **Structured Logging**: Integrated `pino` for better observability.
|
||||||
- [x] **Linting**: Tightened Biome rules and resolved all a11y/correctness issues.
|
- [x] **Linting**: Tightened Biome rules and resolved all a11y/correctness issues.
|
||||||
|
- [x] **Automated Migrations**: Automatically initialize database schema on startup (especially in Docker).
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user