mirror of
https://github.com/d0zingcat/alert-message-center.git
synced 2026-05-13 15:09:19 +00:00
268 lines
16 KiB
Markdown
268 lines
16 KiB
Markdown
# Project Context for GitHub Copilot (v1.4.0)
|
|
|
|
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.
|
|
|
|
## 0. AI/Agent Specific Instructions
|
|
> [!IMPORTANT]
|
|
> **AI Agents MUST read [AGENTS.md](../AGENTS.md) first.** It contains critical information about:
|
|
> - Build/lint/test commands.
|
|
> - Required code style (tabs, double quotes, naming conventions).
|
|
> - Hard rules (NO `any`, Biome checks).
|
|
|
|
## 1. Project Overview
|
|
|
|
**Alert Message Center** (formerly Alert Manager) is a centralized alert dispatching system.
|
|
- **Goal**: Decouple alert sources from alert recipients.
|
|
- **Mechanism**:
|
|
- **Topics**: Alerts are sent to a **Topic**. Users subscribe to Topics to receive messages.
|
|
- **Personal Inbox**: Users can send alerts directly to themselves via a private webhook URL, bypassing Topic creation and approval.
|
|
- **Group Chat**: Alerts can be dispatched to Feishu Group Chats where the App Bot is a member.
|
|
- **Dispatch**: The system sends messages via **Feishu (Lark) Private Messages** or **Group Messages**.
|
|
- **Runtime**: Bun (JavaScript/TypeScript runtime).
|
|
|
|
## 2. Tech Stack
|
|
|
|
- **Monorepo**: Simple directory structure (`apps/server`, `apps/web`).
|
|
- **Backend**:
|
|
- **Runtime**: Bun.
|
|
- **Framework**: Hono (Web Standard based).
|
|
- **Database**: PostgreSQL.
|
|
- **ORM**: Drizzle ORM.
|
|
- **Authentication**: Feishu OAuth2 (Session-based with cookies).
|
|
- **External API**: Feishu Open Platform (Server-side API via `@larksuiteoapi/node-sdk`).
|
|
- **Frontend**:
|
|
- **Build Tool**: Vite.
|
|
- **Framework**: React.
|
|
- **Styling**: Tailwind CSS.
|
|
- **Icons**: Lucide React.
|
|
- **Client**: `hono/client` (RPC-style type-safe client).
|
|
|
|
## 3. Data Model (Schema)
|
|
|
|
The database schema is defined in `apps/server/src/db/schema.ts`.
|
|
|
|
### Entities
|
|
|
|
1. **Topic** (`topics`)
|
|
- `id`: UUID (Primary Key)
|
|
- `name`: Display name (e.g., "Payment Service Errors").
|
|
- `slug`: URL-safe identifier (e.g., `payment-errors`). Used in webhook URLs.
|
|
- `description`: Optional text.
|
|
- `isGlobal`: Boolean flag. If true, alerts are sent to all users automatically.
|
|
- `status`: `pending`, `approved`, or `rejected`.
|
|
- `createdBy`: Foreign Key -> `users.id`.
|
|
- `approvedBy`: Foreign Key -> `users.id`.
|
|
|
|
2. **User** (`users`)
|
|
- `id`: UUID (Primary Key).
|
|
- `name`: Display name.
|
|
- `feishuUserId`: The Feishu `open_id`. **Critical** for sending messages.
|
|
- `email`: Contact info.
|
|
- `isAdmin`: Boolean flag for administrative privileges (create topics, view all users).
|
|
- `isTrusted`: Boolean flag for trusted users (topics are auto-approved).
|
|
|
|
3. **Subscription** (`subscriptions`)
|
|
- `topicId`: Foreign Key -> `topics.id`.
|
|
- `userId`: Foreign Key -> `users.id`.
|
|
- **Relationship**: Many-to-Many between Topics and Users.
|
|
|
|
4. **Topic Group Chat** (`topic_group_chats`)
|
|
- `id`: UUID (Primary Key).
|
|
- `topicId`: Foreign Key -> `topics.id`.
|
|
- `chatId`: The Feishu `chat_id`.
|
|
- `name`: Group name (snapshot).
|
|
- `status`: `pending`, `approved`, or `rejected`.
|
|
- `createdBy`: Foreign Key -> `users.id`.
|
|
- **Relationship**: Many-to-Many between Topics and Feishu Groups.
|
|
|
|
5. **Known Group Chat** (`known_group_chats`)
|
|
- `chatId`: Feishu `chat_id` (Primary Key).
|
|
- `name`: Group name.
|
|
- `lastActiveAt`: Timestamp of last event from this group.
|
|
- **Purpose**: Caches groups the bot has been added to, facilitating easy selection in the UI.
|
|
7. **Alert Task** (`alert_tasks`)
|
|
- `id`: UUID (Primary Key).
|
|
- `topicSlug`: The slug of the target topic (or `NULL` for DM).
|
|
- `senderId`: Foreign Key -> `users.id` (who triggered the webhook).
|
|
- `status`: `pending`, `processing`, `completed`, or `failed`.
|
|
- `recipientCount`: Total recipients (subscribers + groups).
|
|
- `successCount`: Number of successful deliveries.
|
|
- `payload`: Snapshot of the incoming webhook body (JSONB).
|
|
- `error`: Last error message if failed.
|
|
- **Purpose**: Tracks the lifecycle of a single alert ingestion events.
|
|
|
|
8. **Alert Log** (`alert_logs`)
|
|
- `id`: UUID (Primary Key).
|
|
- `taskId`: Foreign Key -> `alert_tasks.id`.
|
|
- `userId`: Target user open_id (snapshot).
|
|
- `status`: `sent` or `failed`.
|
|
- **Purpose**: Granular tracking for each individual delivery within a task.
|
|
|
|
## 4. Key Workflows
|
|
|
|
### Authentication
|
|
- **Strategy**: Feishu OAuth2.
|
|
- **Flow**:
|
|
1. Frontend calls `/api/auth/login-url` to get Feishu auth URL.
|
|
2. User redirects to Feishu, approves, redirects back to `/api/auth/callback`.
|
|
3. Server exchanges code for token, gets user info, creates/updates user in DB.
|
|
4. Server sets `session` cookie (httpOnly).
|
|
- **Context**: `AuthContext.tsx` manages user state on frontend.
|
|
|
|
### Personal Inbox (Direct Messaging)
|
|
- **Strategy**: Direct delivery to a specific user.
|
|
- **Mechanism**:
|
|
1. Each user has a `personalToken` (8-character hex string).
|
|
2. Sending to `POST /api/webhook/:token/dm` routes messages directly to the user associated with the token.
|
|
3. No Topic or Subscription is required.
|
|
|
|
### Alert Ingestion & Dispatch
|
|
**File**: `apps/server/src/webhook.ts`
|
|
|
|
1. **Ingest**:
|
|
- **Topic-based**: `POST /api/webhook/:token/topic/:slug`
|
|
- **Direct (Inbox)**: `POST /api/webhook/:token/dm`
|
|
2. **Lookup**:
|
|
- For Topic-based: Find `Topic` by `slug`.
|
|
- **Recipients**:
|
|
- If `isGlobal` is true: Fetch all active users from DB.
|
|
- If not global: Fetch all `subscriptions` for that topic.
|
|
- Always fetch all bound `topic_group_chats`.
|
|
- For Direct: Identify the user via `token`.
|
|
3. **Dispatch**:
|
|
- Call `FeishuClient.sendMessage` for each recipient.
|
|
- **Payload**: Supports `text` and `interactive` (Feishu Card) message types.
|
|
|
|
- Call `FeishuClient.sendMessage` for each recipient.
|
|
- **Payload**: Supports `text` and `interactive` (Feishu Card) message types.
|
|
|
|
### Feishu Group Chat Integration
|
|
- **Strategy**: App Bot in Group.
|
|
- **Discovery**:
|
|
- The system listens for `im.chat.member.bot.added_v1` events (via Webhook or WebSocket).
|
|
- When the bot is added to a group, the group details are cached in `known_group_chats`.
|
|
- **Bot Removal**:
|
|
- The system listens for `im.chat.member.bot.deleted_v1` events.
|
|
- When the bot is removed, the cached group is deleted from `known_group_chats`.
|
|
- **Auto-Unbind**: All bindings in `topic_group_chats` for that `chat_id` are automatically deleted to ensure data consistency.
|
|
- **Binding**: Users/Admins bind a Topic to a known Feishu Group in the UI.
|
|
- **Search**: The binding UI supports real-time, server-side debounced search by group name.
|
|
- **Security**: Only the Topic Creator or an Admin can bind/unbind groups to a Topic.
|
|
- **Approval**:
|
|
- Normal users: Binding status is `pending` upon creation. Admins receive notification.
|
|
- Admins/Trusted Users: Binding status is `approved` immediately.
|
|
- **Dispatch**: Alerts for the topic are sent to all bound `chat_id`s in addition to individual subscribers.
|
|
|
|
### Long Connection (WebSocket)
|
|
- **Problem**: Intranet deployments cannot receive public Webhook callbacks from Feishu.
|
|
- **Solution**: Use Feishu Open Platform's WebSocket mode.
|
|
- **Configuration**: Set `FEISHU_USE_WS=true` in `.env`.
|
|
- **Implementation**: Uses `@larksuiteoapi/node-sdk` to establish a persistent connection and receive events like `im.chat.member.bot.added_v1`.
|
|
- Users can subscribe/unsubscribe themselves to any topic.
|
|
- Admins can manage subscriptions for other users globally in `AdminView`.
|
|
- **Topic Deletion**: Centralized in the **Admin Dashboard (All Topics Tab)** to avoid accidental deletion from the main topic list.
|
|
- Button logic on frontend toggles between "Subscribe" and "Unsubscribe".
|
|
- **Topic Approval**:
|
|
- Normal users: Topic status is `pending` upon creation. Admins receive an interactive Feishu notification.
|
|
- Admins/Trusted Users: Topic status is `approved` immediately.
|
|
- Admin notification logic is located in `apps/server/src/lib/admin-notifier.ts`.
|
|
- **Trusted User System**:
|
|
- Users with `isTrusted=true` (set by Admin) or `isAdmin=true` have their requests (Topics/Bindings) automatically approved.
|
|
|
|
|
|
## 5. API Endpoints
|
|
|
|
### Auth
|
|
- `GET /api/auth/login-url`
|
|
- `GET /api/auth/callback`
|
|
- `GET /api/auth/me`
|
|
- `POST /api/auth/logout`
|
|
|
|
### Management
|
|
- `GET /api/topics`: List all approved topics.
|
|
- `GET /api/topics/my-requests`: List user's own topic requests.
|
|
- `GET /api/topics/requests`: List pending topic requests (Admin only).
|
|
- `GET /api/topics/all`: List all topics regardless of status (Admin only).
|
|
- `POST /api/topics`: Create a topic (Admin/Trusted creates approved, User creates pending; Supports `isGlobal`).
|
|
- `POST /api/topics/:id/approve`: Approve a topic request (Admin only).
|
|
- `POST /api/topics/:id/reject`: Reject a topic request (Admin only).
|
|
- `DELETE /api/topics/:id`: Delete a topic (Admin only).
|
|
- `POST /api/topics/:id/subscribe/:userId`: Subscribe.
|
|
- `DELETE /api/topics/:id/subscribe/:userId`: Unsubscribe.
|
|
- `GET /api/users`: List users (Admin only).
|
|
- `GET /api/users`: List users (Admin only).
|
|
|
|
### Feishu Group Management
|
|
- `GET /api/groups`: List known groups (cached from bot events). Supports `q` for search and `limit` parameters.
|
|
- `GET /api/topics/:id/groups`: List group bindings for a topic.
|
|
- `POST /api/topics/:id/groups`: Bind a group to a topic.
|
|
- `DELETE /api/topics/:id/groups/:bindingId`: Unbind a group.
|
|
|
|
### Feishu Event
|
|
- `POST /api/feishu/event`: Endpoint for receiving Feishu events (Webhook mode).
|
|
- **Note**: This endpoint uses **manual challenge handling** (`lark.generateChallenge`) and `eventDispatcher.invoke` instead of the SDK's `adaptDefault` to maintain compatibility with Hono's non-standard Node.js response object.
|
|
- **Signature Verification Hack**: To preserve Feishu's signature verification, the internal `invoke` call uses `Object.create({ headers })` to inject HTTP headers on the prototype of the payload object. This ensures headers are accessible to the SDK's internal verification logic but are **excluded** from `JSON.stringify`, which is critical for matching the SHA256 content checksum.
|
|
|
|
### Webhook
|
|
- `POST /api/webhook/:token/topic/:slug`: Trigger an alert for a topic.
|
|
- `POST /api/webhook/:token/dm`: Trigger a direct alert to the user's private inbox.
|
|
|
|
## 6. Future Roadmap (Planned)
|
|
|
|
- [ ] **Message Preview**: Preview Feishu card JSON in the UI.
|
|
- [x] **History/Logs**: Tracking for sent alerts (Alert Tasks/Logs).
|
|
- [ ] **Retry Mechanism**: Handle Feishu API failures.
|
|
- [x] **Deployment**: Dockerfile and CI/CD.
|
|
|
|
## 7. Development Conventions
|
|
|
|
- **Imports**: Use relative imports.
|
|
- **Styling**: Use Tailwind utility classes directly in JSX.
|
|
- **Async/Await**: Prefer `async/await` over `.then()`.
|
|
- **Strict Type Safety & `any` Prohibition**:
|
|
> [!IMPORTANT]
|
|
> **The usage of `any` is strictly prohibited.** This has been a recurring issue and must be avoided at all costs.
|
|
- **Explicit Interfaces**: Always define clear interfaces or types for API responses, webhook payloads, and complex objects.
|
|
- **Type Inference**: Leverage TypeScript's type inference. If a variable is initialized later, provide an explicit type during declaration (e.g., `let whereClause: SQL | undefined;`) instead of leaving it implicit.
|
|
- **Hono RPC**: Utilize the type-safe client (`client.api...`) to ensure end-to-end type safety between backend and frontend.
|
|
- **No Type Casting**: Avoid `as any` or `<any>` casts. Use type guards (`if`, `switch`, `instanceof`) or Zod schema validation to narrow types safely.
|
|
- **AI Responsibility**: AI assistants MUST ensure every new or modified piece of code passes strict TypeScript and Biome checks. If a type is unknown, research the schema rather than defaulting to `any`.
|
|
- **Formatting**: All files MUST end with a single trailing newline (enforced by Biome). Ensure `package.json` and other configuration files are correctly formatted before committing.
|
|
- **Vite Env Access**: When accessing Vite environment variables via `import.meta.env` (or casting `import.meta as any`), **always use optional chaining** (e.g., `meta.env?.VITE_...`). This prevents crashes if the environment is not initialized or if the code runs in a non-browser context during pre-rendering/testing.
|
|
- **Frontend Resilience**:
|
|
- Always check `res.ok` before attempting to parse or use API responses.
|
|
- Use `Array.isArray()` to verify that data expected to be a list actually is one, especially when mapping over it in JSX. This prevents "white page" crashes when the backend returns error objects instead of arrays.
|
|
- Provide fallback empty states (e.g., `setTopics([])`) in `catch` blocks or failed response branches.
|
|
- **Logging**:
|
|
- Framework: `pino`.
|
|
- **Structured Log**: Use JSON format for easy parsing and aggregation.
|
|
- **Contextual Data**: Pass objects as the first argument to `logger` methods (e.g., `logger.error({ err, chatId }, 'message')`) for indexed search.
|
|
- **Dev Mode**: Uses `pino-pretty` for human-friendly output during development.
|
|
- **Environment Isolation**:
|
|
- Each workspace (`apps/server`, `apps/web`) uses its own `.env` file via Bun's `--env-file .env` flag.
|
|
- Development proxy target for the frontend is configurable via `VITE_API_URL` (default: `http://localhost:3000`).
|
|
- **Critical Environment Variables**:
|
|
- `FEISHU_ENCRYPT_KEY`: Essential for the `lark.generateChallenge` and event signature verification.
|
|
- `FEISHU_VERIFICATION_TOKEN`: Used by `EventDispatcher` for event authentication.
|
|
- `FEISHU_USE_WS`: Set to `true` to enable WebSocket mode (bypasses `feishu-event.ts`).
|
|
- `ADMIN_EMAILS`: Comma-separated list of emails that automatically receive `isAdmin=true` upon first login.
|
|
- **CI/CD**:
|
|
- 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`.
|
|
- 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.
|
|
- **Token Migration**: The `db:migrate:deploy` script (defined in `src/db/migrate.ts`) also handles legacy user token shortening to maintain consistency with the 8-character token logic introduced in v1.2.6.
|
|
- **Drizzle Meta**: The `apps/server/drizzle/meta` directory MUST NOT be ignored by git (it was previously explicitly excluded in `.gitignore` but has been restored). This directory contains `_journal.json`, which is essential for `drizzle-kit` and the runtime migrator to verify migration integrity. Without it, migrations will fail in clean environments like Docker containers.
|
|
|
|
- **Multi-Replica Support**:
|
|
- **Migrations**: The `db:migrate:deploy` script uses **Postgres Advisory Locks** to prevent race conditions when multiple replicas start simultaneously. Only one replica will execute the migration; others will wait and verify.
|
|
- **Feishu Events**: The event handling logic is designed to be idempotent (`onConflictDoUpdate`), making it safe to run multiple replicas receiving duplicated events from Feishu (via WebSocket or Webhook).
|
|
|
|
## 8. Core Documents
|
|
|
|
- **[README.md](file:///Users/lilithgames/Workspace/play/alert-message-center/README.md)**: Main project documentation (English version).
|
|
- **[README.zh-CN.md](file:///Users/lilithgames/Workspace/play/alert-message-center/README.zh-CN.md)**: Simplified Chinese version of the documentation.
|
|
- **[AGENTS.md](file:///Users/lilithgames/Workspace/play/alert-message-center/AGENTS.md)**: Specialized instructions and conventions for AI agents.
|
|
- **[CHANGELOG.md](file:///Users/lilithgames/Workspace/play/alert-message-center/CHANGELOG.md)**: Record of version changes.
|
|
- **[todo.md](file:///Users/lilithgames/Workspace/play/alert-message-center/todo.md)**: Task tracking.
|