# Arch Design Dashboard — 全量实现设计规格 ## 1. 概述 将 `design/` 目录下完整的架构设计文档转化为可运行的 Web 应用。系统是单体前后端分离架构,单人使用(无认证),设计文件为 single source of truth(无数据库)。 **实现范围:** MVP + Phase 2 全部功能。 **技术栈:** - 后端:Python 3.12 + FastAPI + Uvicorn,包管理用 uv - 前端:Vue 3 + TypeScript + Vite + Pinia + D3.js - 部署:Docker Compose + Nginx 反代 ## 2. 模块清单与实现顺序 全局顺序(自底向上):构建配置 → shared → design → project → scanner → graph → editor → impl_tracker → 前端 每个后端模块内部顺序:**Domain → Infrastructure → Application → Interfaces** | # | 模块 | 层 | 依赖 | 阶段 | |---|------|------|------|------| | 0 | 构建配置 | - | - | MVP | | 1 | shared | backend | - | MVP | | 2 | MOD-DESIGN | backend domain-only | - | MVP | | 3 | MOD-PROJECT | backend full | - | MVP | | 4 | MOD-SCANNER | backend full | MOD-DESIGN | MVP | | 5 | MOD-GRAPH | backend full | MOD-DESIGN | MVP | | 6 | MOD-EDITOR | backend full | MOD-DESIGN, MOD-SCANNER, MOD-GRAPH | Phase 2 | | 7 | MOD-IMPL-TRACKER | backend full | MOD-DESIGN, MOD-SCANNER | Phase 2 | | 8 | 前端基础设施 | frontend | - | MVP | | 9 | MOD-FE-PROJECT | frontend | 后端 MOD-PROJECT | MVP | | 10 | MOD-FE-GRAPH | frontend | 后端 MOD-SCANNER, MOD-GRAPH | MVP(impl-progress 功能延至 Phase 2,依赖 MOD-IMPL-TRACKER) | | 11 | MOD-FE-EDITOR | frontend | 后端 MOD-EDITOR, MOD-IMPL-TRACKER | Phase 2 | | 12 | Docker 部署 | infra | 前后端完成 | MVP | ## 3. 后端详细设计 ### 3.0 构建配置 - `backend/pyproject.toml`:Python 3.12+,依赖 fastapi, uvicorn, pyyaml, python-multipart - `backend/.python-version`:3.12 - `frontend/package.json`:vue 3, vue-router, pinia, d3, axios, vite, typescript - `frontend/vite.config.ts`:dev proxy `/api` → `localhost:8900` - `frontend/tsconfig.json` - `frontend/index.html` ### 3.1 shared 层 **shared/kernel/exceptions.py**: - `NotFoundError(entity: str, id: str)` — 404 - `ValidationError(message: str)` — 400 - `FileSystemError(path: str, message: str)` — 500 **shared/infrastructure/config.py**: - `Settings` dataclass:registry_path(projects.json 路径,默认 `~/.arch-design-dashboard/projects.json`) **shared/infrastructure/filesystem.py**: - `read_text(path) -> str` - `write_text(path, content)` - `list_files(directory, extensions) -> list[Path]` - `file_exists(path) -> bool` ### 3.2 MOD-DESIGN(核心领域,纯 Python) **序列化策略:** CSV 中的空格分隔字段(如 `related_value_flows`、`depends_on`、`capabilities`、`entity_ids`、`value_flow_ids`)在 Python domain 层存储为 `list[str]`。API 响应中也返回为 JSON 数组(`list[str]`),由 router 层负责转换。OpenAPI 契约中这些字段定义为 `string` 是文档缺陷,实现时以 `list[str]` 为准。 **domain/entities.py** — 28 种设计实体,用 `@dataclass` 定义: ```python # 业务层 @dataclass class Capability: capability_id: str name: str description: str priority: str # must / should / could phase: str related_value_flows: list[str] # CSV 中空格分隔,解析为列表 @dataclass class ValueFlow: value_flow_id: str name: str trigger: str actor: str steps: str outcome: str phase: str related_capabilities: list[str] @dataclass class UserJourney: journey_id: str name: str actor: str precondition: str steps: str postcondition: str phase: str related_value_flows: list[str] @dataclass class ScopeAndGoals: doc_id: str title: str core_problem: str users: str constraints: str # 应用层 @dataclass class Module: module_id: str name: str layer: str # backend / frontend description: str phase: str depends_on: list[str] capabilities: list[str] @dataclass class Integration: integration_id: str source_id: str # API 响应中序列化为 "source"(兼容 OpenAPI) target_id: str # API 响应中序列化为 "target"(兼容 OpenAPI) target_type: str direction: str protocol: str trigger: str phase: str description: str @dataclass class ExternalSystem: system_id: str name: str type: str protocol: str direction: str phase: str description: str @dataclass class ApiContract: doc_id: str path: str method: str operation_id: str summary: str @dataclass class CodebaseAlignment: module_id: str repo_root: str code_root: str package_name: str @dataclass class ModuleBoundaryRule: doc_id: str title: str content: str @dataclass class SystemContext: doc_id: str title: str content: str @dataclass class SolutionLayer: doc_id: str title: str content: str # 数据层 @dataclass class Entity: entity_id: str name: str domain: str owner_module: str description: str phase: str source_file: str @dataclass class DataFlow: data_flow_id: str source: str target: str data_content: str trigger: str protocol: str phase: str description: str @dataclass class DataSecurity: security_id: str sensitivity: str entities: str protection: str # 技术层 @dataclass class TechSelection: category: str technology: str version: str purpose: str rationale: str alternatives_considered: str phase: str @dataclass class RuntimeComponent: component_id: str name: str type: str technology: str port: str @dataclass class RuntimeTopology: doc_id: str title: str content: str @dataclass class Environment: env_id: str name: str purpose: str infra: str @dataclass class OperationalBaseline: doc_id: str title: str content: str @dataclass class ReleasePlan: doc_id: str title: str content: str # 跨层 @dataclass class TraceabilityLink: trace_id: str capability_id: str module_id: str entity_ids: list[str] value_flow_ids: list[str] notes: str @dataclass class ChangeLogEntry: change_id: str date: str scope: str description: str @dataclass class ADR: adr_id: str title: str status: str context: str decision: str @dataclass class DesignDocument: doc_id: str title: str version: str status: str owners: list[str] upstream: list[str] downstream: list[str] file_path: str # 领域层 @dataclass class Domain: domain_name: str overview: str modules: list[str] entities: list[str] @dataclass class UbiquitousTerm: term_id: str term: str english_term: str code_symbol: str domain: str definition: str @dataclass class SharedTerm: term_id: str term: str english_term: str definition: str used_by_domains: list[str] @dataclass class Scenario: scenario_id: str name: str trigger: str actors: str steps: str outcome: str related_capabilities: list[str] @dataclass class DomainModule: module_id: str module_name: str domain: str description: str layer_in_code: str @dataclass class DomainEntity: entity_id: str entity_name: str type: str description: str key_attributes: str ``` **domain/value_objects.py** — 3 种值对象: ```python class FileStatus(str, Enum): OK = "ok" SPARSE = "sparse" MISSING = "missing" TEMPLATE_RESIDUE = "template-residue" PLACEHOLDER_HEAVY = "placeholder-heavy" class ArchitectureLayer(str, Enum): BUSINESS = "business" APPLICATION = "application" DATA = "data" TECHNOLOGY = "technology" class ModuleLayer(str, Enum): DOMAIN = "domain" APPLICATION = "application" INFRASTRUCTURE = "infrastructure" INTERFACES = "interfaces" ``` **domain/services.py** — 约束规则校验 + FileStatus 判定: ```python class DesignValidationService: def validate_all(entities) -> list[ConstraintViolation]: """执行所有约束规则,返回违规列表""" def check_capability_module_linkage(capabilities, traceability_links) -> list def check_entity_owner(entities) -> list def check_traceability_references(links, capabilities, modules, entities) -> list @staticmethod def determine_file_status(content: str, file_path: str) -> FileStatus: """根据文件内容特征判定 FileStatus: - missing: 文件不存在或空 - sparse: 行数 < 阈值(CSV < 2行含头, MD < 5行) - template-residue: 检测到模板占位文本(TODO、EXAMPLE、) - placeholder-heavy: 占位符比例 > 30% - ok: 通过所有检查 """ ``` ### 3.3 MOD-PROJECT **domain/entities.py**: ```python @dataclass class Project: id: str # UUID name: str design_dir: str # 绝对路径 code_dir: str | None # Phase 2 created_at: datetime ``` **domain/repositories.py**: ```python class ProjectRepository(ABC): def list_all() -> list[Project] def get_by_id(id: str) -> Project | None def save(project: Project) -> None def delete(id: str) -> None ``` **infrastructure/json_repository.py**:实现 ProjectRepository,读写 JSON 文件。 **application/services.py**: ```python class ProjectService: def list_projects() -> list[Project] def create_project(name, design_dir, code_dir=None) -> Project # 验证 design_dir 存在 def get_project(id) -> Project def delete_project(id) -> None ``` **interfaces/http/router.py**:FastAPI router,4 个端点。 ### 3.4 MOD-SCANNER **domain/entities.py**: ```python @dataclass class FileStatusEntry: path: str status: FileStatus content_lines: int @dataclass class ScanSummary: total_files: int ok: int sparse: int missing: int placeholder_heavy: int template_residue: int @dataclass class ScanResult: """内部 domain 对象,携带所有解析出的实体。 API 响应(ScanResultResponse)只包含 project_id, scanned_at, file_statuses, summary。 实体数据通过独立的 /entities/* 端点暴露。""" project_id: str scanned_at: datetime file_statuses: list[FileStatusEntry] summary: ScanSummary # 所有解析出的 Design 实体 capabilities: list[Capability] modules: list[Module] entities: list[Entity] value_flows: list[ValueFlow] user_journeys: list[UserJourney] integrations: list[Integration] data_flows: list[DataFlow] traceability_links: list[TraceabilityLink] external_systems: list[ExternalSystem] runtime_components: list[RuntimeComponent] tech_selections: list[TechSelection] environments: list[Environment] design_documents: list[DesignDocument] change_log_entries: list[ChangeLogEntry] adrs: list[ADR] shared_terms: list[SharedTerm] domains: list[Domain] ubiquitous_terms: list[UbiquitousTerm] scenarios: list[Scenario] domain_modules: list[DomainModule] domain_entities: list[DomainEntity] data_securities: list[DataSecurity] codebase_alignments: list[CodebaseAlignment] # MD 文件特有 scope_and_goals: ScopeAndGoals | None system_context: SystemContext | None solution_layer: SolutionLayer | None module_boundary_rule: ModuleBoundaryRule | None runtime_topology: RuntimeTopology | None operational_baseline: OperationalBaseline | None release_plan: ReleasePlan | None ``` **infrastructure/parsers/**: - `csv_parser.py`:解析 CSV 文件,按文件名映射到对应实体类型(capability-map.csv → Capability 列表) - `md_parser.py`:解析 Markdown frontmatter (YAML),提取 doc_id/title/status/upstream/downstream → DesignDocument;特定文件解析为对应实体 - `yaml_parser.py`:解析 YAML 配置文件 - `openapi_parser.py`:解析 OpenAPI YAML → ApiContract 列表 **application/services.py**: ```python class ScanService: def scan(project: Project) -> ScanResult: """遍历 design/ → 按类型分派 Parser → 汇总实体 → 调用约束校验 → 计算 FileStatus → 组装 ScanResult""" def get_latest_scan(project_id: str) -> ScanResult | None: """返回内存缓存的最近一次扫描结果""" ``` **interfaces/http/router.py**:POST/GET scan + 13 个实体查询端点: 列表端点(10个): - GET `.../entities/capabilities` → `list[Capability]` - GET `.../entities/modules` → `list[Module]` - GET `.../entities/entities` → `list[Entity]` - GET `.../entities/integrations` → `list[Integration]` - GET `.../entities/value-flows` → `list[ValueFlow]` - GET `.../entities/user-journeys` → `list[UserJourney]` - GET `.../entities/data-flows` → `list[DataFlow]` - GET `.../entities/external-systems` → `list[ExternalSystem]` - GET `.../entities/traceability-links` → `list[TraceabilityLink]` - GET `.../entities/runtime-components` → `list[RuntimeComponent]` 详情端点(3个,返回关联数据): - GET `.../entities/capabilities/{capability_id}` → `CapabilityDetail`(含关联 modules + value_flows) - GET `.../entities/modules/{module_id}` → `ModuleDetail`(含 owned_entities + integrations + codebase_alignment) - GET `.../entities/entities/{entity_id}` → `EntityDetail`(含 data_flows) ### 3.5 MOD-GRAPH **domain/entities.py**: ```python @dataclass class GraphNode: id: str type: str # capability, module, entity, integration, ... label: str status: str # FileStatus or "unknown" group_id: str @dataclass class GraphEdge: source: str target: str relation: str # traces_to, depends_on, owns, integrates_with, ... @dataclass class GraphGroup: id: str label: str layer: str # business, application, data, technology, cross-layer @dataclass class GraphView: nodes: list[GraphNode] edges: list[GraphEdge] groups: list[GraphGroup] ``` **application/services.py**: ```python class GraphService: def build_panorama(scan_result: ScanResult) -> GraphView: """从 ScanResult 构建全景图: 1. 创建 5 个 group(business, application, data, technology, cross-layer) 2. 每个 Capability → node(group=business) 3. 每个 Module → node(group=application) 4. 每个 Entity → node(group=data) 5. 每个 RuntimeComponent → node(group=technology) 6. TraceabilityLink → edges(capability→module, module→entity) 7. Integration → edges(source→target) 8. Module.depends_on → edges 9. DesignDocument.upstream/downstream → edges """ def get_neighbors(graph_view: GraphView, node_id: str) -> GraphView: """返回指定节点的所有直接邻居组成的子图""" ``` **interfaces/http/router.py**:GET graph, GET neighbors。 ### 3.6 MOD-EDITOR(Phase 2) **domain/entities.py**: ```python @dataclass class EditableFile: path: str format: str # csv, md, yaml, openapi content: str last_modified: datetime @dataclass class AffectedFile: path: str reason: str @dataclass class ImpactResult: source_file: str affected_files: list[AffectedFile] ``` **infrastructure/file_io.py**:读写设计文件。 **application/services.py**: ```python class EditorService: def get_file(project: Project, relative_path: str) -> EditableFile def save_file(project: Project, relative_path: str, content: str) -> ScanResult: """写文件 → 触发重新扫描 → 返回新 ScanResult""" def get_impact(project: Project, relative_path: str, scan_result: ScanResult) -> ImpactResult: """沿 DesignDocument.downstream + TraceabilityLink 遍历""" ``` **interfaces/http/router.py**:GET/PUT files, GET files/impact。 ### 3.7 MOD-IMPL-TRACKER(Phase 2) **domain/entities.py**: ```python @dataclass class ImplProgress: module_id: str percentage: float # 0-100 source: str # auto, llm, manual evaluated_at: datetime @dataclass class CodeStructure: root_path: str directories: list[str] files: list[str] matched_modules: list[str] ``` **infrastructure/code_scanner.py**:扫描代码目录结构。 **infrastructure/llm_client.py**:可选 LLM API 调用。 **application/services.py**: ```python class ImplTrackerService: def evaluate(project: Project, scan_result: ScanResult) -> list[ImplProgress]: """三级评估: 1. auto:扫描 code_dir,对照 CodebaseAlignment 检查目录/文件存在性 2. llm(可选):将模块设计+代码发送 LLM 评估覆盖率 3. manual:合并用户手动覆盖 """ def get_progress(project_id: str) -> list[ImplProgress] def set_manual_progress(project_id: str, module_id: str, percentage: float) ``` **interfaces/http/router.py**:POST/GET impl-progress + PUT impl-progress/{module_id}(手动覆盖,OpenAPI 契约中缺失此端点,实现时补充)。 ### 3.8 main.py(应用入口) ```python app = FastAPI(title="Arch Design Dashboard API") # 注册所有 router app.include_router(project_router, prefix="/api") app.include_router(scanner_router, prefix="/api") app.include_router(graph_router, prefix="/api") app.include_router(editor_router, prefix="/api") app.include_router(impl_tracker_router, prefix="/api") # 健康检查 @app.get("/api/health") def health(): return {"status": "ok"} # 全局异常处理 @app.exception_handler(NotFoundError) → 404 @app.exception_handler(ValidationError) → 400 ``` ## 4. 前端详细设计 ### 4.0 基础设施 **index.html**:SPA 入口页。 **main.ts**:创建 Vue app,安装 Pinia、Router。 **App.vue**: ``` ``` **router/index.ts**: ```typescript routes: [ { path: '/', component: ProjectList }, { path: '/projects/:id', component: GraphPanorama }, { path: '/projects/:id/editor', component: EditorPage }, // Phase 2 ] ``` **shared/api.ts**:Axios 实例,baseURL = `/api`。 **shared/types/api.ts**:TypeScript 类型定义,与 OpenAPI schema 对齐(Project, ScanResult, GraphView, GraphNode, GraphEdge, GraphGroup, Capability, Module, Entity, FileContent, ImpactResult, ImplProgress 等)。 ### 4.1 MOD-FE-PROJECT **components/ProjectList.vue**: - 展示已注册项目列表(卡片式) - "添加项目"按钮 → 展开表单(名称 + 设计目录路径 + 可选代码目录) - 点击项目卡片 → router.push(`/projects/${id}`) - 删除按钮(确认后删除) **components/ProjectOverview.vue**:项目卡片组件。 **composables/useProject.ts**:Pinia store — projects[], currentProject, loading, error, CRUD actions。 **api/index.ts**:listProjects, createProject, getProject, deleteProject。 ### 4.2 MOD-FE-GRAPH **components/GraphPanorama.vue**: - 进入时调用 `triggerScan` → `getGraph` 获取数据 - D3.js 力导向图,节点按 group 分区布局 - 节点颜色映射:ok=`#4CAF50`, sparse=`#FFC107`, missing=`#F44336`, template-residue=`#FF9800`, placeholder-heavy=`#9C27B0`, unknown=`#9E9E9E` - 节点形状:capability=圆, module=方, entity=菱形, 其他=圆 - 边线条:traces_to=实线, depends_on=虚线, owns=粗实线 - 交互: - hover → tooltip(ID, 类型, 状态, 名称) - 单击 → 侧边 GraphDetail 面板 - 双击 → 调用 getNodeNeighbors 展示子图(下钻) - 缩放/平移(D3 zoom behavior) - 扫描摘要面板(total/ok/sparse/missing 统计) **components/GraphDetail.vue**: - 侧边滑出面板 - 显示节点属性(所有字段) - 关联实体列表(可点击跳转) - Phase 2:编辑按钮 → 跳转编辑器 - Phase 2:影响分析按钮 → 高亮下游节点 **composables/useGraph.ts**:Pinia store — graphView, selectedNode, scanResult, loading。 **api/index.ts**:triggerScan, getLatestScan, getGraph, getNodeNeighbors, + 实体查询 API, + Phase 2: getImplProgress, triggerImplProgress。 ### 4.3 MOD-FE-EDITOR(Phase 2) **components/CsvEditor.vue**: - 可编辑 HTML 表格 - 增删行 - 保存按钮 → saveFile → 图自动刷新 **components/MdEditor.vue**: - textarea 左编辑 + 右侧 Markdown 预览 - 支持 frontmatter 高亮 - 保存按钮 **composables/useEditor.ts**:Pinia store — currentFile, impactResult, saving。 **api/index.ts**:getFile, saveFile, getFileImpact。 ## 5. 部署配置 **docker-compose.yml**: ```yaml services: backend: build: ./backend ports: ["8900:8900"] volumes: - ${DESIGN_DIR}:/data/design:rw - ${CODE_DIR:-/dev/null}:/data/code:ro - registry-data:/data/registry frontend: build: ./frontend ports: ["80:80"] depends_on: [backend] volumes: registry-data: ``` **backend/Dockerfile**:Python 3.12 + uv install + uvicorn 启动。 **frontend/Dockerfile**:Node 构建 + Nginx 服务静态文件 + 反代 `/api`。 ## 6. 设计约束与边界规则 - Design 模块是纯 Python,零框架依赖 - Scanner 依赖 Design,不依赖 Graph - Graph 依赖 Design,不依赖 Scanner(通过 ScanResult 数据传递) - Editor 依赖 Design + Scanner + Graph - Impl-Tracker 依赖 Design + Scanner - 前端模块只通过 REST API 与后端通信 - 设计文件是 single source of truth,不引入额外数据库 - 代码仓库只读 ## 7. OpenAPI 契约偏差说明 实现时以本 spec 和 CSV 源数据为准,以下是与 OpenAPI 契约的已知偏差(实现时在 API 响应中包含这些额外字段): | 实体 | 本 spec 有但 OpenAPI 缺失的字段 | 处理方式 | |------|------|------| | Capability | description | API 响应中包含 | | Module | description | API 响应中包含 | | Entity | description, phase, source_file | API 响应中包含 | | ValueFlow | actor, phase, related_capabilities | API 响应中包含 | | UserJourney | actor, phase, related_value_flows | API 响应中包含 | | ExternalSystem | direction, description, phase | API 响应中包含 | | Integration | target_type, trigger(字段名 source_id/target_id → API 中用 source/target) | API 响应中包含,字段名用 source/target | | 多字段 list[str] | related_value_flows, depends_on, capabilities, entity_ids, value_flow_ids | OpenAPI 定义为 string,实现为 JSON array | | ImplProgress | PUT /{module_id} 端点 | OpenAPI 缺失,实现时补充 |