Pressidian
花园入口
笔记
项目
关于
实验室
GitHub
花园入口
笔记
项目
关于
实验室
GitHub

KNOWLEDGE PATHS

笔记库
当前位置
笔记库/前端/项目笔记/代达罗斯/需求/COD-104

用于稳定描述代码结构的数据结构方案

26 分钟阅读 · Note

目录树 578 篇

              • 用于稳定描述代码结构的数据结构方案
              • 总结
            • 国际化
            • 需求整体流程
            • Linear
          • 项目待做
          • 性能优化
          • UI设计
      • 前端技术栈
    • 笔记目录
    • CLAUDE.md
    • Vue 组件与 Render 函数

关联笔记 6

↗总结同一路径↗「Feature」Introduce Crate as an independent metadata entity[ˈentəti] | 引入 Crate 作为独立元数据实体共同主题↗国际化共同主题↗实施计划:Archetype 管理 (COD-86)共同主题↗需求整体流程共同主题↗引入Archetype共同主题
  • 用于稳定描述代码结构的数据结构方案

用于稳定描述代码结构的数据结构方案


摘要

本报告调研了 10 类市场上用于描述代码结构与软件架构的现有方案,从结构单元建模、关系建模、约束/契约建模、边界表达、可组合性、可扩展性、查询友好度、采用成本八个维度逐一分析,并结合 Daedalus 当前 Archetype/Crate 模型的局限性进行适用性评估。

核心结论

  • 不存在可直接采用的"开箱即用"方案
  • Backstage Catalog Model 是最值得深度适配的参考方案——其实体-关系-类型系统的设计哲学与 Daedalus 的 Crate/Archetype 抽象高度一致,且具有成熟的扩展机制(类 Kubernetes CRD)。
  • json-render 的 Catalog + Zod Schema 模式提供了"约束优先"的建模思路——用 Zod schema 定义结构单元的契约,AI 在契约约束内生成/验证结构化输出,这一范式对 Archetype Condition 的演进有直接借鉴价值。
  • 建议采用"混合适配"策略:以 Backstage Catalog Model 为骨架吸收其类型系统与关系模型,以 DDD Aggregate/Bounded Context 为灵魂指导边界设计,以 json-render Catalog 模式增强约束层,以 Rust 模块系统的可见性控制思想完善边界表达。
  • 轻量自定义层有必要但规模可控——核心仅需定义 StructureUnit、Relation、Constraint 三个泛化实体,即可统一表达 Crate、Archetype、Repository 等所有现有实体,并为未来的 Skill、Item 等概念预留扩展能力。

Daedalus 需求定义

在评估外部方案前,先明确 Daedalus 对"代码结构描述"的最小需求集。

现有实体

Crate(代码组织单元)
 ├── name: 唯一名称
 ├── type: 枚举(package | module | feature | library | service | utility | other)
 ├── responsibility: 职责文本
 └── metadata: 自由文本

Archetype(设计范式)
 ├── name: 唯一名称
 ├── concept: 概念描述
 ├── scope: 适用范围(project | repository | crate | page | service)
 ├── description: 详细描述
 └── Conditions[]: 条件列表
      ├── TextCondition: type="text", value="描述文本"
      └── ArchetypeRefCondition: type="archetype_ref", value=archetypeId
           └── 通过 condition_dependencies 中间表实现 M:N 依赖

Crate → Archetype: 实例化/符合(COD-88 规划中)
Archetype → Archetype: requires/depends(通过 Condition 的 archetype_ref 实现)

已知局限性

  1. Crate 的 type 是固定枚举,无法表达更丰富的结构语义(如"既是 library 又是 feature")
  2. Archetype 的 Condition 仅支持 text 和 archetype_ref 两种类型——无法表达数量约束、文件路径模式、依赖方向等结构化条件
  3. Crate、Archetype、Repository 各自独立建模,缺乏统一的"结构单元"抽象
  4. 缺乏表达结构单元之间关系的通用机制(嵌套 partOf、组合 hasPart、依赖 dependsOn、实现 implements)
  5. metadata 字段是自由文本,无法做结构化查询

目标能力

#能力说明
1统一结构单元抽象一个泛型实体能表达 Crate、Archetype、Repository、Page 等所有结构层级
2多态类型系统结构单元可以有多种类型标签(不限于固定枚举),支持类型组合
3富关系模型支持嵌套(partOf/hasPart)、依赖(dependsOn/dependencyOf)、实现(implements/implementedBy)、引用(references/referencedBy)
4可扩展约束系统约束不仅可描述文本和 Archetype 引用,还能表达文件路径模式、数量范围、依赖方向、版本范围等结构化条件
5边界与可见性明确单元的公开接口(对外暴露什么)和私有实现(内部细节)
6层级化组合支持从 Repository → Crate → Module → File → Function 的任意深度嵌套
7结构化查询不依赖自由文本搜索,而是通过类型、关系、属性进行精确查询

方案调研

Backstage Catalog Model

来源:Spotify Backstage (https://backstage.io/)

核心思想:用 Kubernetes 风格的实体模型描述软件资产。所有事物都是一种 typed Entity,具有统一的 envelope(apiVersion、kind、metadata、spec),实体之间通过 well-known relations 连接。

> 简单来讲 Backstage 包含软件目录、软件模板、TechDocs、插件生态,它是一个你可以部署和运行的应用。而 Backstage 内部软件目录功能背后的数据模型设计值得我们去借鉴

  Entity {
    apiVersion: "backstage.io/v1alpha1"   // 版本化
    kind: "Component" | "API" | "Resource" | "System" | "Domain"  // 实体种类
    metadata: {
      name: "my-service"                  // 唯一标识
      namespace: "default"
      tags: ["java", "backend"]
      annotations: { ... }
    }
    spec: {
      type: "service"                     // 子类型
      owner: "team-a"                     // 归属
      lifecycle: "production"
      providesApis: ["my-api"]            // 暴露的接口
      consumesApis: ["other-api"]         // 消费的接口
      dependsOn: ["other-component"]      // 依赖
      partOf: ["my-system"]              // 层级归属
    }
  }
实体类型系统
Kind含义Daedalus 对应
Component软件单元(service/website/library/tool 等)≈ Crate
API组件之间的边界合约≈ 部分 Archetype Condition 的角色
Resource物理/虚拟基础设施暂无直接对应
System协作完成某功能的 Component + Resource 集合≈ Repository/Project
Domain共享术语和业务目标的 System 集合(Bounded Context)≈ 未来可能的 Workspace/Organization
关系模型
关系方向含义
ownedBy / ownerOfEntity → Group所有权
providesApi / apiProvidedByComponent ↔ APIAPI 提供
consumesApi / apiConsumedByComponent ↔ APIAPI 消费
dependsOn / dependencyOfComponent ↔ Component/Resource运行时依赖
partOf / hasPartComponent → System系统成员关系
hasMember / memberOfUser → Group团队成员关系
关键设计点
  1. 可扩展 Kind:像 Kubernetes CRD 一样可定义自定义 Entity Kind(如 ML Model, Mobile App),只需注册 apiVersion + kind + schema
  2. 强制性 owner:spec.owner 是必填字段,驱动"谁来负责"的元数据
  3. 关系是权威数据源:插件应消费 relations 而非直接读 spec.owner,因为 catalog 可能从 CODEOWNERS 等多种源解析所有权
  4. API 是一等公民:将 API 视为独立实体种类,而不是 Component 的属性
适用性评估
维度评分说明
结构单元建模⭐⭐⭐⭐⭐Kind + spec.type 双层分类体系完美对应 Crate 的分类需求
关系建模⭐⭐⭐⭐⭐well-known relations + 可扩展自定义关系;与 Archetype 依赖树高度契合
约束/契约建模⭐⭐⭐API 实体可部分表达契约,但缺乏声明式约束语言(如"must have 3+ conditions")
边界表达⭐⭐⭐⭐API 作为显式边界实体,providesApi/consumesApi 精确表达接口暴露
可组合性⭐⭐⭐⭐⭐System → Domain 层级 + partOf/hasPart + subcomponentOf 支持任意深度嵌套
可扩展性⭐⭐⭐⭐⭐原生支持自定义 Kind + 自定义 Relation,成熟度最高
查询友好⭐⭐⭐⭐通过 Catalog API 的结构化查询(按 kind/type/owner/relations 过滤)
采用成本⭐⭐⭐需要理解其 YAML descriptor 格式和实体引用约定,但与 Daedalus 的 TypeScript 栈可桥接

核心借鉴点:

  • Component/System/Domain 三层抽象可直接映射为 Crate/Repository/Workspace
  • providesApi/consumesApi 关系可泛化为结构单元之间的"接口契约"
  • 可扩展 Kind 机制是让 Archetype、Crate、Repository 统一在"结构单元"抽象下的关键灵感

C4 Model + Structurizr DSL

来源:Simon Brown (https://structurizr.com/)

核心思想:以四个层级(System Context → Container → Component → Code)分层描述软件架构,用 Structurizr DSL 作为 textual representation。

> Structurizr 是一个专门用于可视化、记录和探索软件架构的工具,它是 C4 模型创建者开发的官方参考实现。用代码来创建清晰、一致且多层次的软件架构图。其中的DSL我认为很值得去参考

层级模型
层级元素类型关系目标Daedalus 对应
C1 System ContextPerson, SoftwareSystem外部系统、用户项目边界
C2 ContainerContainer(web app, API, DB)部署单元≈ Crate (type=service/library)
C3 ComponentComponent(内部模块)容器内的逻辑组件≈ Crate (type=module/feature)
C4 CodeClass, Interface源代码级超出 Daedalus 当前范围
DSL 语法核心
workspace {
    model {
        user = person "User"
        system = softwareSystem "Payment Platform" {
            api = container "Payment API" {
                // Components inside container
                controller = component "Payment Controller"
                repository = component "Payment Repository"
                // Component-level relationships
                controller -> repository "Persists via"
            }
            db = container "Payment DB" { technology "PostgreSQL" }
        }
        user -> api "Makes payments via"
    }
    views { ... }
}
适用性评估
维度评分说明
结构单元建模⭐⭐⭐⭐四层抽象非常清晰,Container/Component 概念与 Crate 天然对应
关系建模⭐⭐⭐-> 关系语法简洁,但关系类型单一(仅"uses"语义),缺乏依赖/实现/组合等区分
约束/契约建模⭐⭐无内建约束机制;需通过 DSL 扩展(tags, properties)或外部工具补充
边界表达⭐⭐⭐⭐⭐Container boundary 是最核心概念——明确区分"内部组件"和"外部接口"
可组合性⭐⭐⭐⭐天然层级化:System → Container → Component,group 元素支持同层分组
可扩展性⭐⭐⭐tags/properties 提供轻量扩展,但无类型系统;可通过自定义 DSL 元素扩展
查询友好⭐⭐DSL 本身不是查询语言;可视化为主,非结构化查询
采用成本⭐⭐⭐⭐DSL 语法极简(~20 个元素类型),学习曲线低

核心借鉴点:

  • 四层抽象的分层思想是 Daedalus 最需要的——当前 Archetype 的 scope 字段(project/repository/crate/page/service)实际上已经在尝试做分层,但缺乏系统化的层级定义
  • Container boundary 就是 Crate 的边界:Container 封装内部 Component,对外暴露 API——这与 Crate 的 responsibility + 未来"暴露接口"概念完全对应
  • DSL 的 textual-first 思路适合与 LLM 协作——生成/解析 DSL 文本比生成图表容易得多

ArchUnit / dependency-cruiser

来源:ArchUnit (Java, https://www.archunit.org/), dependency-cruiser (JS/TS, https://github.com/sverweij/dependency-cruiser)

核心思想:用声明式规则描述架构约束,然后自动验证代码是否违反约束。

> 核心也是DSL

规则声明方式对比

ArchUnit (Java fluent API):

classes().that().resideInAPackage("..service..")
    .should().onlyHaveDependentClassesThat()
    .resideInAPackage("..controller..");

dependency-cruiser (JS config DSL):

{
  forbidden: [{
    name: "no-cross-feature-imports",
    severity: "error",
    from: { path: "^src/features/" },
    to:   { path: "^src/features/", pathNot: "^$1" } // 禁止跨 feature 导入
  }]
}
适用性评估
维度评分说明
结构单元建模⭐⭐本身不建模结构单元——它们作用于已有的代码文件/包结构
关系建模⭐⭐⭐⭐依赖关系是核心建模对象:方向、层级、循环、可达性
约束/契约建模⭐⭐⭐⭐⭐本类别最强项——声明式规则 DSL 是 Archetype Condition 演进的直接参考
边界表达⭐⭐⭐⭐from/to 的路径匹配 + 可见性规则精确表达模块边界
可组合性⭐⭐⭐规则可组合(多规则叠加),但规则之间没有层级/依赖关系
可扩展性⭐⭐⭐dependency-cruiser 支持自定义插件和 dot.js 模板扩展
查询友好⭐⭐⭐依赖图可输出为 JSON/CSV,但主要面向验证而非查询
采用成本⭐⭐⭐⭐dependency-cruiser 已是 JS 生态标准工具,可集成到 Daedalus 的自动化检查中

核心借鉴点:

  • 约束的声明式规则 DSL 是 Archetype Condition 的演进方向:当前 Condition 仅有 text 和 archetype_ref 两种类型,应扩展为支持路径模式(pathPattern)、依赖方向(dependsOn/dependedOnBy)、数量约束(minCount/maxCount)等结构化条件
  • dependency-cruiser 的 from→to 规则模式可直接为 Daedalus 的自动化架构检查提供实现基础
  • 但注意:ArchUnit/dependency-cruiser 是验证工具,不是数据模型——它们假设代码已经存在,然后检查是否符合规则。Daedalus 需要的是先有结构描述,再检查代码是否符合描述

DDD Bounded Context / Aggregate

来源:Eric Evans "Domain-Driven Design" (2003),持续演进

核心思想:通过 Bounded Context 划分领域边界,通过 Aggregate 定义一致性单元,通过 Entity/Value Object 区分身份与值。

核心概念映射
DDD 概念含义Daedalus 对应
Bounded Context一个特定领域模型适用的显式边界≈ Repository/Workspace
Aggregate一组 Entity + Value Object 的一致性单元≈ Crate (作为逻辑聚合单元)
Aggregate RootAggregate 的入口,外部只能通过它访问 Aggregate 内部≈ Crate 的公开 API / 暴露接口
Entity有唯一标识,可变≈ 有独立 ID 的结构单元
Value Object无标识,不可变,通过值判断相等≈ Condition / Constraint 的值部分
Domain Service不属于任何单一 Entity 的领域操作≈ Archetype(跨 Crate 的设计契约)
RepositoryAggregate 的持久化抽象≈ 数据访问层
适用性评估
维度评分说明
结构单元建模⭐⭐⭐⭐Aggregate + Entity + Value Object 三层建模粒度精细,与 Daedalus 的三层(Repository → Crate → Condition)有映射空间
关系建模⭐⭐⭐Context Map 定义了多种关系(Partnership, Shared Kernel, Customer-Supplier, Conformist, ACL),但对代码审查场景偏重
约束/契约建模⭐⭐⭐⭐Aggregate 的不变式(invariant)+ 规约模式(Specification)是约束建模的强大范式
边界表达⭐⭐⭐⭐⭐DDD 的最强项——Bounded Context 和 Aggregate Boundary 是软件设计中边界建模的黄金标准
可组合性⭐⭐⭐⭐Context Mapping 天然支持多个 Bounded Context 的组合与协作
可扩展性⭐⭐⭐⭐作为方法论而非工具,DDD 的建模元素可自由裁剪和扩展
查询友好⭐⭐DDD 本身不提供查询能力;需配合 Repository 模式
采用成本⭐⭐⭐概念体系完整但较重,大量术语(Ubiquitous Language, Anti-Corruption Layer, Domain Event)可能超过 Daedalus 当前规模需要

核心借鉴点:

  • Aggregate 边界 = Crate 的本质定义:Crate 应该像 Aggregate 一样定义"什么属于这个单元"和"外部只能通过什么接口访问这个单元"——这正是当前 Crate 模型缺失的
  • Bounded Context 的 Ubiquitous Language:每个 Context 内术语有确定含义——对应 Archetype 的"命名设计契约"
  • Specification 模式:将约束表达为可组合的规约对象,比当前 Condition 的 text/archetype_ref 二元类型强大得多
  • 但警告:DDD 是重型方法论,Daedalus 应借鉴其思想而非完全照搬

Rust Crate/Module 系统

来源:Rust 语言设计 (https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html)

核心思想:三层结构(Package → Crate → Module)+ 隐私默认(private-by-default)+ pub 显式公开 + pub use 重导出。

三层抽象
层级定义可见性控制
PackageCargo.toml 定义;含最多 1 个 library crate + N 个 binary crate—
Crate编译单元;lib.rs 或 main.rs 为根pub(crate) 仅在 crate 内可见
Modulemod 声明;文件/目录结构映射模块树默认私有;pub/pub(super)/pub(in path) 逐级公开
可见性模型
// 可见性从严格到宽松
fn private_func() {}          // 仅当前模块及子模块
pub(super) fn parent_only() {} // 仅父模块
pub(crate) fn crate_only() {}  // crate 内部
pub fn public_api() {}         // 所有人
适用性评估
维度评分说明
结构单元建模⭐⭐⭐⭐⭐Package/Crate/Module 三层抽象简洁、精确、实用——是 Daedalus 结构单元层级的最直接参照
关系建模⭐⭐⭐⭐pub use 重导出 = 接口暴露 + 依赖重定向;Cargo.toml 声明外部依赖
约束/契约建模⭐⭐⭐trait 定义行为契约;where 子句表达类型约束——但这些都是编译时概念
边界表达⭐⭐⭐⭐⭐Rust 的 visibility 系统是本类别最佳实践——private-by-default + 分级 pub 精确控制每个结构单元的边界
可组合性⭐⭐⭐⭐模块树可以任意深度嵌套;pub use 允许内部重组而不影响外部 API
可扩展性⭐⭐⭐编译时固定,无运行时动态扩展
查询友好⭐⭐非查询系统
采用成本⭐⭐⭐⭐概念精确且稳定,但 Daedalus 不是 Rust 项目,直接复用成本高

核心借鉴点:

  • Crate 的命名起源就是 Rust:Daedalus 从 Rust 借用了"Crate"一词,但当前实现只学到了"名字+类型+职责",丢失了 Rust Crate 最核心的两个特性:
    1. Crate 是编译边界 → Crate 应该定义"什么代码属于这个 Crate"
    2. pub 控制 API 表面 → Crate 应该有显式的"暴露接口"列表
  • private-by-default 哲学:结构单元的内部实现在默认情况下不应被外部消费——这一原则应该写入 Archetype 的默认约束
  • pub use 重导出:结构单元的内部路径和公开路径可以不同——用户看到的是整理后的公共 API 表面

RDF/OWL / Property Graph

来源:W3C RDF/OWL (https://www.w3.org/TR/owl2-overview/), Neo4j Property Graph (https://neo4j.com/)

核心思想:RDF 用三元组(Subject-Predicate-Object)表达所有事实;Property Graph 用节点+属性+带类型的有向边建模。

模型对比
特性RDF/OWLProperty Graph (Neo4j)
核心原子三元组 (S, P, O)节点(Node) + 关系(Relationship)
SchemaOWL 本体(class hierarchy, property domain/range, axioms)可选 Label + 属性约束(轻量)
关系属性需 Reification(繁琐)原生支持(关系上直接挂 key-value)
查询语言SPARQLCypher
推理内建(RDFS entailment, OWL 2 RL)需外部引擎
适用性评估
维度评分说明
结构单元建模⭐⭐⭐⭐Property Graph 的 Node + Label 天然映射到结构单元 + 类型标签;RDF 的 Class hierarchy 可通过 rdfs:subClassOf 定义类型层级
关系建模⭐⭐⭐⭐⭐图模型的最强项——Property Graph 的命名+有属性+有向边是关系建模的终极方案
约束/契约建模⭐⭐⭐⭐⭐OWL 的公理系统(subClassOf, equivalentClass, disjointWith, allValuesFrom, someValuesFrom, cardinality)是约束表达的完整形式化体系
边界表达⭐⭐⭐图模型不天然强调"边界"——需要通过命名图(Named Graph)或子图模式补充
可组合性⭐⭐⭐⭐图的组合天然支持(合并两个图即可),但语义层面的组合需要本体对齐
可扩展性⭐⭐⭐⭐⭐本体可以无限扩展(新的 Class, Property, Axiom),且与现有本体兼容
查询友好⭐⭐⭐⭐⭐SPARQL/Cypher 是图查询的标准语言——比 JSONB 自由文本查询强几个数量级
采用成本⭐⭐OWL 本体建模的学习曲线陡峭;引入图数据库会显著增加运维复杂度;Protégé 等工具链与 TypeScript 生态不兼容

核心借鉴点:

  • OWL 的约束表达力是上限参照:当前 Archetype Condition 的 text/archetype_ref 在最底层,OWL 的公理体系在最顶层——我们需要在中间找一个平衡点
  • Property Graph 的"关系可以有属性"是重要的设计启示:dependsOn 关系应该有 strength(强/弱依赖)、direction(单向/双向)、reason(为什么依赖)等属性——当前通过中间表 condition_dependencies 实现,但无关系属性
  • 不建议引入图数据库:当前的 PostgreSQL JSONB + 关系表足以支撑结构描述的中等复杂度场景;图数据库是优化项而非必需项
  • 可以借鉴 RDF 的 URI 命名思想:为每个结构单元分配全局唯一的 URI 标识,便于跨项目引用

Wasp @wasp.sh/spec

来源:Wasp (https://wasp.sh/)

核心思想:用 TypeScript DSL 声明式定义全栈应用的结构(routes, pages, queries, actions, jobs, entities),Wasp 编译器生成胶水代码。

Spec 声明示例
import { app, route, page, query, action, job } from "@wasp.sh/spec";
import { MainPage } from "./src/MainPage" with { type: "ref" };
import { getTasks } from "./src/queries" with { type: "ref" };
import { createTask } from "./src/actions" with { type: "ref" };

export default app({
  name: "TodoApp",
  title: "TodoApp",
  spec: [
    route("RootRoute", "/", page(MainPage)),
    query(getTasks, { entities: ["Task"] }),
    action(createTask, { entities: ["Task"] }),
  ],
})
声明类型
声明语义Daedalus 对应
pageUI 页面≈ Crate (type=page)
routeURL → Page 映射≈ 路由 Archetype
query只读数据获取≈ 数据读操作的 Crate
action数据写入≈ 数据写操作的 Crate
job后台任务≈ Crate (type=job)
entityPrisma 数据模型≈ 数据库表 Archetype
crud自动 CRUD≈ 通用 CRUD Archetype
适用性评估
维度评分说明
结构单元建模⭐⭐⭐声明类型精确但固定——page/query/action/job 是 Wasp 特有的,不够通用
关系建模⭐⭐⭐entities 声明声明了数据依赖关系(query 依赖哪些 entity)
约束/契约建模⭐⭐⭐⭐authRequired, entities 自动缓存失效是"行为契约"的体现
边界表达⭐⭐非 Wasp 关注点
可组合性⭐⭐⭐⭐spec 数组可组合任意声明;可以拆分到多个文件
可扩展性⭐⭐声明类型由 Wasp 框架定义,用户不能自定义新的声明类型
查询友好⭐⭐⭐TypeScript AST 可被分析/查询
采用成本⭐⭐Wasp 是全栈框架,无法只使用其 spec 层

核心借鉴点:

  • spec 数组作为"应用的声明式结构描述":这种"将所有结构单元放在一个 spec 数组中声明"的模式,可以直接转化为 Daedalus 中的"Repository 的结构描述"
  • entities 声明自动驱动缓存失效:如果 Archetype Condition 变更,可以自动标记受影响的 Crate 需要重新审查——这是元数据驱动的自动化
  • 声明式优于命令式:Wasp 用声明表达"应用有什么",而不是"怎么构建"——Daedalus 的 Crate/Archetype 也应该坚持声明式

json-render Catalog 模式

来源:Vercel Labs (https://github.com/vercel-labs/json-render)

核心思想:用 Zod schema 定义组件目录(Catalog),AI 在目录的约束内生成 JSON spec——把"定义可约束的结构单元"提升为一等公民。

Catalog 定义
import { defineCatalog } from '@json-render/core';
import { z } from 'zod';

export const catalog = defineCatalog(schema, {
  components: {
    Card: {
      props: z.object({
        title: z.string(),
        description: z.string().optional(),
      }),
      children: true,        // 可以有子元素
    },
    Button: {
      props: z.object({
        label: z.string(),
        variant: z.enum(['default', 'destructive', 'outline', 'ghost']),
      }),
      children: false,       // 无子元素
    },
  },
});
JSON Spec
{
  "root": "card-1",
  "elements": {
    "card-1": {
      "type": "Card",
      "props": { "title": "Dashboard" },
      "children": ["btn-1"]
    },
    "btn-1": {
      "type": "Button",
      "props": { "label": "View Details", "variant": "default" }
    }
  }
}
适用性评估
维度评分说明
结构单元建模⭐⭐⭐⭐Catalog + Zod schema 精确定义了"什么是一个合法的结构单元"
关系建模⭐⭐⭐⭐children 数组表达了树状组合关系;flat tree 结构天然支持 ID 引用
约束/契约建模⭐⭐⭐⭐⭐Zod schema 即约束——z.enum(), z.string().min(), z.object() 等原生表达所有约束
边界表达⭐⭐⭐⭐children: true/false 精确控制"能否包含子元素"——叶节点 vs 容器节点
可组合性⭐⭐⭐⭐⭐Catalog 可 merge(mergeCatalogs());元素可通过 ID 引用任意组合
可扩展性⭐⭐⭐⭐⭐自定义组件 + 自定义 props schema + 自定义 directives——完全开放
查询友好⭐⭐⭐⭐JSON 结构化数据天然可查询;catalog.validate() 提供运行时验证
采用成本⭐⭐⭐⭐Zod 已在项目中使用;JSON spec 格式极简;flat tree 模式易于 LLM 生成/解析

核心借鉴点:

  • 这是对 Archetype Condition 演进最具启发性的方案:
    1. 当前 Condition 的 { type: "text" | "archetype_ref", value: string } → 可以演化为 Zod schema 定义的强类型 Condition
    2. children: true/false → Condition 的 isComposite 字段,表示该 Archetype 是否可成为其他 Archetype 的依赖
    3. catalog.validate() → 审查时自动验证 Crate 是否满足 Archetype 的所有 Condition
  • flat tree + ID 引用模式:比嵌套 JSON 更适合 LLM 生成(不会产生不闭合的括号),适合作为结构描述的数据格式
  • "约束优先"是本质思想:先定义 Schema/Catalog,然后所有具体结构单元都在这个约束内产生——这就是 Archetype(契约)→ Crate(实例)的关系

Google AIP / Buf

来源:Google API Improvement Proposals (https://google.aip.dev/), Buf (https://buf.build/)

核心思想:通过统一的 API 设计指南(AIP)+ Protocol Buffer schema 定义 + 自动化 lint 规则,确保所有 API 遵循一致的 resource-oriented 设计模式。

AIP 资源建模

AIP 定义了标准的 resource-oriented 设计模式:

概念示例
Resource//pubsub.googleapis.com/projects/{project}/topics/{topic}
Resource Name层级化的资源路径,父资源包含子资源
Resource Typetype.googleapis.com/google.pubsub.v1.Topic
Standard MethodsCreate, Get, Update, Delete, List
Custom MethodsPublish, Subscribe, Acknowledge
Buf Schema Registry 治理模式
  • Proto 文件集中存储(BSR)
  • 自动化 lint(AIP 兼容检查)+ breaking change 检测
  • 依赖管理(proto 之间的导入关系)
适用性评估
维度评分说明
结构单元建模⭐⭐⭐⭐Resource 概念+层级命名+标准方法 = 完整的 API 结构建模
关系建模⭐⭐⭐⭐Resource name 的路径层级天然表达 partOf 关系
约束/契约建模⭐⭐⭐⭐⭐AIP 的 lint 规则 + Buf 的 breaking change 检测是契约验证的工业化方案
边界表达⭐⭐⭐⭐API 本质上就是边界——定义外部可见的接口
可组合性⭐⭐⭐Resource 层级组合;API 方法是 Resource 的行为契约
可扩展性⭐⭐⭐Proto 语法可扩展(options),但受限于 protobuf 生态
查询友好⭐⭐⭐BSR 支持按 package/resource 搜索
采用成本⭐⭐Protocol Buffer 生态与 TypeScript 有桥接但不够原生;AIP 以 API 为中心,与 Daedalus 的代码结构审查场景有差异

核心借鉴点:

  • Resource Name 的层级路径模式:projects/{project}/topics/{topic}/subscriptions/{subscription} → 可以用于统一描述 Daedalus 中结构单元的层级:repositories/{repo}/crates/{crate}/modules/{module}
  • AIP 的 lint 规则模式:可以将 Archetype Condition 视为"架构 lint 规则",每次审查时自动检查 Crate 是否违反任何 Condition
  • 但注意:AIP 面向的是 REST/gRPC API 设计,而不是代码内部结构。直接采用范围太窄。

架构描述语言 (ADL)

来源:ACME (CMU), xADL (UC Irvine), Darwin (Imperial College), AADL (SAE AS5506)

核心思想:用形式化语言描述软件架构的组件(Component)、连接子(Connector)和配置(Configuration)。

通用 ADL 概念模型

所有 ADL 共享一个核心概念三元组:

概念含义Daedalus 对应
Component计算单元 + 数据存储,有类型的接口(Port)≈ Crate + 暴露的 API
Connector协调组件间通信/交互的一等公民≈ 关系 + 关系属性
Configuration/SystemComponent 实例通过 Connector 连接形成的图≈ Repository 的 Crate 依赖图
各 ADL 关键差异
ADLConnector 地位形式化基础特殊价值
ACME一等公民(有 Port + Role)Armani 约束语言架构互换格式
xADL一等公民(XML schema 定义)XML + 扩展 Schema模块化、可扩展
Darwin非一等公民(隐式 bind)π-calculus分布式系统的动态重配置
AADL一等公民(带 timing 属性)实时系统理论嵌入式/安全关键系统的可调度性分析
适用性评估
维度评分说明
结构单元建模⭐⭐⭐⭐⭐Component/Connector/Configuration 是经过 30+ 年验证的架构建模范式
关系建模⭐⭐⭐⭐⭐Connector 作为一等公民——关系可以有自己的属性、约束和语义
约束/契约建模⭐⭐⭐⭐ACME 的 Armani 语言、AADL 的 property sets 提供约束表达能力
边界表达⭐⭐⭐⭐⭐Port + Role 精确定义了"组件暴露什么"和"连接子期望什么"
可组合性⭐⭐⭐⭐Configuration 可嵌套;Representation 支持层级展开
可扩展性⭐⭐⭐⭐大多数 ADL 支持通过 property/annotation 扩展
查询友好⭐⭐ADL 本身不关注查询
采用成本⭐ADL 生态的工具链与 Web/TypeScript 世界完全脱节;概念形式化程度过高

核心借鉴点:

  • Connector 作为一等公民是 ADL 最本质的贡献:在 Daedalus 中,这意味着"Crate 之间的依赖关系"应该有独立的建模——不仅仅是 crateA 依赖 crateB,还应该有依赖的性质(compile-time vs runtime)、方向(单向 vs 双向)、契约(接口约定)
  • Port/Role 区分:组件的 Port(暴露接口)和连接子的 Role(期望角色)的区分——对应 Crate 的"提供的功能"和"依赖的接口"
  • 但注意:ADL 的 Connector 设计用于表达 RPC、事件总线、共享内存等通信协议,对代码结构的静态描述过于重型

交叉对比矩阵

综合评分

方案结构单元关系约束边界可组合性可扩展性查询采用成本加权总分
Backstage Catalog553455434.1
C4 + Structurizr432543243.4
ArchUnit/dep-cruiser245433343.5
DDD434544233.7
Rust Module543543243.8
RDF/OWL + PG455345524.1
Wasp Spec334242322.9
json-render Catalog445455444.4
Google AIP / Buf445433323.5
ADL (ACME/xADL)554544213.8

> 加权公式:(结构单元 × 2 + 关系 × 2 + 约束 × 2 + 边界 × 1.5 + 可组合性 × 1 + 可扩展性 × 1 + 查询 × 1 + 采用成本 × 0.5) / 11

按关注点分组的强项方案

关注点最强方案得分借鉴优先级
统一实体建模Backstage Catalog + Rust Module5🔴 最高
关系建模RDF/PG + ADL Connector5🟡 高
约束/契约json-render Catalog + OWL + ArchUnit5🔴 最高
边界表达DDD + Rust visibility + C4 Container5🟡 高
可组合性Backstage Catalog + json-render5🟢 中
可扩展性Backstage Catalog + RDF/OWL + json-render5🟢 中
采用成本json-render + Structurizr + dep-cruiser4🟡 高

与 Daedalus 概念的直接映射

Daedalus 概念BackstageC4DDDRustjson-renderADL
CrateComponentContainer/ComponentAggregateCrateCatalog ComponentComponent
ArchetypeAPI (部分) + 自定义 Kind—Domain Service + SpecificationTraitZod SchemaConnector Type
Archetype.scopeSystem/Domain hierarchyC1-C4 levelsBounded Context hierarchyCrate/Module hierarchy—Configuration nesting
Condition— (外部 lint)Tags + PropertiesInvariant + Specificationwhere clause + trait boundZod schema propsArmani constraint
Condition DependencyRelations (dependsOn)—Context Maptrait dependency—Connector attachment
RepositorySystemSoftwareSystemBounded ContextPackage—Configuration

决策建议

适配为主,自定义为辅

不推荐直接采用任何单一方案。理由:

  1. Backstage Catalog 最接近但以服务治理为中心(API/Component/Resource 三类实体对 Daedalus 过窄)
  2. json-render Catalog 的 Zod 约束模式极强但面向 UI 组件而非代码结构
  3. DDD 思想深刻但作为完整方法论过重
  4. RDF/OWL 表达力完整但学习曲线和运维成本过高

推荐"混合适配"策略:以 Backstage 实体模型为骨架 + json-render Zod 约束为肌肉 + DDD 边界思想为灵魂 + Rust 模块可见性为神经。

具体建议

建议 1:引入统一的 StructureUnit 抽象

借鉴 Backstage 的 Entity envelope 模式,所有结构相关实体共享一个基础层:

StructureUnit (抽象基)
 ├── unitId: 全局唯一标识
 ├── unitKind: "crate" | "archetype" | "repository" | "page" | "service" | ...
 ├── unitType: 可扩展的子类型标签(多值)
 ├── displayName: 人类可读名称
 ├── description: 描述
 ├── scope: 所处的 StructureUnit 层级引用
 ├── relations: 关系列表
 │    ├── relationType: "partOf" | "hasPart" | "dependsOn" | "implements" | "references" | ...
 │    ├── targetUnitId: 目标 StructureUnit
 │    └── properties: 关系属性 (strength?, reason?, ...)
 ├── boundary: 边界定义
 │    ├── exposes: 暴露的接口/API 列表
 │    └── encapsulates: 内部实现的文件/路径模式
 └── properties: 扩展属性 (JSONB)
建议 2:用 Zod Schema 重构 Condition

借鉴 json-render 的 Catalog Schema 模式,将 Condition 从简单的 { type, value } 升级为强类型约束:

// 约束类型枚举
const ConditionSchema = z.discriminatedUnion("conditionType", [
  z.object({
    conditionType: z.literal("text"),
    value: z.string(),                         // 现有的文本约束
  }),
  z.object({
    conditionType: z.literal("archetype_ref"),
    archetypeId: z.string(),                   // 现有的 Archetype 引用
  }),
  z.object({
    conditionType: z.literal("path_pattern"),
    pattern: z.string(),                       // 文件路径必须匹配 glob
    modifier: z.enum(["must_exist", "must_not_exist", "must_contain"]),
  }),
  z.object({
    conditionType: z.literal("dependency"),
    direction: z.enum(["depends_on", "depended_on_by"]),
    targetPattern: z.string(),                 // 依赖目标匹配模式
    cardinality: z.enum(["at_least_one", "exactly_one", "zero_or_more"]).optional(),
  }),
  z.object({
    conditionType: z.literal("structural"),
    constraint: z.enum([
      "has_readme", "has_tests", "has_stories",
      "has_index_barrel", "no_circular_deps",
      "single_responsibility", "public_api_documented",
    ]),
  }),
  z.object({
    conditionType: z.literal("quantity"),
    target: z.string(),                        // 目标元素(如 "files", "exports", "dependencies")
    operator: z.enum(["eq", "gt", "gte", "lt", "lte", "between"]),
    value: z.number(),
    maxValue: z.number().optional(),           // between 时用
  }),
]);
建议 3:采纳层级化命名约定

借鉴 Rust pub use 路径 + Backstage {kind}:{namespace}/{name} + Google AIP Resource Name:

repository:default/my-repo/crate:default/my-repo/auth-module/page:default/my-repo/login

这提供了统一的引用语法,并使结构查询可以直接按路径层级过滤。

建议 4:关系模型升级

借鉴 ADL Connector 的设计,将"关系"提升为一等公民:

  • 关系有自己的 relationType(不只是"依赖",而是 partOf、implements、dependsOn、references 等)
  • 关系可以携带属性(strength: strong | weak、direction: uni | bi、reason: string)
  • 关系是独立的数据库记录(已有 condition_dependencies 中间表的基础,扩展即可)
建议 5:暂不引入图数据库

虽然 RDF/Property Graph 的表达力最强,但当前阶段:

  • PostgreSQL JSONB 足以支撑结构描述的存储
  • PostgreSQL 的递归 CTE 可以处理层级查询
  • 如果未来 Archetype 依赖树的查询性能成为瓶颈,再考虑引入 Neo4j 作为只读查询引擎

如有必要:轻量自定义方案草案

基于以上分析,以下是一个轻量自定义方案的草案。它不是要替换现有 Crate/Archetype 模型,而是提供一个共享的泛化层,使这些实体能够统一描述和互操作。

核心实体

// === 1. StructureUnit:统一结构单元(泛化 Crate、Archetype、Repository 等)===

interface StructureUnit {
  /** 全局唯一标识,格式: {kind}:{namespace}/{name} */
  uid: string;

  /** 结构单元种类 */
  kind: StructureKind; // "crate" | "archetype" | "repository" | "page" | "service" | custom

  /** 结构单元子类型(可多值,可扩展) */
  types: string[]; // 替代当前 Crate.type 固定枚举

  /** 人类可读名称 */
  displayName: string;

  /** 描述 */
  description?: string;

  /** 所属父结构单元(层级关系) */
  parentUid?: string;

  /** 所处层级 */
  level?: StructureLevel; // "workspace" | "repository" | "crate" | "module" | "file" | "function"

  /** 边界定义 */
  boundary?: Boundary;

  /** 扩展属性 */
  properties?: Record<string, unknown>;
}

type StructureKind = string; // 可扩展:不仅是内置 kind,用户可定义新 kind
type StructureLevel = string; // 可扩展

// === 2. Boundary:边界定义 ===

interface Boundary {
  /** 暴露的接口——对外可见的 API */
  exposes: ExposedInterface[];
  /** 内部实现范围(文件路径 glob 模式) */
  encapsulations: string[];
  /** 可见性控制 */
  visibility: "public" | "internal" | "private";
}

interface ExposedInterface {
  name: string;
  kind: "function" | "class" | "type" | "variable" | "component" | "route" | custom;
  signature?: string;
  path: string; // 文件路径
}

// === 3. Relation:结构单元之间的关系(一等公民)===

interface Relation {
  /** 关系 ID */
  id: string;
  /** 源结构单元 uid */
  sourceUid: string;
  /** 目标结构单元 uid */
  targetUid: string;
  /** 关系类型 */
  relationType: RelationType;
  /** 关系属性 */
  properties?: RelationProperties;
}

type RelationType =
  | "dependsOn"       // 运行时依赖
  | "partOf"          // 作为目标的一部分
  | "hasPart"          // 包含子单元
  | "implements"       // 实现了目标的接口/契约
  | "references"       // 引用(非依赖的弱引用)
  | "conformsTo";      // 符合 Archetype(Crate → Archetype 的关系)

interface RelationProperties {
  strength?: "strong" | "weak";
  direction?: "unidirectional" | "bidirectional";
  reason?: string;
  [key: string]: unknown; // 可扩展
}

// === 4. Constraint:约束(升级后的 Condition)===

type Constraint =
  | TextConstraint
  | ArchetypeRefConstraint
  | PathPatternConstraint
  | DependencyConstraint
  | StructuralConstraint
  | QuantityConstraint;

interface TextConstraint {
  constraintType: "text";
  value: string;
}

interface ArchetypeRefConstraint {
  constraintType: "archetype_ref";
  archetypeUid: string;
}

interface PathPatternConstraint {
  constraintType: "path_pattern";
  pattern: string;           // glob
  modifier: "must_exist" | "must_not_exist" | "must_contain";
}

interface DependencyConstraint {
  constraintType: "dependency";
  direction: "depends_on" | "depended_on_by";
  targetPattern: string;
  cardinality?: "at_least_one" | "exactly_one" | "zero_or_more";
}

interface StructuralConstraint {
  constraintType: "structural";
  rule: string; // "has_readme" | "has_tests" | "has_stories" | "has_index_barrel" | "no_circular_deps" | custom
}

interface QuantityConstraint {
  constraintType: "quantity";
  target: string;     // "files" | "exports" | "dependencies" | ...
  operator: "eq" | "gt" | "gte" | "lt" | "lte" | "between";
  value: number;
  maxValue?: number;
}

与现有模型的对应关系

现有 Crate Table → StructureUnit (kind="crate")
现有 Archetype Table → StructureUnit (kind="archetype")
现有 ArchetypeCondition Table → Constraint (挂载在 StructureUnit (kind="archetype") 上)
现有 condition_dependencies Table → Relation (relationType="dependsOn", source=Condition, target=Archetype)
Crate → Archetype 绑定 (COD-88) → Relation (relationType="conformsTo", source=Crate, target=Archetype)
Repository (现有) → StructureUnit (kind="repository")
未来:Skill, Item, Achievement → StructureUnit (kind="skill" | "item" | "achievement")

对现有 DB Schema 的兼容性

本方案不要求立即修改现有 DB schema。推荐的演进路径:

  1. Phase 1(当前 COD-104 后):在 docs/ 中记录统一模型作为设计文档,不改代码
  2. Phase 2(后续 COD):在代码中添加 StructureUnit TypeScript 类型和映射函数,使现有 Crate/Archetype 可通过适配器转换为统一模型
  3. Phase 3(长期):若统一模型验证有效,逐步将数据库 schema 迁移到统一的 structure_units 表

草稿验证

场景 1:Button 组件
const buttonCrate: StructureUnit = {
  uid: "crate:default/ui-button",
  kind: "crate",
  types: ["component", "ui"],
  displayName: "Button",
  description: "基础交互触发组件",
  level: "crate",
  boundary: {
    exposes: [
      { name: "Button", kind: "component", path: "src/components/Button/Button.tsx" },
    ],
    encapsulations: ["src/components/Button/**"],
    visibility: "public",
  },
};

const buttonArchetype: StructureUnit = {
  uid: "archetype:default/component-design-best-practice",
  kind: "archetype",
  types: ["design-contract"],
  displayName: "Component Design Best Practice",
  level: "crate",
};

const conformsRelation: Relation = {
  id: "rel-001",
  sourceUid: "crate:default/ui-button",
  targetUid: "archetype:default/component-design-best-practice",
  relationType: "conformsTo",
  properties: { strength: "strong" },
};
场景 2:Button Group 与 Button 的组合关系
const buttonGroupCrate: StructureUnit = {
  uid: "crate:default/ui-button-group",
  kind: "crate",
  types: ["component", "container"],
  displayName: "ButtonGroup",
  level: "crate",
};

const compositionRelation: Relation = {
  id: "rel-002",
  sourceUid: "crate:default/ui-button-group",
  targetUid: "crate:default/ui-button",
  relationType: "dependsOn",
  properties: { strength: "strong", reason: "ButtonGroup 聚合 Button 实例" },
};
场景 3:Monorepo 层级结构
const daedalusRepo: StructureUnit = {
  uid: "repository:default/daedalus",
  kind: "repository",
  types: ["monorepo", "turborepo"],
  displayName: "Daedalus",
  level: "repository",
};

const appPackage: StructureUnit = {
  uid: "crate:default/daedalus-app",
  kind: "crate",
  types: ["application", "web"],
  displayName: "@daedalus/app",
  level: "crate",
  parentUid: "repository:default/daedalus", // 层级关系
};

const appToAppRelation: Relation = {
  id: "rel-003",
  sourceUid: "crate:default/daedalus-app",
  targetUid: "repository:default/daedalus",
  relationType: "partOf", // 与 parentUid 呼应但更语义化
};

✅ 三个场景均可被草案表达。


开放问题

#问题当前倾向影响
1Archetype/Crate 的长期演进方向:是否需要通用化到 Skill、Item、Achievement 等领域?是——统一 StructureUnit 抽象为此预留扩展能力若仅服务于 Crate/Archetype,则过度抽象;若需要通用化,则现在设计好基础可避免未来重构
2结构描述的消费方:是给人读的文档、LLM 消费的上下文、还是可视化引擎的数据源?三者的优先级:LLM > 可视化 > 人类阅读LLM 消费需要结构化+可序列化(JSON Schema);可视化需要图结构;人类阅读需要层级化摘要
3关系属性的存储深度:关系上需要挂多少属性?当前 condition_dependencies 中间表仅存储两个外键,按 ADL Connector 思路需要更多属性渐进式——先加 properties: JSONB 字段,再根据实际使用决定是否结构化JSONB 灵活但无 schema 约束;结构化列精确但迁移成本高
4统一表的时机:现在统一还是先不改?先不改——在 TypeScript 层面建立统一模型,DB 层面维持现状,通过映射层桥接早期统一表可能过度设计;但若 TypeScript 层模型与 DB 层长期不一致,会增加认知负担

参考来源

方案官方文档

  1. Backstage Catalog Model: https://backstage.io/docs/features/software-catalog/system-model
  2. Backstage Descriptor Format: https://backstage.io/docs/features/software-catalog/descriptor-format
  3. Structurizr DSL: https://structurizr.com/
  4. ArchUnit: https://www.archunit.org/
  5. dependency-cruiser: https://github.com/sverweij/dependency-cruiser
  6. Wasp Spec: https://wasp.sh/docs
  7. json-render: https://github.com/vercel-labs/json-render
  8. Google AIP: https://google.aip.dev/
  9. Buf: https://buf.build/
  10. Rust Crate/Module: https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html
  11. Neo4j Property Graph: https://neo4j.com/

学术/技术参考

  1. ACME ADL (Garlan et al., CMU): https://www.cs.cmu.edu/~acme/
  2. xADL (Dashofy et al., UC Irvine): https://isr.uci.edu/projects/xarchuci/
  3. Darwin (Magee et al., Imperial College): π-calculus-based distributed system ADL
  4. AADL (SAE AS5506): https://www.aadl.info/
  5. OWL 2 Web Ontology Language: https://www.w3.org/TR/owl2-overview/
  6. RDF-star / Property Graph bridging (OWLStar): https://github.com/linkml/owlstar
  7. Reimplementing Structurizr DSL as Hybrid DSL (ICSA 2025): https://conf.researchr.org/details/icsa-2025/icsa-2025-workshops/23/

Daedalus 内部参考

  1. COD-80: Crate 实体
  2. COD-81: Archetype 概念定义
  3. COD-86: Archetype 定义管理
  4. COD-100: 场景分析
  5. 当前 DB Schema