shared/CLAUDE.md

13 KiB
Raw Blame History

CLAUDE.md — shared 共享库

概述

shared 是 tlyq.ai 项目群的共享库,包含后端认证、告警、审计、企业微信推送等标准模块,以及前端 React UI 组件库。所有模块遵循零业务依赖、配置驱动、TypeScript 优先的设计原则。


目录结构

shared/
├── lib/                            # 后端服务端库(无 barrel按路径直接导入
│   ├── auth/                       # 认证标准库
│   │   ├── types.ts                # 类型定义AuthConfig, SessionPayload, OidcUserinfo 等)
│   │   ├── jwt.ts                  # JWT 签名/验证零依赖Node crypto
│   │   ├── ldap.ts                 # LDAP 认证ldapts 客户端)
│   │   ├── oidc.ts                 # OIDC PKCE 流程openid-client
│   │   ├── middleware.ts           # Next.js 路由守卫工厂
│   │   └── user-sync.ts           # OIDC 用户同步到本地 SQLite
│   ├── alert/                      # 告警引擎
│   │   ├── types.ts                # 类型定义AlertLevel, ServiceStatus, CheckResult 等)
│   │   ├── alert-manager.ts        # AlertManager 告警决策引擎
│   │   └── health-checker.ts       # HealthChecker 健康检查引擎
│   ├── audit/                      # 审计日志
│   │   ├── audit-schema.ts         # audit_logs 表 DDL
│   │   └── write-audit-log.ts      # writeAuditLog 函数
│   ├── db/                         # 数据库 Schema 定义
│   │   └── alert-schema.ts         # 5 张表 DDLservices, alert_channels 等)
│   └── wechat/                     # 企业微信 Webhook
│       ├── message-formatter.ts    # 消息格式化
│       └── wechat-pusher.ts        # WeChatPusher 推送客户端
└── ui/                             # 前端 React 组件库(@tlyq/shared-ui
    ├── package.json                # 发布为 @tlyq/shared-ui v1.0.0
    ├── index.tsx                   # Barrel 导出9 个组件)
    ├── Button.tsx                  # 按钮4 种 variant3 种 sizeloading 状态)
    ├── Badge.tsx                   # 标签5 种 variant
    ├── Card.tsx                    # 卡片容器
    ├── Input.tsx                   # 输入框(含 label 和 error
    ├── Select.tsx                  # 下拉选择
    ├── Modal.tsx                   # 模态框backdrop 点击关闭body scroll 锁定)
    ├── Table.tsx                   # 表格styled theadtbody 由调用方提供)
    ├── Toast.tsx                   # 通知条(右下角固定定位)
    ├── Pagination.tsx              # 分页(中文标签:"上一页"/"下一页"
    └── login-page.tsx              # 统一登录页SSO + LDAP 切换,不在 barrel 中导出)

设计原则

零业务依赖

共享库不包含任何站点特定的业务逻辑。所有需要外部状态(数据库、配置)的模块通过 TypeScript 接口注入依赖,不耦合具体实现。

配置驱动

模块行为通过配置对象控制,而非硬编码。例如:

  • createMiddleware(config) 通过 AuthConfig 配置公开路径、管理路径、cookie 名称
  • AlertManager 通过 CooldownProvider 接口获取冷却状态
  • HealthChecker 通过 registerChecker() 注册检查器

TypeScript 优先

所有模块使用 TypeScript 编写,导出完整类型定义。消费方通过 tsconfig.jsonpaths 映射导入。


各模块详解

lib/auth/ — 认证标准库

统一认证栈OIDC SSO + LDAP 本地登录 + localadmin 应急用户 + 共享 JWT session。

types.ts

interface AuthConfig {
  jwtSecret: string
  cookieDomain: string
  cookieName?: string        // 默认 'tlyq_session'
  cookieMaxAge?: number      // 默认 7 天(秒)
  publicPaths?: string[]     // 公开路径(不需要认证)
  adminPaths?: string[]      // 管理路径(需要 admin 角色)
  ldapUrl?: string
  ldapBaseDn?: string
  autheliaUrl?: string
  oidcClientId?: string
  oidcClientSecret?: string
  oidcRedirectUri?: string
}

interface SessionPayload {
  sub: string        // 用户 ID 或 username
  username: string
  role: string
  exp: number
  iat: number
}

interface OidcUserinfo {
  sub: string
  preferred_username: string
  email?: string
  name?: string
  groups?: string[]
}

interface LdapAuthResult {
  success: boolean
  username?: string
  displayName?: string
  email?: string
  isAdmin?: boolean
  error?: string
}

jwt.ts

signJwt(options: { payload: SessionPayload, secret: string, expiresIn?: number }): string
verifyJwt(token: string, secret: string): SessionPayload | null
sharedCookieConfig(domain: string, maxAge?: number): CookieConfig

零外部依赖,使用 Node.js crypto 模块实现 HS256 JWT 签名和验证。

ldap.ts

ldapAuth(config: { url: string, baseDn: string }, username: string, password: string): Promise<LdapAuthResult>
checkAdminGroup(config: { url: string, baseDn: string }, username: string): Promise<boolean>

使用 ldapts 客户端进行 LDAP bind 认证和管理员组成员检查。

oidc.ts

discoverOidcConfig(url: string): Promise<OidcConfig>
generatePkce(): { codeVerifier: string, codeChallenge: string }
generateState(): string
buildAuthorizeUrl(config: OidcConfig, params: { clientId: string, redirectUri: string, state: string, codeChallenge: string }): string
exchangeCodeForToken(config: OidcConfig, code: string, verifier: string): Promise<TokenSet>
getUserinfo(url: string, accessToken: string): Promise<OidcUserinfo>

完整的 OIDC 授权码 + PKCE 流程,基于 Authelia 实现。

middleware.ts

createMiddleware(config: AuthConfig): NextMiddleware

Next.js 路由守卫工厂。验证 tlyq_session cookieJWT payload 解码,检查过期时间)。公开路径放行,管理路径检查 admin 角色,未认证请求重定向到 /login

user-sync.ts

syncOidcUser(store: UserSyncStore, userinfo: OidcUserinfo): Promise<{ id: number, role: string, isNew: boolean }>

将 OIDC userinfo 同步到本地 SQLite users 表。UserSyncStore 是依赖注入接口,不耦合具体数据库驱动。


lib/alert/ — 告警引擎

告警决策和健康检查的核心引擎。

types.ts

type AlertLevel = 'critical' | 'warning' | 'info'
type ServiceStatus = 'normal' | 'abnormal' | 'unknown'
type CheckType = 'http' | 'docker' | 'ssh'
type AlertType = 'alert' | 'recovery' | 'flapping'

interface HealthCheckConfig {
  type: CheckType
  url?: string           // HTTP 检查
  expectedStatus?: number
  expectedBody?: string
  containerName?: string // Docker 检查
  command?: string       // SSH 检查
}

interface CheckResult {
  success: boolean
  responseTime?: number
  errorMessage?: string
}

interface AlertDecision {
  shouldAlert: boolean
  reason?: string
  suppressedBy?: 'quiet_period' | 'cooldown' | 'flapping'
}

interface AlertChannelConfig {
  id: number
  levelCritical: boolean
  levelWarning: boolean
  levelInfo: boolean
  quietEnabled: boolean
  quietStart?: string
  quietEnd?: string
  quietBypassCritical: boolean
  cooldownMinutes: number
}

alert-manager.ts

class AlertManager {
  constructor(cooldownProvider: CooldownProvider)
  evaluate(channel: AlertChannelConfig, serviceId: number, level: AlertLevel, now?: Date): AlertDecision
  isQuietPeriod(channel: AlertChannelConfig, now?: Date): boolean
  isCoolingDown(channelId: number, serviceId: number, level: AlertLevel, cooldownMinutes: number): boolean
  recordAlert(channelId: number, serviceId: number, level: AlertLevel): void
}

三阶段告警决策:级别匹配 → 免打扰检查(支持跨午夜) → 冷却窗口检查。

CooldownProvider 是依赖注入接口:

interface CooldownProvider {
  getCooldown(key: string): number | null  // 返回 Unix 时间戳
  setCooldown(key: string, timestamp: number): void
}

health-checker.ts

class HealthChecker {
  registerChecker(type: CheckType, handler: Checker): void
  check(checks: HealthCheckConfig[], timeoutMs: number): Promise<CheckResult[]>
}

class HttpChecker implements Checker { ... }
class DockerChecker implements Checker { ... }

策略模式:通过 registerChecker() 注册检查器,新检查类型(如 SSH可无缝扩展。内部使用 Promise.allSettled 并发执行。


lib/audit/ — 审计日志

audit-schema.ts

const AUDIT_LOGS_TABLE_SQL: string  // audit_logs 表 DDL

write-audit-log.ts

interface AuditLogEntry {
  userId?: number
  username?: string
  action: string
  entityType: string
  entityId?: number
  details?: Record<string, unknown>
  ipAddress?: string
}

interface AuditStore {
  exec(sql: string): void
}

function writeAuditLog(store: AuditStore, entry: AuditLogEntry): void

使用 SQL 字符串拼接 + 单引号转义(非参数化查询),这是已知的设计选择。


lib/db/ — 数据库 Schema

alert-schema.ts

const SERVICES_TABLE_SQL: string
const ALERT_CHANNELS_TABLE_SQL: string
const ALERT_SETTINGS_TABLE_SQL: string
const STATUS_HISTORY_TABLE_SQL: string
const ALERT_HISTORY_TABLE_SQL: string
const ALL_TABLES_SQL: string  // 以上 5 个的拼接

定义监控相关的 5 张核心表,供各站点初始化数据库使用。


lib/wechat/ — 企业微信 Webhook

message-formatter.ts

formatAvailabilityMessage(params: { serviceName: string, status: string, ... }): string
formatAlertLevel(level: AlertLevel): string  // 返回带 emoji 的级别标签

wechat-pusher.ts

class WeChatPusher {
  constructor(webhookUrl: string)
  pushMarkdown(title: string, content: string): Promise<boolean>
  pushText(content: string): Promise<boolean>
}

class WeChatPusherCompat {
  // 兼容 issue-ai 的旧接口(返回 boolean
  pushMarkdown(title: string, content: string): Promise<boolean>
}

5 秒超时markdown 格式推送。WeChatPusherCompat 为迁移提供向后兼容。


ui/ — React 组件库

所有组件均为 'use client'Next.js App Router 兼容),使用 Tailwind CSS 工具类,支持 dark: 暗色模式。

导出方式

import { Button, Card, Badge, Table, Modal, Input, Select, Toast, Pagination } from '@shared/ui'
import LoginPage from '@shared/ui/login-page'  // 单独导入,不在 barrel 中
组件 核心 Props 说明
Button `variant: 'primary' 'secondary'
Badge `variant: 'default' 'success'
Card children, className? 白色/暗色圆角容器
Input label?, error? 带标签和错误提示的输入框
Select label?, options: {value, label}[] 下拉选择器
Modal open: boolean, onClose, title?, maxWidth? 无 portal 模态框backdrop 点击关闭,锁定 body scroll
Table headers: string[], children: ReactNode 样式化 theadtbody 由调用方提供
Toast message, `type: 'success' 'error'
Pagination page, totalPages, onPageChange 中文标签totalPages <= 1 时隐藏
LoginPage siteName: string, title?: string 完整登录页,支持 SSO 和 LDAP 切换

如何导入

tsconfig.json 配置

在消费方项目的 tsconfig.json 中添加路径映射:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"],
      "@shared/*": ["./shared/*"]
    }
  }
}

符号链接

在消费方项目根目录创建符号链接:

cd /Users/niuniu/programs/docker/monitor-ai
ln -s ../shared shared

导入示例

// 后端认证
import { signJwt, verifyJwt } from '@shared/lib/auth/jwt'
import { ldapAuth } from '@shared/lib/auth/ldap'
import { discoverOidcConfig, buildAuthorizeUrl } from '@shared/lib/auth/oidc'

// 告警引擎
import { AlertManager } from '@shared/lib/alert/alert-manager'
import { HealthChecker, HttpChecker, DockerChecker } from '@shared/lib/alert/health-checker'

// 审计日志
import { writeAuditLog } from '@shared/lib/audit/write-audit-log'

// 数据库 Schema
import { ALL_TABLES_SQL } from '@shared/lib/db/alert-schema'

// 企业微信
import { WeChatPusher } from '@shared/lib/wechat/wechat-pusher'

// UI 组件
import { Button, Card, Badge, Table, Modal, Input, Select, Toast, Pagination } from '@shared/ui'
import LoginPage from '@shared/ui/login-page'

设计模式

模式 应用位置 说明
依赖注入 CooldownProvider, UserSyncStore, AuditStore, Checker 接口 通过接口注入外部状态,不耦合具体数据库驱动
策略模式 HealthChecker.registerChecker() 可插拔检查器,新检查类型无需修改引擎
工厂模式 createMiddleware(config) 返回配置化的 Next.js middleware
适配器模式 WeChatPusherCompat 包装 WeChatPusher 提供旧接口兼容
Barrel 导出 ui/index.tsx 统一导出入口,消费方一行导入