This commit is contained in:
mangomqy
2025-11-13 02:54:06 +00:00
commit c5e51ed069
254 changed files with 54901 additions and 0 deletions

View File

@ -0,0 +1,348 @@
# 📋 OCDP 开发规范
本文档定义了 OCDP 项目的开发规范和架构要求。
## 🎯 整体架构 (Full Stack)
### 1. OpenAPI 驱动开发
采用 OpenAPI 规范来驱动前后端开发,确保 API 契约的一致性。
**优势**
- API 设计优先,前后端并行开发
- 自动生成类型安全的代码
- 文档和代码永远同步
- 减少沟通成本
**实践**
```bash
# 1. 设计 API (编辑 backend/docs/openapi.yaml)
# 2. 验证规范
make openapi-validate
# 3. 生成代码
make openapi-gen
# 4. 实现功能
```
### 2. Docker Compose 部署
使用 Docker Compose 进行整个应用的部署。新版的 Docker 已经将 Compose 集成到 Docker 里面了,所以使用 `docker compose`(带空格)而非旧版的 `docker-compose`(带连字符)。
**部署服务**
- PostgreSQL - 数据持久化
- Redis - 缓存和会话
- Backend - Go 后端服务
- Frontend - React 前端应用
- Nginx - 反向代理(生产环境)
## 🎨 前端规范 (Frontend)
### 1. 纯函数渲染
**要求**:使用纯函数进行组件渲染,避免不必要的副作用。
**原则**
- 组件应该是可预测的(相同输入→相同输出)
- 避免在渲染过程中修改外部状态
- 使用 `useEffect` 等 Hook 处理副作用
- 保持组件的可测试性
**示例**
```typescript
// ✅ 好的实践 - 纯函数组件
interface Props {
name: string;
count: number;
}
const UserCard = ({ name, count }: Props) => {
// 纯函数:只依赖 props不修改外部状态
return (
<div>
<h3>{name}</h3>
<p>Count: {count}</p>
</div>
);
};
// ✅ 副作用在 useEffect 中处理
const UserList = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
// 副作用API 调用)在这里处理
fetchUsers().then(setUsers);
}, []);
return users.map(user => <UserCard {...user} />);
};
// ❌ 不好的实践 - 在渲染中产生副作用
const BadComponent = () => {
// 不要在这里调用 API 或修改外部状态
globalState.count++; // ❌ 副作用
fetchData(); // ❌ 副作用
return <div>Bad</div>;
};
```
### 2. 技术栈
- **框架**: React 18+ (使用 Hooks)
- **语言**: TypeScript 5+
- **构建工具**: Vite
- **样式**: Tailwind CSS
- **路由**: React Router 6+
- **状态管理**: React Context + Hooks
- **API 客户端**: 从 OpenAPI 自动生成
## 🔧 后端规范 (Backend)
### 1. 六边形架构 (Hexagonal Architecture)
后端采用六边形架构(也称为端口和适配器架构),将业务逻辑与技术实现解耦。
**核心目录结构**
```
backend/internal/
├── domain/ # 领域层 - 业务逻辑核心
│ ├── entity/ # 领域实体
│ ├── service/ # 领域服务
│ └── repository/ # 仓库接口(端口)
├── application/ # 应用层 - 用例编排
│ └── usecase/ # 用例实现
└── adapter/ # 适配器层 - 技术实现
├── input/ # 输入适配器
│ └── http/ # HTTP REST API
└── output/ # 输出适配器
├── persistence/
│ ├── mock/ # Mock 实现
│ └── postgres/ # PostgreSQL 实现
├── oci/ # OCI Registry 客户端
└── helm/ # Helm SDK 封装
```
**职责划分**
- **Domain 层**:纯业务逻辑,不依赖任何框架或外部库
- **Application 层**:编排 Domain 层的服务,实现具体的用例
- **Adapter 层**处理所有技术细节HTTP、数据库、第三方 API
### 2. Mock Adapter 实现
**要求**:除了实现 ports 的 adapters 外,还要做 mock。Mock 的是 adapter 的行为反应而非假数据。
**Mock 原则**
- ✅ 模拟真实 adapter 的行为
- ✅ 可以注入真实数据
- ✅ 可以通过调用接口自行加入数据
- ✅ 使用内存来模拟 adapter 的交互
- ❌ 不是返回固定的假数据
**示例**
```go
// Mock Repository - 模拟真实的数据库行为
type RegistryRepositoryMock struct {
registries map[string]*entity.Registry // 内存存储
mu sync.RWMutex
}
func (r *RegistryRepositoryMock) Create(ctx context.Context, registry *entity.Registry) error {
r.mu.Lock()
defer r.mu.Unlock()
// 模拟真实行为:检查重复、生成 ID、加密等
if _, exists := r.registries[registry.ID]; exists {
return errors.New("registry already exists")
}
r.registries[registry.ID] = registry
return nil
}
func (r *RegistryRepositoryMock) GetByID(ctx context.Context, id string) (*entity.Registry, error) {
r.mu.RLock()
defer r.mu.RUnlock()
registry, exists := r.registries[id]
if !exists {
return nil, errors.New("registry not found")
}
return registry, nil
}
```
### 3. Makefile 支持
**要求**:采用 Makefile 来支持 mock 启动以及 real 启动。
**命令规范**
```makefile
# 开发模式Mock Adapter
run-mock:
@echo "Starting backend with Mock adapters..."
MODE=mock go run cmd/api/main.go
# 生产模式Real Adapter
run-real:
@echo "Starting backend with Real adapters..."
MODE=real go run cmd/api/main.go
# 运行测试
test:
go test -v ./...
# 生成代码
generate:
go generate ./...
```
**使用方式**
```bash
# 开发模式(无需数据库)
make run-mock
# 生产模式(需要 PostgreSQL
make run-real
```
### 4. 技术栈
- **语言**: Go 1.21+
- **Web 框架**: Gin (轻量、高性能)
- **ORM**: GORM (可选,用于 PostgreSQL adapter)
- **OCI 客户端**: ORAS Go SDK v2
- **Helm 客户端**: Helm SDK v3
- **K8s 客户端**: client-go
## 📐 架构原则
### 1. 依赖方向
```
Adapter → Application → Domain
(技术) (编排) (业务)
```
- Domain 层不依赖任何外部库(除了标准库)
- Application 层依赖 Domain 层
- Adapter 层依赖 Application 和 Domain 层
### 2. 端口和适配器
**端口Port**:接口定义,在 Domain 层
```go
// domain/repository/registry_repository.go
type RegistryRepository interface {
Create(ctx context.Context, registry *entity.Registry) error
GetByID(ctx context.Context, id string) (*entity.Registry, error)
List(ctx context.Context) ([]*entity.Registry, error)
}
```
**适配器Adapter**:接口实现,在 Adapter 层
```go
// adapter/output/persistence/mock/registry_repository_mock.go
type RegistryRepositoryMock struct {
// Mock 实现
}
// adapter/output/persistence/postgres/registry_repository_postgres.go
type RegistryRepositoryPostgres struct {
// PostgreSQL 实现
}
```
### 3. 依赖注入
使用构造函数注入依赖:
```go
// 创建 Mock 模式的应用
func NewMockApp() *App {
// 创建 Mock Repository
registryRepo := mock.NewRegistryRepositoryMock()
// 创建 Service注入 Repository
registryService := service.NewRegistryService(registryRepo)
// 创建 Handler注入 Service
registryHandler := handler.NewRegistryHandler(registryService)
return &App{
RegistryHandler: registryHandler,
}
}
// 创建 Production 模式的应用
func NewProductionApp(db *gorm.DB) *App {
// 创建 PostgreSQL Repository
registryRepo := postgres.NewRegistryRepositoryPostgres(db)
// ... 其他相同
}
```
## 🔄 开发工作流
### 1. 功能开发流程
```bash
# 1. 设计 API
vim backend/docs/openapi.yaml
# 2. 生成代码
make openapi-gen
# 3. 实现 Domain 层
vim backend/internal/domain/service/xxx_service.go
# 4. 实现 Mock Adapter
vim backend/internal/adapter/output/persistence/mock/xxx_mock.go
# 5. 实现 Handler
vim backend/internal/adapter/input/http/handler/xxx_handler.go
# 6. 启动测试
make run-mock
# 7. 实现前端
vim frontend/src/features/xxx/pages/XxxPage.tsx
# 8. 集成测试
make dev
# 9. 实现 Production Adapter
vim backend/internal/adapter/output/persistence/postgres/xxx_postgres.go
# 10. 部署测试
docker compose up
```
### 2. 测试策略
- **单元测试**Domain 层和 Service 层(使用 Mock Repository
- **集成测试**:使用 Mock Adapter 测试完整流程
- **E2E 测试**:使用真实 Adapter 测试生产环境
## 📚 参考文档
- [后端六边形架构详解](../../backend/HEXAGONAL_ARCHITECTURE.md)
- [OpenAPI 规范](../../backend/docs/openapi.yaml)
- [Docker 部署指南](../deployment/docker-guide.md)
- [安全实现方案](../security/security-implementation.md)
---
**版本**: 1.0
**最后更新**: 2025-11-07