Skip to content

Commit 16e1653

Browse files
authored
refactor: modern arch (#9)
* refactor: modern arch * refactor: tauri dev * fix: window size * fix: center window * refactor: clean codes
1 parent 196763b commit 16e1653

122 files changed

Lines changed: 11827 additions & 851 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cursorrules

Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
# Aumate 项目开发规范
2+
3+
## 🏗️ 架构原则
4+
5+
### DDD 分层架构
6+
7+
本项目采用 Domain-Driven Design (DDD) 分层架构,严格遵循依赖倒置原则:
8+
9+
```
10+
API Layer (Tauri Commands)
11+
↓ 调用
12+
Application Layer (Use Cases)
13+
↓ 依赖接口
14+
Domain Layer (Ports - Trait接口)
15+
↑ 实现接口
16+
Infrastructure Layer (Adapters)
17+
```
18+
19+
### 核心规则
20+
21+
1. **依赖方向**
22+
- Domain Layer 定义接口(Ports),不依赖任何其他层
23+
- Infrastructure Layer 实现接口(Adapters)
24+
- Application Layer 通过接口调用,不直接依赖具体实现
25+
- API Layer 仅做参数验证和调用 Use Cases
26+
27+
2. **单一职责**
28+
- API Layer: 参数验证、错误转换
29+
- Application Layer: 业务流程编排
30+
- Domain Layer: 领域模型和业务规则
31+
- Infrastructure Layer: 技术实现细节
32+
33+
3. **命名约定**
34+
- Port接口: `xxxPort` (如 `ScreenCapturePort`)
35+
- Adapter实现: `xxxAdapter` (如 `ScreenCaptureAdapter`)
36+
- Use Case: `xxxUseCase` (如 `CaptureScreenUseCase`)
37+
- DTO: `xxxDto` / `xxxRequest` / `xxxResponse`
38+
39+
## 📦 代码组织
40+
41+
### Crate 结构
42+
43+
```
44+
crates/
45+
├── core/
46+
│ ├── shared/ # 共享类型、错误定义
47+
│ ├── domain/ # 领域模型
48+
│ └── traits/ # Port 接口定义
49+
├── application/ # Use Cases + DTOs
50+
└── infrastructure/ # Adapters + Services
51+
52+
aumate-app/src-tauri/ # API Layer (应用特定)
53+
└── src/
54+
├── commands/ # Tauri Commands
55+
├── state.rs # AppState
56+
└── setup.rs # 依赖注入
57+
```
58+
59+
### 新功能实现流程
60+
61+
当添加新功能时,按照以下顺序实现:
62+
63+
#### 1. Domain Layer - 定义接口
64+
65+
**位置**: `crates/core/traits/src/`
66+
67+
```rust
68+
// crates/core/traits/src/my_feature.rs
69+
use async_trait::async_trait;
70+
use aumate_core_shared::InfrastructureError;
71+
72+
#[async_trait]
73+
pub trait MyFeaturePort: Send + Sync {
74+
async fn do_something(&self) -> Result<MyResult, InfrastructureError>;
75+
}
76+
```
77+
78+
**导出**: 在 `crates/core/traits/src/lib.rs` 中添加:
79+
```rust
80+
pub mod my_feature;
81+
pub use my_feature::MyFeaturePort;
82+
```
83+
84+
#### 2. Infrastructure Layer - 实现 Adapter
85+
86+
**位置**: `crates/infrastructure/src/adapters/`
87+
88+
```rust
89+
// crates/infrastructure/src/adapters/my_feature.rs
90+
use async_trait::async_trait;
91+
use aumate_core_traits::MyFeaturePort;
92+
93+
pub struct MyFeatureAdapter {
94+
// 字段
95+
}
96+
97+
impl MyFeatureAdapter {
98+
pub fn new() -> Self {
99+
Self {}
100+
}
101+
}
102+
103+
#[async_trait]
104+
impl MyFeaturePort for MyFeatureAdapter {
105+
async fn do_something(&self) -> Result<MyResult, InfrastructureError> {
106+
// 实现逻辑
107+
// 如果需要平台特定代码,使用:
108+
#[cfg(target_os = "macos")]
109+
{
110+
// macOS 实现
111+
}
112+
113+
#[cfg(target_os = "windows")]
114+
{
115+
// Windows 实现
116+
}
117+
}
118+
}
119+
```
120+
121+
**平台特定代码** (如需要):
122+
- 位置: `crates/infrastructure/src/platform/macos/` (或 `windows/`, `linux/`)
123+
- 在 Adapter 中调用平台特定函数
124+
125+
**导出**: 在 `crates/infrastructure/src/adapters/mod.rs` 中添加:
126+
```rust
127+
pub mod my_feature;
128+
pub use my_feature::MyFeatureAdapter;
129+
```
130+
131+
#### 3. Application Layer - Use Case + DTO
132+
133+
**Use Case** (`crates/application/src/use_cases/my_feature.rs`):
134+
```rust
135+
use aumate_core_shared::UseCaseError;
136+
use aumate_core_traits::MyFeaturePort;
137+
use std::sync::Arc;
138+
139+
pub struct MyFeatureUseCase {
140+
feature: Arc<dyn MyFeaturePort>,
141+
}
142+
143+
impl MyFeatureUseCase {
144+
pub fn new(feature: Arc<dyn MyFeaturePort>) -> Self {
145+
Self { feature }
146+
}
147+
148+
pub async fn execute(&self) -> Result<MyResultDto, UseCaseError> {
149+
log::info!("[MyFeatureUseCase] Executing");
150+
151+
let result = self.feature
152+
.do_something()
153+
.await
154+
.map_err(|e| e.into())?;
155+
156+
// 转换为 DTO
157+
Ok(result.into())
158+
}
159+
}
160+
```
161+
162+
**DTO** (`crates/application/src/dto/my_feature.rs`):
163+
```rust
164+
use serde::{Deserialize, Serialize};
165+
166+
#[derive(Debug, Clone, Serialize, Deserialize)]
167+
pub struct MyResultDto {
168+
// 字段
169+
}
170+
171+
// 实现 From trait 进行转换
172+
impl From<DomainType> for MyResultDto {
173+
fn from(value: DomainType) -> Self {
174+
Self {
175+
// 转换逻辑
176+
}
177+
}
178+
}
179+
```
180+
181+
**导出**:
182+
- `crates/application/src/use_cases/mod.rs` 添加 `pub mod my_feature;` 和 `pub use my_feature::*;`
183+
- `crates/application/src/dto/mod.rs` 添加 `pub mod my_feature;` 和 `pub use my_feature::*;`
184+
185+
#### 4. API Layer - Tauri Command (仅在应用层)
186+
187+
**注意**: API commands 只在 `aumate-app/src-tauri/src/commands/` 中,不在 crates 里
188+
189+
**位置**: `aumate-app/src-tauri/src/commands/my_feature.rs`
190+
191+
```rust
192+
use crate::state::AppState;
193+
use aumate_application::dto::MyResultDto;
194+
use aumate_core_shared::ApiError;
195+
use tauri::State;
196+
197+
#[tauri::command]
198+
pub async fn do_my_feature(
199+
state: State<'_, AppState>,
200+
) -> Result<MyResultDto, String> {
201+
log::info!("API: do_my_feature called");
202+
203+
state.my_feature_use_case
204+
.execute()
205+
.await
206+
.map_err(|e| {
207+
let api_error: ApiError = e.into();
208+
api_error.to_string()
209+
})
210+
}
211+
```
212+
213+
**注册命令**: 在 `aumate-app/src-tauri/src/lib.rs` 的 `invoke_handler` 中添加
214+
215+
#### 5. 依赖注入 - AppState
216+
217+
**State** (`aumate-app/src-tauri/src/state.rs`):
218+
```rust
219+
pub struct AppState {
220+
// ... existing fields ...
221+
pub my_feature_adapter: Arc<MyFeatureAdapter>,
222+
pub my_feature_use_case: Arc<MyFeatureUseCase>,
223+
}
224+
```
225+
226+
**Setup** (`aumate-app/src-tauri/src/setup.rs`):
227+
```rust
228+
pub fn setup_application() -> AppState {
229+
// 1. 创建 Adapter
230+
let my_feature_adapter = Arc::new(MyFeatureAdapter::new());
231+
232+
// 2. 创建 Use Case
233+
let my_feature_use_case = Arc::new(MyFeatureUseCase::new(
234+
my_feature_adapter.clone()
235+
));
236+
237+
// 3. 返回 AppState
238+
AppState {
239+
// ... existing fields ...
240+
my_feature_adapter,
241+
my_feature_use_case,
242+
}
243+
}
244+
```
245+
246+
## ⚠️ 重要禁止事项
247+
248+
### ❌ 不要在 Commands 中直接实现业务逻辑
249+
250+
**错误示例**:
251+
```rust
252+
#[tauri::command]
253+
pub async fn get_window_elements() -> Result<Vec<WindowElement>, String> {
254+
// ❌ 错误:直接在 command 中实现逻辑
255+
#[cfg(target_os = "macos")]
256+
{
257+
use core_graphics::window::CGWindowListCopyWindowInfo;
258+
// ... 大量实现代码 ...
259+
}
260+
}
261+
```
262+
263+
**正确做法**:
264+
```rust
265+
#[tauri::command]
266+
pub async fn get_window_elements(
267+
state: State<'_, AppState>
268+
) -> Result<Vec<WindowElementDto>, String> {
269+
// ✅ 正确:仅调用 Use Case
270+
state.get_window_elements
271+
.execute()
272+
.await
273+
.map_err(|e| e.into())
274+
}
275+
```
276+
277+
### ❌ 不要跨层直接依赖
278+
279+
- Domain Layer 不能依赖 Infrastructure/Application/API
280+
- Application Layer 不能直接依赖 Adapter 实现(只能依赖 Port 接口)
281+
- Infrastructure Layer 不能依赖 Application/API
282+
283+
### ❌ 不要在错误的地方定义类型
284+
285+
- 领域模型: `core/domain/` (如 `Image`, `Screenshot`)
286+
- 共享类型: `core/shared/` (如 `Rectangle`, `Point`, `MonitorId`)
287+
- DTO: `application/dto/` (用于 API 响应)
288+
- Port 接口: `core/traits/`
289+
290+
## 🔍 代码审查清单
291+
292+
提交代码前,检查:
293+
294+
- [ ] 新功能是否按照 DDD 分层实现?
295+
- [ ] Port 接口是否在 `core/traits` 定义?
296+
- [ ] Adapter 是否在 `infrastructure/adapters` 实现?
297+
- [ ] Use Case 是否在 `application/use_cases` 实现?
298+
- [ ] DTO 是否在 `application/dto` 定义?
299+
- [ ] API Command 是否只做参数验证和调用 Use Case?
300+
- [ ] 是否更新了模块导出 (`mod.rs`, `lib.rs`)?
301+
- [ ] 是否更新了 `AppState` 和 `setup_application`?
302+
- [ ] 是否在 `lib.rs` 中注册了新的 command?
303+
- [ ] 是否更新了相关文档 (README.md, ARCHITECTURE.md)?
304+
- [ ] 代码是否通过 `cargo check --workspace` 检查?
305+
- [ ] 是否添加了必要的测试?
306+
307+
## 📝 常用命令
308+
309+
```bash
310+
# 检查整个工作区
311+
cargo check --workspace
312+
313+
# 检查特定 crate
314+
cargo check --package aumate-infrastructure
315+
316+
# 运行测试
317+
cargo test --workspace
318+
319+
# 格式化代码
320+
cargo fmt --all
321+
322+
# Lint 检查
323+
cargo clippy --workspace -- -D warnings
324+
325+
# 编译发布版本
326+
cd aumate-app && pnpm tauri build
327+
```
328+
329+
## 🔗 相关文档
330+
331+
- 架构详解: `crates/docs/ARCHITECTURE.md`
332+
- 项目概览: `crates/docs/README.md`
333+
- 命令变更: `crates/docs/COMMANDS_CHANGELOG.md`
334+
335+
---
336+
337+
**记住**: 保持架构清晰,代码组织有序,遵循 DDD 原则,让代码更易维护和扩展!

0 commit comments

Comments
 (0)