23 KiB
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-multipartbackend/.python-version:3.12frontend/package.json:vue 3, vue-router, pinia, d3, axios, vite, typescriptfrontend/vite.config.ts:dev proxy/api→localhost:8900frontend/tsconfig.jsonfrontend/index.html
3.1 shared 层
shared/kernel/exceptions.py:
NotFoundError(entity: str, id: str)— 404ValidationError(message: str)— 400FileSystemError(path: str, message: str)— 500
shared/infrastructure/config.py:
Settingsdataclass:registry_path(projects.json 路径,默认~/.arch-design-dashboard/projects.json)
shared/infrastructure/filesystem.py:
read_text(path) -> strwrite_text(path, content)list_files(directory, extensions) -> list[Path]file_exists(path) -> bool
3.2 MOD-DESIGN(核心领域,纯 Python)
序列化策略: CSV 中的空格分隔字段在 Python domain 层存储为 list[str]。API 响应中也返回为 JSON 数组(list[str]),由 router 层负责转换。OpenAPI 契约中这些字段定义为 string 是文档缺陷,实现时以 list[str] 为准。涉及的字段包括:
- Capability.related_value_flows, Module.depends_on, Module.capabilities
- TraceabilityLink.entity_ids, TraceabilityLink.value_flow_ids
- ValueFlow.related_capabilities, UserJourney.related_value_flows
- Scenario.related_capabilities, SharedTerm.used_by_domains
- Domain.modules, Domain.entities
- DesignDocument.owners, DesignDocument.upstream, DesignDocument.downstream
domain/entities.py — 31 种设计实体,用 @dataclass 定义:
# 业务层
@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 种值对象:
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 判定:
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、<replace>)
- placeholder-heavy: 占位符比例 > 30%
- ok: 通过所有检查
"""
3.3 MOD-PROJECT
domain/entities.py:
@dataclass
class Project:
id: str # UUID
name: str
design_dir: str # 绝对路径
code_dir: str | None # Phase 2
created_at: datetime
domain/repositories.py:
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:
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:
@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:
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:
@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:
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:
@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:
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:
@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:
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(应用入口)
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:
<template>
<div class="app-layout">
<aside class="sidebar">项目列表(始终可见)</aside>
<main class="content"><router-view /></main>
</div>
</template>
router/index.ts:
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:
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 缺失,实现时补充 |