## 当前状态 - 插件界面已完成重命名 (cursorpro → hummingbird) - 双账号池 UI 已实现 (Auto/Pro 卡片) - 后端已切换到 MySQL 数据库 - 添加了 Cursor 官方用量 API 文档 ## 已知问题 (待修复) 1. 激活时检查账号导致无账号时激活失败 2. 未启用无感换号时不应获取账号 3. 账号用量模块不显示 (seamless 未启用时应隐藏) 4. 积分显示为 0 (后端未正确返回) 5. Auto/Pro 双密钥逻辑混乱,状态不同步 6. 账号添加后无自动分析功能 ## 下一版本计划 - 重构数据模型,优化账号状态管理 - 实现 Cursor API 自动分析账号 - 修复激活流程,不依赖账号 - 启用无感时才分配账号 - 完善账号用量实时显示 ## 文件说明 - docs/系统设计文档.md - 完整架构设计 - cursor 官方用量接口.md - Cursor API 文档 - 参考计费/ - Vibeviewer 开源项目参考 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
109 lines
6.9 KiB
Plaintext
109 lines
6.9 KiB
Plaintext
---
|
|
alwaysApply: true
|
|
title: Vibeviewer Architecture Guidelines
|
|
---
|
|
|
|
## Background
|
|
|
|
- The project uses a layered, modular Swift Package architecture with goals: minimal public surface, one-way dependencies, single responsibility, testability, and replaceability.
|
|
- Layers and dependency direction (top-down only):
|
|
- Core/Shared → common utilities and extensions (no business-layer dependencies)
|
|
- Model → pure data/DTO/domain entities (may depend on Core)
|
|
- API/Service → networking/IO/3rd-party orchestration and DTO→domain mapping (depends on Model + 3rd-party)
|
|
- Feature/UI → SwiftUI views and interactions (depends on API-exposed service protocols and domain models; must not depend on networking libraries)
|
|
- Architectural style: Native SwiftUI MV (not MVVM). State via @State/@Observable; dependency injection via @Environment; concurrency with async/await and @MainActor.
|
|
|
|
## Do (Recommended)
|
|
|
|
- Module placement & responsibilities
|
|
- Before adding code, decide whether it belongs to UI/Service/Model/Core and place it in the corresponding package/directory; one type/responsibility per file.
|
|
- The API layer exposes only “service protocol + default implementation”; networking library/targets/plugins are encapsulated internally.
|
|
- Service functions return domain models (Model-layer entities) or clear error types; avoid leaking DTOs to the UI.
|
|
|
|
- Domain models & mapping
|
|
- Abstract API response DTOs into domain entities (e.g., UserProfile / UsageOverview / TeamSpendOverview / UsageEvent / FilteredUsageHistory).
|
|
- Perform DTO→domain mapping in the API layer; UI consumes domain-only.
|
|
|
|
- Dependencies & visibility
|
|
- One-way: Core ← Model ← API ← Feature.
|
|
- Default to internal; use public only for cross-package use; prefer protocols over concrete types.
|
|
|
|
- SwiftUI & concurrency
|
|
- Inject services via @Environment; place side effects in .task / .onChange so they automatically cancel with the view lifecycle.
|
|
- UI updates occur on @MainActor; networking/IO on background using async/await; cross-isolation types must be Sendable.
|
|
|
|
- Testing & replaceability
|
|
- Provide an injectable network client interface for services; separate default implementation from testable construction paths.
|
|
- Put utilities/algorithms into Core; prefer pure functions for unit testing and reuse.
|
|
|
|
- Troble Shooting
|
|
- if you facing an lint error by "can't not found xxx in scope" when you edit/new/delete some interface on Package, that means you need to call XCodeBuildMCP to rebuild that package, so that other package can update the codebase to fix that error
|
|
|
|
## Don't (Avoid)
|
|
|
|
- UI directly depending on networking libraries, triggering requests, or being exposed to backend error details.
|
|
- Feature depending on API internals (e.g., Targets/Plugins/concrete networking implementations).
|
|
- Exposing API DTOs directly to the UI (causes global coupling and fragility).
|
|
- Reverse dependencies (e.g., Model depends on Feature; API depends on UI).
|
|
- Introducing MVVM/ViewModel as the default; or using Task { } in onAppear (use .task instead).
|
|
- Overusing public types/initializers; placing multiple unrelated types in one file.
|
|
|
|
## Review checklist
|
|
|
|
1) Quadrant self-check (placement)
|
|
- UI/interaction/rendering → Feature/UI
|
|
- Networking/disk/auth/3rd-party → API/Service
|
|
- Pure data/DTO/state aggregation → Model
|
|
- Utilities/extensions/algorithms → Core
|
|
|
|
2) Surface area & replaceability
|
|
- Can it be exposed via protocol to hide details? Is internal sufficient by default?
|
|
- Do services return only domain models/error enums? Is it easy to replace/mock?
|
|
|
|
3) Dependency direction & coupling
|
|
- Any violation of Core ← Model ← API ← Feature one-way dependency?
|
|
- Does the UI still reference DTOs or networking implementations? If yes, move mapping/abstraction to the API layer.
|
|
|
|
4) Concurrency & thread safety
|
|
- Are UI updates on @MainActor? Are cross-isolation types Sendable? Are we using async/await?
|
|
- Should serialization-required persistence/cache be placed within an Actor boundary?
|
|
|
|
5) File organization & naming
|
|
- Clear directories (Feature/Views, API/Service, API/Targets, API/Plugins, Model/Entities, Core/Extensions).
|
|
- One type per file; names reflect layer and responsibility (e.g., FeatureXView, FeatureXService, GetYAPI, ZResponse).
|
|
- Package directory structure: Sources/<PackageName>/ organized by feature subfolders; avoid dumping all source at one level.
|
|
- Suggested subfolders:
|
|
- API: Service / Targets / Plugins / Mapping (DTO→Domain mapping)
|
|
- Feature: Views / Components / Scenes / Modifiers
|
|
- Model: Entities
|
|
- Core: Extensions / Utils
|
|
- Consistent naming: use a shared prefix/suffix for similar features for discoverability.
|
|
- Suffix examples: …Service, …API, …Response, …Request, …View, …Section, …Window, …Plugin, …Mapper.
|
|
- Use a consistent domain/vendor prefix where needed (e.g., Cursor…).
|
|
- File name equals type name: each file contains only one primary type; exact case-sensitive match.
|
|
- Protocol/implementation convention: protocol uses FooService; default implementation uses DefaultFooService (or LiveFooService). Expose only protocols and inject implementations.
|
|
|
|
- Model-layer naming (Entities vs DTOs):
|
|
- Entities (exposed to business/UI):
|
|
- Use domain-oriented neutral nouns; avoid vendor prefixes by default (e.g., UserProfile, UsageOverview, TeamSpendOverview, UsageEvent, FilteredUsageHistory, AppSettings, Credentials, DashboardSnapshot).
|
|
- If source domain must be shown (e.g., “Cursor”), use a consistent prefix within that domain (e.g., CursorCredentials, CursorDashboardSnapshot) for consistency and discoverability.
|
|
- Suggested suffixes: …Overview, …Snapshot, …History, …Event, …Member, …RoleCount.
|
|
- Prefer struct, value semantics, and Sendable; expose public types/members only when needed cross-package.
|
|
- File name equals type name; single-type files.
|
|
- DTOs (API layer only, under API/Mapping/DTOs):
|
|
- Use vendor/source prefix + semantic suffix: e.g., Cursor…Request, Cursor…Response, Cursor…Event.
|
|
- Default visibility is internal; do not expose to Feature/UI; map to domain in the API layer only.
|
|
- File name equals type name; single-type files; field names mirror backend responses (literal), adapted to domain naming via mapping.
|
|
- Mapping lives in the API layer (Service/Mapping); UI/Feature must never depend on DTOs.
|
|
|
|
## Pre-PR checks
|
|
- Remove unnecessary public modifiers; check for reverse dependencies across layers.
|
|
- Ensure UI injects services via @Environment and contains no networking details.
|
|
- Ensure DTO→domain mapping is complete, robust, and testable.
|
|
|
|
Note: When using iOS 26 features, follow availability checks and progressive enhancement; ensure reasonable fallbacks for older OS versions.
|
|
|
|
## FAQ
|
|
- After adding/removing module code, if lint reports a missing class but you are sure it exists, rebuild the package with XcodeBuild MCP and try again.
|
|
|