diff --git a/.trae/skills/bls-backend-component-builder/SKILL.md b/.trae/skills/bls-backend-component-builder/SKILL.md new file mode 100644 index 0000000..ad9c8a4 --- /dev/null +++ b/.trae/skills/bls-backend-component-builder/SKILL.md @@ -0,0 +1,155 @@ +--- +name: "bls-backend-component-builder" +description: "生成与本仓库一致的 Kafka→处理→DB→Redis 错误链路后端组件脚手架。Invoke when用户说:开始构建BLS后端组件。" +triggers: + - "开始构建BLS后端组件" +actions: + - id: "collect-inputs" + title: "收集生成参数" + outputs: + - "newProjectDir" + - "projectName" + - "kafka.topics" + - "kafka.groupId" + - "inputSchema" + - "db.type" + - "db.schemaName" + - "db.tableOrCollection" + - "transformRules" + - "redis.errorQueue" + steps: + - "默认 newProjectDir = ../(与当前仓库同级)。" + - "默认 projectName = BLS_<业务名>_Processor。" + - "默认 kafka.topics = [<业务Topic>],groupId = 。" + - "inputSchema 描述 Kafka message.value 解码后的 JSON 结构(字段、类型、必填、枚举)。" + - "db.type 默认 postgresql;如改为 mysql/mongodb,需同步调整 db 层实现。" + - "db.schemaName/tableOrCollection 指定落库位置与结构。" + - "transformRules 描述清洗、映射、归一化、补缺、派生字段规则。" + - "redis.errorQueue 默认 :errors(用于可重试错误队列)。" + - id: "scaffold-project" + title: "生成项目骨架(同架构同产物)" + steps: + - "创建 newProjectDir,并复制本仓库的 package.json、package-lock.json、vite.config.js、scripts/、src/、test/、.eslintrc.cjs、.gitignore、ecosystem.config.cjs、.env.example。" + - "将本 Skill 自带的 assets/skill/ 复制为 newProjectDir/skill/(作为新项目的标准约束文件与可移植模板集合)。" + - "在 newProjectDir/src/config/config.js 基于 config.example.js 生成运行配置,并将 kafka.topics/groupId/clientId、db、redis 按参数写入。" + - "确保构建产物入口与 PM2 启动脚本一致:dist/index.* 与 ecosystem.config.cjs 的 script 字段一致。" + - id: "implement-kafka-ingestion" + title: "配置 Kafka 订阅与解码" + steps: + - "在 newProjectDir/src/kafka/consumer.js 复用 ConsumerGroupStream 模式,订阅 kafka.topics。" + - "保持 encoding 为 buffer,并在 processor 中按 UTF-8 解码为 JSON。" + - "如生产者启用压缩/封装(gzip/brotli/deflate),在 processor 解包逻辑中保持兼容。" + - id: "implement-processor" + title: "实现解析/校验/转换/批处理写入" + steps: + - "在 newProjectDir/src/processor/ 生成 Processor(可沿用 HeartbeatProcessor 命名模式)。" + - "实现四段式处理:unpackMessage -> validateData -> transformData -> processBatch。" + - "validateData 按 inputSchema 强校验:缺字段、类型不符、枚举越界直接判失败。" + - "transformData 按 transformRules 进行字段映射、清洗、派生字段生成。" + - "processBatch 使用批量队列与 batchTimeout/batchSize 控制吞吐;写入失败要降级逐条写入并记录失败记录。" + - id: "implement-db" + title: "实现数据库 Schema 与持久化" + steps: + - "在 newProjectDir/src/db/ 复用 DatabaseManager 连接池模式。" + - "在 initTables 中创建 db.schemaName 与目标表/集合结构;为高频写入表添加必要索引。" + - "对高频时序数据按天分区:复用 scripts/db/020_partitioning_auto_daily.sql 的策略,必要时修改表名与分区键。" + - "写入接口提供:batchInsert(events) 返回 insertedCount 与 failedRecords。" + - id: "implement-redis-errors" + title: "实现错误上报与可重试队列" + steps: + - "保留现有 Redis 心跳与控制台日志 Key 约定(项目心跳、${projectName}_项目控制台)。" + - "新增错误队列 Key::errors(LIST)存储可重试错误记录 JSON。" + - "错误记录建议字段:errorId、firstSeenAt、lastSeenAt、attempts、topic、partition、offset、rawData、reason、stack。" + - "当 decode/validate/transform/db_write 失败且可重试时:RPUSH :errors 并同时写控制台日志。" + - "在 newProjectDir/src/retry/ 增加 RetryWorker:BLPOP :errors,按策略重放(调用 Processor 的单条处理入口),失败则回队列并 attempts+1。" + - "提供人工干预:支持将错误记录移动到 :errors:dead(超过最大 attempts)并保留查询入口。" + - id: "wiring-entry" + title: "串联入口与运行生命周期" + steps: + - "在 newProjectDir/src/index.js 复用现有启动顺序:Redis -> Stats -> DB -> Processor -> Kafka Consumers。" + - "保证任何启动/运行异常都写入 Redis 控制台日志(info/warn/error)。" + - "在 stop() 中优雅停止:停止 Stats、停止 Kafka、断开 DB、断开 Redis。" + - id: "build-package-deploy" + title: "构建、打包与部署" + steps: + - "在 newProjectDir/package.json 保持 npm run build 产出 dist/。" + - "PM2:提供 ecosystem.config.cjs(或从 assets/skill/templates/ecosystem.config.js 复制)并指向 dist 入口。" + - "Docker:提供 Dockerfile 与 docker-compose.yml(可直接从 assets/skill/templates 复制)。" + - "CI/CD:在 assets/skill/templates 中补充 pipeline 示例(如 GitHub Actions),执行 lint/test/build。" + - id: "verification" + title: "验证与交付" + steps: + - "执行 npm test、npm run lint、npm run build,确保通过。" + - "执行 scripts/db/smokeTest.js 与 scripts/redis/smokeTest.js(如存在)验证外部依赖可用。" + - "输出交付清单:.env.example、ecosystem.config.cjs、skill/、dist/ 构建产物。" +--- + +# BLS 后端组件构建 Skill + +## 触发 + +当用户说出以下语句时,启用本 Skill: + +- 开始构建BLS后端组件 + +## 目标 + +快速生成一个与当前仓库相同架构、相同运行环境、相同构建产物(dist/)的数据处理服务,新项目允许变化点仅包括: + +- Kafka 订阅 Topic 不同 +- Kafka 原始数据结构不同 +- 目标数据库 Schema 不同 +- 中间处理/转换/清洗/业务流程不同 + +同时必须具备: + +- 错误捕获并写入 Redis +- 从 Redis 读取错误并进行重试/人工介入的处理链路 + +## 输出约定 + +- 新项目目录:newProjectDir +- 代码目录:src/ +- 构建产物:dist/ +- 约束与模板资产:skill/ +- 运维资产:ecosystem.config.cjs、Dockerfile、docker-compose.yml、.env.example + +## 使用示例(对话风格) + +用户: + +开始构建BLS后端组件:业务=xxx,Topic=yyy,数据结构=zzz,落库=postgresql 表=aaa,转换规则=bbb。 + +本 Skill 需要生成: + +- 统一骨架 + 可替换的 Processor / DB Schema / Redis 错误队列 + +## 内置约束文件与模板 + +本 Skill 内置并随 Skill 发布的约束/模板文件位于: + +- assets/skill/ +- assets/skill/templates/ + +其中包含(与原有约束文件一致): + +- CONSTRAINTS.md(目录结构、代码规范、约束) +- KAFKA_PRODUCER.md(生产者对接) +- REDIS_ERROR_HANDLING.md(Redis 错误上报与监控) +- DATABASE_DESIGN.md(数据库设计约束) +- templates/.env.example、templates/ecosystem.config.js、templates/Dockerfile、templates/docker-compose.yml、templates/OPENAPI_TEMPLATE.yaml + +生成新项目时,必须将上述文件原样复制到新项目根目录下的 skill/ 目录,以保证可移植性与一致性。 + +## 生成后的项目使用要点 + +- 约束文件入口:newProjectDir/skill/CONSTRAINTS.md +- 环境变量模板:newProjectDir/skill/templates/.env.example +- PM2 模板:newProjectDir/skill/templates/ecosystem.config.js +- Docker 模板:newProjectDir/skill/templates/Dockerfile、newProjectDir/skill/templates/docker-compose.yml + +建议在新项目根目录执行: + +- 复制环境变量模板到根目录:cp skill/templates/.env.example .env +- 复制 PM2 模板到根目录:cp skill/templates/ecosystem.config.js ecosystem.config.cjs + diff --git a/.trae/skills/bls-backend-component-builder/assets/skill/CONSTRAINTS.md b/.trae/skills/bls-backend-component-builder/assets/skill/CONSTRAINTS.md new file mode 100644 index 0000000..6a28c12 --- /dev/null +++ b/.trae/skills/bls-backend-component-builder/assets/skill/CONSTRAINTS.md @@ -0,0 +1,31 @@ +# 项目约束与规范 + +## 1. 技术栈规范 +- **Runtime**: Node.js >= 18.0.0 +- **Language**: JavaScript (ES Modules) +- **Framework**: 原生 Node.js + Vite (构建) +- **Dependencies**: + - `kafka-node`: Kafka 客户端 + - `pg`: PostgreSQL 客户端 + - `redis`: Redis 客户端 + +## 2. 目录结构约定 +src/ +├── config/ # 配置文件 (config.js) +├── db/ # 数据库连接与操作 (databaseManager.js) +├── kafka/ # Kafka 消费者逻辑 (consumer.js) +├── processor/ # 业务处理逻辑 (heartbeatProcessor.js) +├── redis/ # Redis 集成与错误上报 (redisIntegration.js) +└── index.js # 程序入口 + +## 3. 代码规范 +- 使用 ES Modules (`import`/`export`)。 +- 异步操作统一使用 `async/await`。 +- 错误处理必须使用 `try/catch`,并上报至 Redis。 +- 配置文件不应硬编码,需通过环境变量注入。 + +## 4. 命名规范 +- 文件名:小驼峰 (camelCase),如 `databaseManager.js`。 +- 类名:大驼峰 (PascalCase),如 `DatabaseManager`。 +- 变量名:小驼峰 (camelCase)。 +- 常量名:全大写下划线 (UPPER_CASE),如 `MAX_CONNECTIONS`。 diff --git a/.trae/skills/bls-backend-component-builder/assets/skill/DATABASE_DESIGN.md b/.trae/skills/bls-backend-component-builder/assets/skill/DATABASE_DESIGN.md new file mode 100644 index 0000000..006c473 --- /dev/null +++ b/.trae/skills/bls-backend-component-builder/assets/skill/DATABASE_DESIGN.md @@ -0,0 +1,27 @@ +# 数据库设计指南 + +## 1. 连接管理 +本项目使用 `pg` 库的连接池 (`Pool`) 模式。 +配置参数见 `src/config/config.js` 和 `.env`。 + +## 2. Schema 定义 +- 建议将业务表放置在独立的 Schema 下,而非 `public`。 +- 必须包含 `created_at` (入库时间) 和业务时间戳字段。 + +## 3. 分区策略 (强制) +对于写入的数据,按天进行表分区。 +参考 `scripts/db/020_partitioning_auto_daily.sql`。 + +## 4. 示例建表语句 +```sql +CREATE SCHEMA IF NOT EXISTS my_business; + +CREATE TABLE IF NOT EXISTS my_business.events ( + id SERIAL PRIMARY KEY, + event_time TIMESTAMP NOT NULL, + payload JSONB, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_events_time ON my_business.events(event_time); +``` diff --git a/.trae/skills/bls-backend-component-builder/assets/skill/KAFKA_PRODUCER.md b/.trae/skills/bls-backend-component-builder/assets/skill/KAFKA_PRODUCER.md new file mode 100644 index 0000000..2a071b7 --- /dev/null +++ b/.trae/skills/bls-backend-component-builder/assets/skill/KAFKA_PRODUCER.md @@ -0,0 +1,36 @@ +# Kafka 数据接入指南 + +本指南用于指导数据生产者如何按照标准格式向 Kafka Topic 推送数据。 + +## 1. 基础要求 +- **Topic**: 根据业务需求定义的 Kafka Topic 名称。 +- **编码**: UTF-8 +- **格式**: JSON + +## 2. 消息结构建议 +为了确保数据的一致性和可追溯性,建议包含以下基础字段: + +| 字段 | 类型 | 说明 | 示例 | +|---|---|---|---| +| ts_ms | number | 毫秒级时间戳 | 1700000000123 | +| id | string | 唯一标识符 | "uuid-v4" | +| data | object | 业务数据载荷 | {...} | + +### Key 的使用 +建议使用能够唯一标识数据来源或业务实体的字符串作为 Kafka Message Key(如设备ID、订单ID),以保证同一实体的消息有序。 + +## 3. 示例 +```json +{ + "ts_ms": 1700000000123, + "id": "device-001", + "data": { + "temperature": 25.5, + "humidity": 60 + } +} +``` + +## 4. 压缩与批处理 +- 建议开启 `lz4` 或 `zstd` 压缩。 +- 适当配置 `batch.size` 和 `linger.ms` 以提高吞吐量。 diff --git a/.trae/skills/bls-backend-component-builder/assets/skill/REDIS_ERROR_HANDLING.md b/.trae/skills/bls-backend-component-builder/assets/skill/REDIS_ERROR_HANDLING.md new file mode 100644 index 0000000..7cd918e --- /dev/null +++ b/.trae/skills/bls-backend-component-builder/assets/skill/REDIS_ERROR_HANDLING.md @@ -0,0 +1,42 @@ +# Redis 错误处理与监控协议 + +本项目使用 Redis 作为错误日志的临时存储和心跳监控机制。 + +## 1. 配置要求 +每个项目必须配置唯一的 `REDIS_PROJECT_NAME`。 + +## 2. 心跳机制 (Heartbeat) +- **Key**: `项目心跳` (List) +- **Value**: JSON 字符串 +- **频率**: 每 3 秒写入一次 +- **用途**: 告知监控台该服务存活。 + +示例数据: +```json +{ + "projectName": "my-service", + "apiBaseUrl": "http://192.168.1.10:3000", + "lastActiveAt": 1700000000123 +} +``` + +## 3. 错误日志 (Error Logs) +- **Key**: `${projectName}_项目控制台` (List) +- **Value**: JSON 字符串 +- **用途**: 存储运行时错误、启动日志等。 + +示例数据: +```json +{ + "level": "error", + "message": "数据库连接失败", + "timestamp": 1700000000123, + "module": "db", + "stack": "Error: connection timeout..." +} +``` + +## 4. 集成方式 +项目中已封装 `RedisIntegration` 类,开发者只需调用: +- `redis.info(message, context)` +- `redis.error(message, context)` diff --git a/.trae/skills/bls-backend-component-builder/assets/skill/templates/.env.example b/.trae/skills/bls-backend-component-builder/assets/skill/templates/.env.example new file mode 100644 index 0000000..72c0dfb --- /dev/null +++ b/.trae/skills/bls-backend-component-builder/assets/skill/templates/.env.example @@ -0,0 +1,29 @@ +# Server Configuration +PORT=3000 +NODE_ENV=development + +# Kafka Configuration +KAFKA_BROKERS=localhost:9092 +KAFKA_TOPIC=my-topic-name +KAFKA_GROUP_ID=my-group-id +KAFKA_CLIENT_ID=my-client-id +KAFKA_CONSUMER_INSTANCES=1 +# KAFKA_SASL_USERNAME= +# KAFKA_SASL_PASSWORD= +# KAFKA_SASL_MECHANISM=plain + +# Database Configuration (PostgreSQL) +DB_HOST=localhost +DB_PORT=5432 +DB_USER=postgres +DB_PASSWORD=password +DB_DATABASE=my_database +DB_MAX_CONNECTIONS=10 + +# Redis Configuration +REDIS_HOST=localhost +REDIS_PORT=6379 +REDIS_PASSWORD= +REDIS_DB=0 +REDIS_PROJECT_NAME=my-project +REDIS_API_BASE_URL=http://localhost:3000 diff --git a/.trae/skills/bls-backend-component-builder/assets/skill/templates/Dockerfile b/.trae/skills/bls-backend-component-builder/assets/skill/templates/Dockerfile new file mode 100644 index 0000000..4f176f2 --- /dev/null +++ b/.trae/skills/bls-backend-component-builder/assets/skill/templates/Dockerfile @@ -0,0 +1,19 @@ +FROM node:18-alpine + +WORKDIR /app + +# Install dependencies +COPY package.json package-lock.json ./ +RUN npm ci + +# Copy source code +COPY . . + +# Build +RUN npm run build + +# Expose port +EXPOSE 3000 + +# Start command +CMD ["npm", "run", "start"] diff --git a/.trae/skills/bls-backend-component-builder/assets/skill/templates/OPENAPI_TEMPLATE.yaml b/.trae/skills/bls-backend-component-builder/assets/skill/templates/OPENAPI_TEMPLATE.yaml new file mode 100644 index 0000000..b154194 --- /dev/null +++ b/.trae/skills/bls-backend-component-builder/assets/skill/templates/OPENAPI_TEMPLATE.yaml @@ -0,0 +1,26 @@ +openapi: 3.0.0 +info: + title: Project API + version: 1.0.0 + description: API documentation for the service. +servers: + - url: http://localhost:3000 + description: Local server +paths: + /health: + get: + summary: Health check + responses: + '200': + description: Service is healthy + content: + application/json: + schema: + type: object + properties: + status: + type: string + example: "ok" + timestamp: + type: integer + format: int64 diff --git a/.trae/skills/bls-backend-component-builder/assets/skill/templates/docker-compose.yml b/.trae/skills/bls-backend-component-builder/assets/skill/templates/docker-compose.yml new file mode 100644 index 0000000..fcb405e --- /dev/null +++ b/.trae/skills/bls-backend-component-builder/assets/skill/templates/docker-compose.yml @@ -0,0 +1,55 @@ +version: '3.8' + +services: + app: + build: . + restart: always + ports: + - "3000:3000" + env_file: + - .env + depends_on: + - postgres + - redis + - kafka + + postgres: + image: postgres:15-alpine + restart: always + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: password + POSTGRES_DB: my_database + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + + redis: + image: redis:alpine + restart: always + ports: + - "6379:6379" + volumes: + - redis_data:/data + + zookeeper: + image: wurstmeister/zookeeper + ports: + - "2181:2181" + + kafka: + image: wurstmeister/kafka + ports: + - "9092:9092" + environment: + KAFKA_ADVERTISED_HOST_NAME: localhost + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + - zookeeper + +volumes: + postgres_data: + redis_data: diff --git a/.trae/skills/bls-backend-component-builder/assets/skill/templates/ecosystem.config.js b/.trae/skills/bls-backend-component-builder/assets/skill/templates/ecosystem.config.js new file mode 100644 index 0000000..af08eda --- /dev/null +++ b/.trae/skills/bls-backend-component-builder/assets/skill/templates/ecosystem.config.js @@ -0,0 +1,24 @@ +module.exports = { + apps: [{ + name: 'my-project-name', // 修改为实际项目名 + script: 'dist/index.js', // 确保指向构建后的入口文件 + instances: 1, + exec_mode: 'fork', + autorestart: true, + watch: false, + max_memory_restart: '1G', + env: { + NODE_ENV: 'production', + PORT: 3000 + }, + env_development: { + NODE_ENV: 'development', + PORT: 3000 + }, + error_file: './logs/error.log', + out_file: './logs/out.log', + log_date_format: 'YYYY-MM-DD HH:mm:ss Z', + merge_logs: true, + time: true + }] +};