项目整体架构与链路梳理
📦 项目结构
这是一个 Monorepo 架构的前端项目,使用 npm workspaces 管理多个包:
frontend-monorepo/
├── packages/
│ ├── console/ # 主控制台应用(核心业务)
│ ├── console-admin/ # 管理后台应用
│ ├── console-ui-renderer/ # UI 渲染服务(用于邮件/导出)
│ └── shared-library/ # 共享库(组件、数据模型核心、工具)
├── devtools-extension/ # 浏览器开发工具扩展
└── local-servers/ # 本地开发服务器(数据库等)
🏗️ 核心架构层次
项目采用分层架构,遵循单向数据流原则:
┌─────────────────────────────────────────────────┐
│ AppController (应用协调层) │
│ - AppController.ts │
│ - 应用启动时初始化(在 React 渲染之前) │
│ - 创建和管理所有下层组件 │
│ - 通过 Context 提供给 React 组件 │
│ - 包含所有 PageController 实例 │
└────────────────┬────────────────────────────────┘
│ 通过 Context 提供
↓
┌─────────────────────────────────────────────────┐
│ React Views (UI 层) │
│ - pages/ │
│ - components/ │
│ - 通过 Context 访问 AppController │
│ - 使用 hooks 访问数据和触发操作 │
└────────────────┬────────────────────────────────┘
│ 可选:通过 AppController 访问
↓
┌─────────────────────────────────────────────────┐
│ Page Controllers (页面协调层) │
│ - controllers/ │
│ - 由 AppController 创建和管理 │
│ - 协调复杂页面逻辑 │
│ - 管理页面特定状态 │
└────────────────┬────────────────────────────────┘
│ 访问
↓
┌─────────────────────────────────────────────────┐
│ DataModel (数据模型层) │
│ - DataModel/ │
│ - 由 AppController 创建 │
│ - 纯数据存储 (StorageObject) │
│ - 观察者模式,发出变更事件 │
│ - 无 UI 逻辑,无服务器调用 │
└─────┬───────────────────────────┬───────────────┘
│ 被读取 │ 被写入
↓ ↓
┌─────────────────────┐ ┌─────────────────────────────────┐
│ DataFetchers │ │ ActionManager (操作管理层) │
│ - DataFetchers/ │ │ - Actions/ │
│ - 读取数据时调用 │ │ - 由 AppController 创建 │
│ - 调用 ServerAPI │ │ - 所有数据变更通过 ActionManager│
└──────────┬──────────┘ │ - 乐观更新 + 自动回滚 │
│ └──────────┬──────────────────────┘
│ │ Action.save() 调用
│ ↓
│ ┌─────────────────────────────────┐
│ │ Action (操作实例) │
│ │ - 在 save() 方法中调用 ServerAPI│
│ └──────────┬──────────────────────┘
│ │
└─────────────────────────┼───────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ ServerAPI (服务器接口层) │
│ - ServerAPI/Requests/ │
│ - ServerAPI/Parse*Response.ts │
│ - 原始 API 调用和响应解析 │
│ - 被 DataFetchers 和 Action 调用 │
└─────────────────────────────────────────────────┘
🔄 数据流链路
1. 数据获取流程 (Read Flow)
用户操作/组件挂载
│
↓
Controller.loadData(filters)
│
↓
LoaderStatesManager.setLoading(true) // 显示加载状态
│
↓
DataFetchers.fetchData(filters, model)
│
├─→ ServerAPI.getData(filters) // 原始 API 调用
│ │
│ ↓
│ API Response (原始数据)
│ │
│ ↓
├─→ ParseResponse(response) // 转换为对象
│ │
│ ↓
│ Array<StorageObject>
│
↓
Model.storage.putObjects(objects) // 更新存储
│
↓
Storage 发出事件 (OBJECT_ADDED, OBJECT_UPDATED)
│
↓
React Hooks 触发重新渲染
│
↓
LoaderStatesManager.setLoading(false)
│
↓
UI 更新显示新数据
关键文件:
DataFetchers/*.ts- 数据获取器ServerAPI/Requests/*.ts- API 请求函数ServerAPI/Parse*Response.ts- 响应解析器DataModel/*/Model.ts- 数据模型
2. 数据更新流程 (Write Flow)
用户点击"更新"按钮
│
↓
Component: onClick={() => handleUpdate(id, newData)}
│
↓
创建 Action 实例
const action = new UpdateResourceAction(storage, id, newData)
│
↓
ActionManager.doAction(action)
│
├─→ action.doAction() // 立即应用(乐观更新)
│ │
│ ↓
│ storage.putObject(newObject) // UI 立即看到变化
│ │
│ ↓
│ Storage 发出事件
│ │
│ ↓
│ React 重新渲染
│
├─→ action.save() // 异步保存到服务器
│ │
│ ↓
│ ServerAPI.updateResource(id, newData) // Action 内部调用 ServerAPI
│ │
│ ├─→ 成功
│ │ │
│ │ ↓
│ │ 更新为服务器返回的数据
│ │ │
│ │ ↓
│ │ Toast 通知成功
│ │
│ └─→ 失败
│ │
│ ↓
│ action.undoAction() // 自动回滚
│ │
│ ↓
│ storage.putObject(oldObject)
│ │
│ ↓
│ Storage 发出事件
│ │
│ ↓
│ React 重新渲染(恢复原状)
│ │
│ ↓
│ Toast 通知失败
关键文件:
Actions/*.ts- Action 定义(在 save() 方法中调用 ServerAPI)Actions/ActionManager.ts- Action 管理器Actions/Action.ts- Action 基类ServerAPI/Requests/*.ts- API 请求函数(被 Action 和 DataFetchers 调用)
📁 核心目录结构
Console 包 (packages/console/)
src/
├── index.tsx # 应用入口
├── App.tsx # 根组件
├── AppController.ts # 应用控制器(单例)
├── AppDataModel.ts # 应用数据模型(聚合所有模型)
│
├── Router/ # 自定义路由系统
│ ├── Router.ts # 路由核心类
│ └── constants.ts # 路由常量
│
├── DataModel/ # 数据模型层
│ ├── SharedModel.ts # 共享模型(避免循环依赖)
│ ├── WorkloadDataModel.ts # 工作负载模型
│ ├── InventoryModel.ts # 库存模型
│ ├── DetectionModel.ts # 检测模型
│ ├── VulnerabilitiesModel.ts # 漏洞模型
│ └── ... # 其他业务模型
│
├── DataFetchers/ # 数据获取器
│ ├── workloadDataFetchers.ts
│ ├── timelineDataModelFetchers.ts
│ └── ...
│
├── ServerAPI/ # 服务器 API 层
│ ├── Requests/ # API 请求函数
│ │ ├── getResources.ts
│ │ └── ...
│ ├── Parse*Response.ts # 响应解析器
│ └── consoleRequestMiddlewares.ts # 请求中间件
│
├── Actions/ # 操作层
│ ├── ActionManager.ts # Action 管理器
│ ├── Action.ts # Action 基类
│ └── Update*Action.ts # 各种更新操作
│
├── controllers/ # 页面控制器
│ ├── WorkloadPageController.ts
│ ├── InventoryPageController.ts
│ └── ...
│
├── pages/ # 页面组件
│ ├── ThreatsPage/
│ ├── InventoryPage/
│ ├── VulnerabilitiesPage/
│ └── ...
│
├── components/ # 可复用组件
│ ├── UpwindHeader/
│ ├── UpwindLoader/
│ └── ...
│
├── hooks/ # 自定义 Hooks
│ ├── UseDataStorageObjects.ts # 访问存储对象
│ ├── UseObjectAttribute.ts # 访问对象属性
│ └── ...
│
├── services/ # 服务层
│ ├── AuthService.ts # 认证服务
│ ├── LoaderStatesManager.ts # 加载状态管理
│ └── ...
│
└── contexts/ # React Contexts
├── AppControllerContext.tsx
├── RouterContext.tsx
└── ...
🔑 核心概念
1. AppController (应用控制器)
应用级别的协调器,在 React 渲染之前初始化,负责整个应用的初始化和管理:
// 在 App.tsx 模块级别创建(React 渲染之前)
const appController = new AppController();
// 初始化顺序(在构造函数中):
1. 创建 AppDataModel(数据模型层)
2. 创建 SharedController(共享控制器)
3. 创建 ActionManager(操作管理层)
4. 创建 Router(路由管理)
5. 创建各种 Service(认证、加载状态等)
6. 创建所有 PageController 实例(页面控制器)
// 通过 Context 提供给 React 组件
<AppControllerContext.Provider value={appController}>
<Pages />
</AppControllerContext.Provider>
// 包含的核心组件:
- router: Router // 路由管理
- appDataModel: AppDataModel // 数据模型聚合
- actionManager: ActionManager // 操作管理
- authenticationService: AuthService // 认证服务
- loaderStatesManager: LoaderStatesManager // 加载状态
- 各种 PageController 实例 // 页面控制器(如 WorkloadPageController, InventoryPageController 等)
2. AppDataModel (应用数据模型)
聚合所有业务模型,是整个应用的数据模型根节点:
export class AppDataModel {
// 1. SharedModel - 共享模型(必须第一个创建)
public sharedModel: SharedModel;
// 2. 业务模型(按功能模块组织,约 20+ 个)
public workloadDataModel: WorkloadDataModel;
public inventoryModel: InventoryModel;
public newInventoryModel: NewInventoryModel;
public detectionsModel: DetectionModel;
public vulnerabilityModel: VulnerabilitiesModel;
public organizationDataModel: OrganizationModel;
public newPostureModel: NewPostureModel;
public policyModel: PolicyModel;
public issuesPageModel: IssuesPageModel;
public apiSecurityPageModel: ApiSecurityPageModel;
public identitiesModel: IdentitiesModel;
public identitiesDashboardModel: IdentitiesDashboardModel;
public aiPageModel: AiPageModel;
public codePageModel: CodePageModel;
public feedPageModel: FeedPageModel;
public onboardingModel: OnboardingModel;
public onboardingCenterModel: OnboardingCenterModel;
public panesModels: PanesModels;
public panesStorages: PanesStorages;
public chatDataModel: ChatDataModel;
// ... 更多业务模型
}
初始化顺序(在构造函数中):
constructor(...) {
// 1. 首先创建 SharedModel(所有其他模型都依赖它)
this.sharedModel = new SharedModel(...);
// 2. 然后创建所有业务模型,都传入 sharedModel
this.workloadDataModel = new WorkloadDataModel(this.sharedModel);
this.inventoryModel = new InventoryModel(this.sharedModel);
this.detectionsModel = new DetectionModel(this.sharedModel);
// ... 其他模型
}
2.1 SharedModel (共享模型)
作用:避免循环依赖 + 存储跨业务模块共享的数据
为什么需要 SharedModel?
如果所有业务模型都直接依赖 AppDataModel,会导致循环依赖问题:
AppDataModel → InventoryModel → AppDataModel (循环依赖!)
解决方案:引入 SharedModel 作为中间层
AppDataModel
├── SharedModel (共享数据)
└── 业务模型们 → 都依赖 SharedModel(而不是 AppDataModel)
SharedModel 包含的数据:
-
跨业务共享的存储:
cloudConnectedAccounts- 云账户(所有模块都需要)connectedClusters- 已连接集群(Inventory、Workload 都需要)integrationsStorage- 集成信息(Jira、Slack 等,多个模块使用)frameworksStorage- 框架数据(Configurations、Vulnerabilities 都需要)accountsStorage- 账户存储(多个模块需要)usersStorage- 用户信息(多个模块需要)savedQueriesStorage- 保存的查询(全局使用)apiSessionsStorage- API 会话(API Security 相关)cloudOrganizationUnits- 云组织单元(组织架构)- ... 更多共享存储
-
跨业务共享的对象:
computeCoverage- 计算覆盖率(Onboarding 使用)ciCdConnectivity- CI/CD 连接状态(Onboarding 使用)enabledConnections- 启用的连接(认证相关)samlConfiguration- SAML 配置(访问管理)- ... 更多共享对象
-
嵌套的子模型:
assetsModel- 资产模型(被多个业务模型使用)workloadDataModel- 工作负载模型(被多个业务模型使用)
使用示例:
// ✅ 正确:业务模型通过 SharedModel 访问共享数据
class InventoryModel {
constructor(sharedModel: SharedModel) {
// 访问共享的账户数据
const accounts = sharedModel.storages.cloudConnectedAccounts.getAllObjects();
// 访问共享的集群数据
const clusters = sharedModel.storages.connectedClusters.getAllObjects();
}
}
// ❌ 错误:直接依赖 AppDataModel 会导致循环依赖
class InventoryModel {
constructor(appDataModel: AppDataModel) {
// 这会导致循环依赖!
}
}
设计原则:
- ✅ SharedModel 优先创建:在 AppDataModel 构造函数中第一个创建
- ✅ 所有业务模型接收 SharedModel:而不是 AppDataModel
- ✅ SharedModel 只包含跨业务共享的数据:业务特定的数据放在各自的 Model 中
- ✅ 避免循环依赖:通过 SharedModel 解耦,而不是直接引用 AppDataModel
3. 完整层级关系图
从 AppDataModel 到最底层 DataStorage 的完整架构层级:
┌─────────────────────────────────────────────────────────────────────────┐
│ Level 1: AppDataModel (应用数据模型根节点) │
│ packages/console/src/AppDataModel.ts │
└─────────────────────────────────────────────────────────────────────────┘
│
┌─────────────┴─────────────┐
│ │
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────────────────────┐
│ SharedModel │ │ 业务模型们 (Business Models) │
│ (共享模型) │ │ - InventoryModel │
│ │ │ - VulnerabilitiesModel │
│ implements IDataModel │ │ - DetectionModel │
│ │ │ - OrganizationModel │
│ │ │ - ... (20+ 个业务模型) │
│ │ │ │
│ 包含三部分: │ │ 每个业务模型包含: │
│ │ │ │
│ 1. storages: { │ │ 1. storages: { │
│ cloudConnectedAccounts │ │ inventoryComputeAssetsStorage │
│ connectedClusters │ │ inventoryImagesStorage │
│ integrationsStorage │ │ ... (业务特定的 Storage) │
│ frameworksStorage │ │ } │
│ accountsStorage │ │ │
│ usersStorage │ │ 2. sharedModel: SharedModel (引用) │
│ ... (20+ 个 Storage) │ │ │
│ } │ │ 3. objects: { │
│ │ │ accountsCoverage: ObjectWithEvents │
│ 2. objects: { │ │ ... (业务特定的 Object) │
│ computeCoverage │ │ } │
│ ciCdConnectivity │ │ │
│ enabledConnections │ │ 4. 可能包含子模型 │
│ ... (10+ 个 Object) │ │ │
│ } │ │ │
│ │ │ │
│ 3. models: { │ │ │
│ assetsModel │ │ │
│ workloadDataModel │ │ │
│ } │ │ │
│ │ │ │
│ 4. events: EventEmitter │ │ │
└──────────────────────────┘ └──────────────────────────────────────────┘
│ │
│ │
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Level 2: DataStorage (数据存储层) │
│ packages/shared-library/src/DataModelCore/Storage/DataStorage.ts │
│ │
│ class DataStorage<TObject extends StorageObject> { │
│ protected index: Map<ID, TObject>; // ← 核心:Map 索引 │
│ protected events: EventEmitter<TEventsMap>; │
│ protected versionNumber: number; │
│ protected loadingObject: ObjectWithEvents<{ isLoading: boolean }>; │
│ protected _allObjectsCache: TObject[]; │
│ } │
│ │
│ 方法: │
│ - getObjectByID(id): O(1) 查找 │
│ - putObjects(objects): 添加/更新对象 │
│ - removeObjects(objects): 删除对象 │
│ - getAllObjects(): 获取所有对象 │
│ - emit(STORAGE_EVENTS.OBJECT_ADDED, ...): 发出事件 │
└─────────────────────────────────────────────────────────────────────────┘
│ │
│ │
│ │
├────────────────────────────────────┼──────────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────────────────┐ ┌──────────────────────────┐ ┌─────────────────┐
│ StorageObject │ │ ObjectWithEvents │ │ EventEmitter │
│ (存储在 DataStorage 中) │ │ (用于响应式状态) │ │ (事件系统) │
│ │ │ │ │ │
│ extends DataObject │ │ extends DataObject │ │ class EventEmitter│
│ │ │ │ │ { │
│ abstract class │ │ class ObjectWithEvents │ │ listeners: { │
│ StorageObject< │ │ <Attributes> { │ │ [eventName] │
│ RawAttributes, │ │ protected attributes:│ │ ?: Handler[]│
│ ParsedAttributes │ │ Attributes; │ │ } │
│ > { │ │ │ │ } │
│ protected attributes: │ │ protected │ │ │
│ ParsedAttributes; │ │ attributesChangedEvents:│ │ 方法: │
│ │ │ EventEmitter; │ │ - on() │
│ getId(): string │ │ │ │ - off() │
│ setID(id): void │ │ protected │ │ - emit() │
│ } │ │ objectEvents: │ │ │
│ │ │ EventEmitter; │ │ │
│ 具体实现: │ │ │ │ │
│ - ConnectedAccount │ │ 用途: │ │ │
│ - Cluster │ │ - computeCoverage │ │ │
│ - Integration │ │ - ciCdConnectivity │ │ │
│ - FrameworkFilterType │ │ - enabledConnections │ │ │
│ - User │ │ - loadingObject │ │ │
│ - Workflow │ │ - ... │ │ │
│ - ... (所有业务对象) │ │ │ │ │
└──────────────────────────┘ └──────────────────────────┘ └─────────────────┘
│ │
│ │
│ │
└────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Level 3: DataObject (数据对象基类) │
│ packages/shared-library/src/DataModelCore/DataObject.ts │
│ │
│ abstract class DataObject< │
│ RawAttributes extends {} = {}, │
│ ParsedAttributes extends {} = {} │
│ > { │
│ protected attributes: ParsedAttributes; // ← 核心:普通对象 │
│ │
│ // 属性访问 │
│ getAttribute<T>(name): T │
│ setAttribute<T>(name, value): void │
│ getAttributes(): ParsedAttributes │
│ setAttributes(attrs): void │
│ │
│ // 工具方法 │
│ toJSON(): RawAttributes │
│ clone(): this │
│ isEqual(other): boolean │
│ } │
└─────────────────────────────────────────────────────────────────────────┘
关键层级说明:
-
Level 1: AppDataModel
- 根节点,聚合所有业务模型
- 包含 SharedModel 和 20+ 个业务模型
示例数据:
const appDataModel = { sharedModel: SharedModel { /* 见下方 Level 2 */ }, inventoryModel: InventoryModel { /* 见下方 Level 2 */ }, vulnerabilityModel: VulnerabilitiesModel { ... }, detectionsModel: DetectionModel { ... }, organizationDataModel: OrganizationModel { ... }, // ... 20+ 个业务模型 }; -
Level 2: SharedModel & 业务模型
- SharedModel: 存储跨业务共享的数据(storages、objects、models)
- 业务模型: 存储业务特定的数据,都引用 SharedModel
SharedModel 示例数据:
const sharedModel = { storages: { cloudConnectedAccounts: DataStorage { index: Map { "acc-123" => ConnectedAccount { /* 见下方 Level 4 */ }, "acc-456" => ConnectedAccount { ... } } }, connectedClusters: DataStorage { index: Map { "cluster-789" => Cluster { /* 见下方 Level 4 */ } } }, integrationsStorage: IntegrationsStorage { ... }, frameworksStorage: DataStorage { ... }, usersStorage: DataStorage { ... }, // ... 20+ 个 Storage }, objects: { computeCoverage: ObjectWithEvents { attributes: { containerClusters: { sensor: 10, scanner: 5, none: 2 }, containerClusterAssets: { sensor: 150, scanner: 80, none: 30 }, scalingGroups: { sensor: 3, scanner: 1, none: 0 }, virtualMachines: { sensor: 25, scanner: 12, none: 5 } } }, ciCdConnectivity: ObjectWithEvents { attributes: { status: "CONNECTED", cdSourcesEventsLastStatus: { github: 1234567890 }, ciSourcesEventsLastStatus: { jenkins: 1234567891 } } }, enabledConnections: ObjectWithEvents { attributes: { connections: { is_social_connection_enabled: true, is_otp_connection_enabled: false, is_saml_connection_enabled: true, social_connection_types: ["google", "github"] } } } // ... 10+ 个 Object }, models: { assetsModel: AssetModel { ... }, workloadDataModel: WorkloadDataModel { ... } } };业务模型(InventoryModel)示例数据:
const inventoryModel = { storages: { inventoryComputeAssetsStorage: ComputeAssetsStorageWithFilters { index: Map { "asset-001" => InventoryComputeAsset { ... }, "asset-002" => InventoryComputeAsset { ... } } }, inventoryImagesStorage: InventoryImagesStorage { index: Map { "image-001" => InventoryImage { ... } } }, accountsStorage: DataStorageWithFilters { index: Map { "acc-123" => CloudProviderAccount { ... } } } // ... 更多业务特定的 Storage }, objects: { accountsCoverage: ObjectWithEvents { attributes: { cloudAccounts: { "acc-123": { computeAssets: 150, images: 45, vulnerabilities: 12 } } } } }, sharedModel: SharedModel { /* 引用到上面的 sharedModel */ } }; -
Level 3: DataStorage
- 核心存储容器,使用
Map<ID, Object>作为索引 - 内置事件系统(EventEmitter)
- O(1) 查找性能
DataStorage 示例数据:
const cloudConnectedAccountsStorage = DataStorage<ConnectedAccount> { // 核心索引:Map 结构 index: Map { "acc-123" => ConnectedAccount { attributes: { id: "acc-123", name: "Production AWS Account", cloudProvider: "AWS", hasConnectedCluster: true, hasConnectedHost: false, hasCloudScannerAdminRole: true } }, "acc-456" => ConnectedAccount { attributes: { id: "acc-456", name: "Staging GCP Account", cloudProvider: "GCP", hasConnectedCluster: true, hasConnectedHost: true, hasCloudScannerAdminRole: false } } }, // 事件系统 events: EventEmitter { listeners: { "OBJECT_ADDED": [ { handler: function, context: ReactComponent }, { handler: function, context: AnotherComponent } ], "OBJECT_UPDATED": [ ... ] } }, // 版本号(用于追踪变更) versionNumber: 15, // 加载状态 loadingObject: ObjectWithEvents { attributes: { isLoading: false } }, // 缓存所有对象的数组 _allObjectsCache: [ ConnectedAccount { id: "acc-123", ... }, ConnectedAccount { id: "acc-456", ... } ] }; - 核心存储容器,使用
-
Level 4: StorageObject & ObjectWithEvents
- StorageObject: 存储在 DataStorage 中的业务对象
- ObjectWithEvents: 响应式状态对象
- 都继承自 DataObject
StorageObject 示例数据(ConnectedAccount):
const connectedAccount = ConnectedAccount { // 继承自 DataObject attributes: { id: "acc-123", name: "Production AWS Account", cloudProvider: "AWS", hasConnectedCluster: true, hasConnectedHost: false, hasCloudScannerAdminRole: true }, // 方法(继承自 StorageObject) getId(): "acc-123", getName(): "Production AWS Account", getCloudProvider(): "AWS", isBYOC(): false, isCloudScannerAdminRole(): true };ObjectWithEvents 示例数据(computeCoverage):
const computeCoverage = ObjectWithEvents { // 继承自 DataObject attributes: { containerClusters: { sensor: 10, // 10 个集群有 sensor scanner: 5, // 5 个集群有 scanner none: 2 // 2 个集群没有保护 }, containerClusterAssets: { sensor: 150, scanner: 80, none: 30 }, scalingGroups: { sensor: 3, scanner: 1, none: 0 }, virtualMachines: { sensor: 25, scanner: 12, none: 5 } }, // 事件系统(ObjectWithEvents 特有) attributesChangedEvents: EventEmitter { listeners: { "containerClusters": [ handler1, handler2 ], "virtualMachines": [ handler3 ] } }, objectEvents: EventEmitter { listeners: { "OBJECT_CHANGED": [ handler1, handler2 ] } }, // 初始属性(用于重置) initialAttributes: { ... } }; -
Level 5: DataObject
- 所有数据对象的基类
- 管理
attributes对象 - 提供属性访问方法
DataObject 示例数据:
// ConnectedAccount 内部的 DataObject 部分 const dataObject = { // 核心:普通 JavaScript 对象 attributes: { id: "acc-123", name: "Production AWS Account", cloudProvider: "AWS", hasConnectedCluster: true, hasConnectedHost: false, hasCloudScannerAdminRole: true }, // 方法(继承自 DataObject) getAttribute("name"): "Production AWS Account", setAttribute("name", "New Name"): void, getAttributes(): { id: "acc-123", name: "Production AWS Account", cloudProvider: "AWS", hasConnectedCluster: true, hasConnectedHost: false, hasCloudScannerAdminRole: true }, toJSON(): { /* 同上 */ }, clone(): ConnectedAccount { /* 新实例 */ } };
数据流向:
服务器 API 响应
↓
Action.save() / DataFetcher
↓
DataStorage.putObjects([StorageObject, ...])
↓
DataStorage.index.set(id, object) // Map 操作
↓
EventEmitter.emit(OBJECT_ADDED, objects) // 发出事件
↓
React Hooks (useDataStorageObjects) 监听事件
↓
React 组件重新渲染
4. DataStorage (数据存储)
高性能的索引存储系统:
// 每个 Model 包含多个 Storage
export class InventoryModel {
public storages = {
assets: new DataStorage<Asset>(),
clusters: new DataStorage<Cluster>(),
// ...
};
}
// Storage 特性:
- O(1) 查找(通过 ID 索引)
- 事件驱动(发出 OBJECT_ADDED, OBJECT_UPDATED 等事件)
- 支持百万级对象
- 不可变对象(StorageObject)
4. StorageObject (存储对象)
所有数据对象的基类:
class Asset extends StorageObject {
// 通过 getAttribute/setAttribute 访问属性
getName(): string {
return this.getAttribute("name");
}
// 不可变:更新需要创建新对象
updateName(newName: string): Asset {
return new Asset({
...this.getAttributes(),
name: newName
});
}
}
6. Action Pattern (操作模式)
所有数据变更通过 Action:
// 1. 定义 Action
class UpdateAssetAction extends Action {
constructor(
private storage: DataStorage<Asset>,
private assetId: string,
private newAttributes: Partial<AssetAttributes>
) {
super();
this.oldAsset = storage.getObjectByID(assetId)!;
this.newAsset = new Asset({
...this.oldAsset.getAttributes(),
...newAttributes
});
}
doAction() {
this.storage.putObject(this.newAsset); // 乐观更新
}
undoAction() {
this.storage.putObject(this.oldAsset); // 回滚
}
async save(): Promise<Asset> {
const response = await updateAssetAPI(this.assetId, this.newAttributes);
const serverAsset = new Asset(response);
this.storage.putObject(serverAsset);
return serverAsset;
}
}
// 2. 使用 Action
const action = new UpdateAssetAction(storage, "a1", { name: "New Name" });
await actionManager.doAction(action);
6. Router (路由系统)
自定义路由,支持复杂参数和层级:
// Router 管理:
- pathName: string // 当前路径
- filters: FilterOptions // 过滤器
- selectedResourceId: string // 选中的资源
- sidePaneType: SidePaneType // 侧边栏类型
- ... 更多路由参数
// 路由变更流程:
1. 用户操作 → router.pushAttributes({ ... })
2. Router 更新内部状态
3. Router 发出事件 (change:attributeName)
4. Router 延迟推送到浏览器历史
5. 浏览器历史变更 → Router 从历史同步
6. 组件通过 hooks 监听路由变化
7. ServerAPI (服务器接口层)
统一的后端 API 交互层,负责所有与后端的通信:
// ServerAPI 结构:
ServerAPI/
├── Requests/ # API 请求函数(按功能模块组织)
│ ├── Inventory.ts # 库存相关 API
│ ├── Detections.ts # 检测相关 API
│ └── ...
├── Parse*Response.ts # 响应解析器(将后端响应转换为对象)
└── consoleRequestMiddlewares.ts # 请求中间件(RBAC 错误处理等)
// 核心请求处理(shared-library/src/ServerAPI/Request.ts):
- 统一的 API 请求处理
- 自动 token 管理(获取、刷新)
- 请求/响应中间件支持
- 缓存策略(NO_CACHE, FROM_CACHE, FROM_NETWORK_AND_SAVE_TO_CACHE)
- 错误处理和日志记录
// 使用示例:
// 1. 定义请求函数
export const getResources = (filters: FilterOptions) => {
return apiRequest("/api/resources", { params: filters });
};
// 2. 解析响应
export const parseResourceResponse = (response: ResourceResponse): Resource[] => {
return response.items.map(item => new Resource(item));
};
// 3. 在 DataFetchers 中使用
const response = await getResources(filters);
const resources = parseResourceResponse(response);
storage.putObjects(resources);
关键特性:
- ✅ 统一入口:所有后端请求通过 ServerAPI
- ✅ 类型安全:完整的 TypeScript 类型定义
- ✅ 中间件机制:支持请求/响应中间件(认证、错误处理)
- ✅ 自动认证:token 自动获取和刷新
- ✅ 响应解析:将后端响应转换为前端对象
🔌 React Hooks 生态系统
数据访问 Hooks
// 1. 访问存储中的对象
const [assets] = useDataStorageObjects(
appController.appDataModel.inventoryModel.storages.assets
);
// 2. 访问单个对象
const [asset] = useDataStorageObject(
appController.appDataModel.inventoryModel.storages.assets,
assetId
);
// 3. 访问对象属性(自动订阅变更)
const [name] = useObjectAttribute(asset, "name");
const [status] = useObjectAttribute(asset, "status");
// 4. 访问路由属性
const [pathName] = useRouterAttribute(router, "pathName");
const [selectedId] = useRouterAttribute(router, "selectedResourceId");
权限控制 Hooks
// RBAC 按钮禁用
const restrictButton = useRbacDisableButton(
PERMISSION_CONSTANT,
{ isAllowedOnlyForAdmin: true }
);
// RBAC 网络错误
const [rbacError] = useRbacNetworkError();
const [rbacError] = useConsoleRequestState(storage);
🛣️ 路由与页面
主要页面路由
// Pages.tsx 中定义
- /settings/* → SettingsPage
- /configurations/* → NewPosturePage
- /threats/* → ThreatsPage
- /inventory/* → InventoryPage
- /vulnerabilities/* → VulnerabilitiesPage
- /api/* → APISecurity
- /home/* → IssuesPage
- /identities/* → IdentitiesPage
- /code/* → CodePage
- /feed/* → FeedPage
- /ai/* → AiPage
- /custom-dashboard/* → CustomDashboardPage
页面结构
每个页面通常包含:
- Page Component - 页面主组件
- Page Controller - 页面控制器(可选,复杂页面使用)
- Tabs/Views - 页面内的标签页和视图
- Components - 页面特定组件
🔐 认证与权限
认证流程
// App.tsx 中初始化
useEffect(() => {
appController.authenticateUser();
}, []);
// AuthService 处理:
- Auth0 集成
- Token 管理
- 用户信息获取
- 认证状态管理
RBAC (基于角色的访问控制)
// 1. 按钮级别权限
const restrictButton = useRbacDisableButton(
SETTINGS_UPDATE_PERMISSION,
{ isAllowedOnlyForAdmin: true }
);
// 2. 内容级别权限
const [rbacError] = useConsoleRequestState(storage);
<WithMissingPermissionsNetworkErrorGuard error={rbacError}>
<ProtectedContent />
</WithMissingPermissionsNetworkErrorGuard>
// 3. 功能开关
const isFeatureEnabled = authenticationService.isFeatureFlagOpen(
FeatureFlagId.CONSOLE_MY_FEATURE,
false
);
📦 Shared Library
共享库包含可复用的核心功能:
shared-library/src/
├── DataModelCore/ # 数据模型核心
│ ├── Storage/ # DataStorage, StorageObject
│ ├── EventEmitter.ts # 事件发射器
│ ├── ObjectWithEvents.ts # 带事件的对象
│ └── Filters/ # 过滤器系统
│
├── components/ # 共享 UI 组件
│ ├── PrimaryButton/
│ ├── InputText/
│ └── ...
│
├── hooks/ # 共享 Hooks
│ ├── UseDataStorageObjects.ts
│ ├── UseObjectAttribute.ts
│ └── ...
│
├── ServerAPI/ # 共享 API 工具
│ └── Request.ts # API 请求基础
│
├── GraphModels/ # 图数据模型
│ └── ...
│
└── Chat/ # 聊天功能模块
├── ChatController.ts
├── ChatModel/
└── ChatUI/
🎯 关键设计模式
1. 观察者模式 (Observer Pattern)
// Storage 发出事件
storage.events.on(STORAGE_EVENTS.OBJECT_ADDED, (object) => {
// 处理对象添加
});
// React Hook 自动订阅
const [objects] = useDataStorageObjects(storage);
// Hook 内部监听事件,触发重新渲染
2. 命令模式 (Command Pattern)
// 所有变更通过 Action
const action = new UpdateAction(...);
await actionManager.doAction(action);
3. 单例模式 (Singleton)
// AppController 是单例
const appController = new AppController();
// 通过 Context 全局访问
const { appController } = useContext(AppControllerContext);
4. 工厂模式 (Factory Pattern)
// 创建 StorageObject
const asset = new Asset(attributes);
// 解析响应时批量创建
const assets = response.items.map(item => new Asset(item));
🚀 启动流程
1. 应用初始化 (index.tsx)
1. 设置后端 URL
2. 初始化 Google Analytics
3. 创建 React Root
4. 渲染 <App />
2. AppController 初始化 (App.tsx 模块级别)
// 在 React 渲染之前,模块级别创建
const appController = new AppController();
// AppController 构造函数执行顺序:
1. 创建 AppDataModel
└─→ 创建所有业务 Model(WorkloadDataModel, InventoryModel 等)
2. 创建 SharedController
└─→ 创建 ActionManager
└─→ 创建 Router
└─→ 创建各种 Service(AuthService, LoaderStatesManager 等)
3. 创建所有 PageController 实例
└─→ WorkloadPageController
└─→ InventoryPageController
└─→ ... 其他页面控制器
3. App 组件 (App.tsx)
1. AppController 已在模块级别创建(单例)
2. 通过 Context 提供给所有子组件
<AppControllerContext.Provider value={appController}>
3. 初始化认证 (appController.authenticateUser())
4. 监听认证状态
5. 渲染路由和页面
4. 页面加载
1. Router 匹配路由
2. 渲染对应 Page Component
3. Page Component 通过 Context 访问 AppController
4. Page Component 访问对应的 PageController(已由 AppController 创建)
5. PageController.loadData() 获取数据
6. DataFetchers 调用 ServerAPI
7. 解析响应,创建 StorageObject
8. 更新 Storage,触发事件
9. React Hooks 订阅事件,触发重新渲染
10. UI 更新显示新数据
📊 数据模型关系
AppDataModel
├── SharedModel (共享模型,避免循环依赖)
│ ├── assetsStorage: DataStorage<Asset>
│ ├── endpointsStorage: DataStorage<Endpoint>
│ └── ...
│
├── WorkloadDataModel
│ ├── storages.endpoints: DataStorage<Endpoint>
│ ├── storages.workloads: DataStorage<Workload>
│ └── 依赖 SharedModel
│
├── InventoryModel
│ ├── storages.assets: DataStorage<Asset>
│ ├── storages.clusters: DataStorage<Cluster>
│ └── 依赖 SharedModel
│
└── ... 其他模型
🔧 开发工作流
添加新功能
-
定义数据模型 (
DataModel/)- 创建 StorageObject 类
- 创建 Model 类(包含 Storage)
- 在 AppDataModel 中注册
-
创建 API 接口 (
ServerAPI/)Requests/getXxx.ts- API 请求函数ParseXxxResponse.ts- 响应解析器
-
创建数据获取器 (
DataFetchers/)- 调用 ServerAPI
- 解析响应
- 更新 Model Storage
-
创建 Action (
Actions/)- 定义更新/删除等操作
- 实现乐观更新和回滚
-
创建页面/组件 (
pages/,components/)- 使用 Hooks 访问数据
- 使用 ActionManager 执行操作
- 监听路由和模型事件
-
可选:创建 Controller (
controllers/)- 复杂页面逻辑协调
- 管理页面状态
🎨 样式系统
- 组件级 SCSS:每个组件有自己的
.scss文件 - CSS 变量:主题和颜色使用 CSS 变量
- Flexbox/Grid:现代布局系统
- 避免全局样式:组件样式隔离
📝 总结
这是一个企业级、大规模、高性能的前端应用,采用:
✅ 分层架构 - 清晰的职责分离
✅ 单向数据流 - 可预测的状态管理
✅ 事件驱动 - 解耦的组件通信
✅ 乐观更新 - 优秀的用户体验
✅ 类型安全 - 完整的 TypeScript 支持
✅ 高性能 - 支持百万级数据对象
✅ 可维护 - 清晰的代码组织
核心思想:数据向下流动,操作向上传递,通过 ActionManager 统一管理所有变更。