Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions frontend-architecture-v3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Windup 前端粗架构

## 本 PR 的目标

本 PR 只确定粗粒度模块、公开接口和必要类型。具体目录细分、服务端调用、流程状态转换、生成处理、页面交互、测试和工程配置分别由后续小 PR 实现。

## 依赖方向

```text
app -> pages -> features -> workflow-controller / entities -> shared
```

- `app`:启动、路由、布局。
- `pages`:路由页面和模块组合。
- `features`:角色设置、生成、审核、导出。
- `workflow-controller`:Quick Start 与 Workflow Editor 共享的整体流程接口。
- `entities`:业务数据及其服务端 APIs。
- `shared`:不理解 Windup 业务语义的通用 UI、Hooks、工具与配置边界。

`shared` 只能被上层依赖,不能反向导入任何 Entity 或业务模块。当前没有需要沉淀的
公共实现,因此只保留职责说明,不为了目录完整度制造空工具代码。

## 两种制作方式

Quick Start 使用自然语言和参考图直接表达目标,自动流程隐藏内部步骤;Workflow Editor 让用户逐步操作。两者页面和显示内容完全不同,但共享 WorkflowRun、WorkflowStep 和 Workflow Controller 接口。

## Workflow 边界

Workflow Controller 负责维护步骤数据、当前步骤、历史 Revision 和流程推进。每个 Revision 通过 `currentStepId` 明确指向当前步骤;服务端异步结果携带发起请求时的 `revisionId`,防止重启后的旧结果串入新版本。需要服务端结果的步骤由 Controller 调用相应业务 APIs,并把返回结果更新到 WorkflowStep。WorkflowRun 作为业务资源由服务端持久化。

Controller 是一个整体,不把推进、重启、中断、恢复或服务端结果处理拆成独立模块。

## 多方向资产

Project 通过 `DirectionMode` 决定单方向、四方向或八方向。`BaseFrame` 使用
`SpriteDirection` 标注方向,Action 使用 `ActionSequence[]` 保存各方向的帧序列,
不依赖隐含的数组顺序猜测方向。

## Generation 边界

前端接触的是 Generation 和 Task 业务记录:创建记录、查询状态、展示结果,并据此更新 WorkflowStep。真正的模型调用发生在后端,前端不表达模型能力层。

## 当前未冻结

- 服务端 URL、DTO 外壳、认证和错误格式。
- 图片上传方法和媒体引用形式。
- 审核、导出和事件传输方法。
- Workflow Controller 的具体状态转换实现。
111 changes: 111 additions & 0 deletions frontend/API_CONTRACT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# 前端公开接口

本文件描述模块调用形状,不声明服务端 URL、请求外壳或错误格式。

## 命名约定

- TypeScript 类型和组件使用 PascalCase,字段、参数和方法使用 camelCase。
- URL 路径和源码目录使用 kebab-case,例如 `/quick-start`、`workflow-controller/`。
- 会进入业务 JSON 的枚举值统一使用 snake_case,例如 `create_character`、
`character_template`、`north_east`。
- 服务端业务接口集合遵循导师约定统一使用 `*APIs`,不混用其他接口后缀。
- 所有容易混淆的模板和候选字段必须带业务前缀,例如 `actionTemplateId`、
`characterTemplateCandidateId`。

## 业务 APIs

业务模块就近公开以下七组 APIs:

- `ProjectAPIs`:项目。
- `CharacterAPIs`:角色、造型和动作。
- `ActionTemplateAPIs`:动作模板。
- `WorkflowRunAPIs`:工作流持久化。
- `GenerationAPIs`:生成业务记录。
- `TaskAPIs`:异步任务快照。
- `PlaytestInspectionAPIs`:Playtest 独立核验记录。

它们只描述前端已确认的业务操作,具体实现等待对应后端合同。

```ts
interface ProjectAPIs {
list(): Promise<Project[]>
get(projectId: string): Promise<Project>
create(input: CreateProjectInput): Promise<Project>
update(projectId: string, input: UpdateProjectInput): Promise<Project>
remove(projectId: string): Promise<void>
}

interface CharacterAPIs {
get(characterId: string): Promise<Character>
listByProject(projectId: string): Promise<Character[]>
create(input: CreateCharacterInput): Promise<Character>
update(character: Character): Promise<Character>
confirmCharacterTemplate(
characterId: string,
input: ConfirmCharacterTemplateInput,
): Promise<Character>
addAction(characterId: string, input: AddActionInput): Promise<Character>
}

interface ActionTemplateAPIs {
listAvailable(projectId: string): Promise<ActionTemplate[]>
}

interface WorkflowRunAPIs {
create(input: CreateWorkflowRunInput): Promise<WorkflowRun>
get(runId: string): Promise<WorkflowRun>
update(run: WorkflowRun): Promise<WorkflowRun>
}

interface GenerationAPIs {
create(input: CreateGenerationInput): Promise<Generation>
get(generationId: string): Promise<Generation>
}

interface TaskAPIs {
get(taskId: string): Promise<Task>
}

interface PlaytestInspectionAPIs {
getLatest(target: {
characterId: string
outfitId: string
}): Promise<PlaytestInspection | null>
record(input: RecordPlaytestInspectionInput): Promise<PlaytestInspection>
}
```

图片上传、审核、导出和事件传输的正式方法尚未冻结,本 PR 不提前声明。

## Workflow Controller

Workflow Controller 操作一份 WorkflowRun 数据,不按 next、restart 等方法拆模块。

```ts
interface WorkflowController {
create(input: CreateWorkflowRunInput): Promise<WorkflowRun>
getWorkflow(): WorkflowRun
nextStep(): Promise<WorkflowRun>
updateStep(input: UpdateWorkflowStepInput): Promise<WorkflowRun>
restartFromStep(input: RestartWorkflowFromStepInput): Promise<WorkflowRun>
interrupt(): Promise<WorkflowRun>
resume(): Promise<WorkflowRun>
applyServerResult(input: ApplyWorkflowServerResultInput): Promise<WorkflowRun>
}
```

步骤的当前数据保存在 `WorkflowStep.data`,当前步骤由 `WorkflowRevision.currentStepId` 明确指向。从历史步骤重新开始时追加 Revision,旧 Revision 保持只读;异步服务端结果必须携带发起请求时的 `revisionId`,不能污染重启后的新版本。如何清理后续步骤由后续实现 PR 完成。

## 关键术语

- `ActionTemplate`:动作模板,描述动作名称与提示词。
- `ActionSource`:动作来自 ActionTemplate,还是来自用户自定义提示词。
- `candidateCharacterTemplates`:生成出的角色母版候选。
- `characterTemplateCandidateId`:用户确认的具体角色母版候选 ID。
- `characterTemplateUrl`:用户确认的角色母版。
- `baseFrames`:母版确认后展开的多方向基础帧。
- `DirectionMode`:Project 要求单方向、四方向还是八方向资产。
- `SpriteDirection`:基础帧和动作序列共同使用的明确精灵朝向。
- `ActionSequence`:一个动作在某个精灵朝向下的完整帧序列。
- `Generation`:前端创建、查询和展示的生成业务记录。
- `Task`:服务端异步任务快照,不等于 WorkflowStep。
41 changes: 41 additions & 0 deletions frontend/MODULES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 前端模块

## app

只负责启动、路由和全局布局。它不构造业务服务,也不决定 Workflow 如何推进。本 PR 保留 `src/app/README.md` 固定边界,不提交 app 运行实现。

## pages

页面是路由入口,负责组合粗粒度 Feature。Quick Start 与 Workflow Editor 是两个独立页面;Playtest 是只读核验入口。本 PR 保留 `src/pages/README.md` 固定边界,不提交页面运行实现。

## features

- `character-setup`:角色资料、造型、动作定义与参考素材。
- `generation`:创建和展示 Generation 业务记录。
- `review`:查看生成结果并形成审核结论。
- `export`:展示导出条件、配置与结果。

当前不继续拆分 Feature 内部目录。
本 PR 保留 `src/features/README.md` 固定边界,不提交 Feature 实现或占位组件。

## workflow-controller

维护同一份 WorkflowRun/WorkflowStep 数据,对外提供创建、推进、更新、重启、中断、恢复和接收服务端结果的方法。当前只声明整体接口,不提交状态转换和服务端调用实现。

## entities

业务实体按规模就近维护,通常使用:

- `types.ts`:数据结构。
- `apis.ts`:该业务资源对应的服务端方法集合。
- `index.ts`:唯一公开入口。

内容较少的实体可以直接在 `index.ts` 中声明类型和 APIs,避免为了形式增加空文件。

Generation 和 Task 是前端可见的业务数据。后端如何调用图像模型不属于前端模块。

## shared

`shared` 是无业务含义的公共基础层,可以在出现真实需求后承载通用 UI、Hooks、纯
工具和配置读取。它不能依赖任何上层模块,也不能保存 Entity、业务 APIs 或
Workflow 规则。当前用 `shared/README.md` 固定边界,不提前创建空子目录和占位实现。
21 changes: 21 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Windup Frontend

当前前端只提交粗架构、公开接口和必要业务类型,不包含具体业务实现、测试、页面壳或依赖安装入口。

## 目录

```text
src/
workflow-controller/ 两套制作界面共享的整体流程接口
entities/ Project、Character、WorkflowRun、Generation、Task 等业务数据
shared/ 无业务含义的公共基础层边界说明
```

Quick Start 与 Workflow Editor 使用同一种 WorkflowRun,但页面独立:Quick Start 隐藏步骤并由自动流程决策,Workflow Editor 逐步展示操作。当前没有服务端调用实现;后续按业务模块拆分小 PR 接入。

## 文件说明

- `API_CONTRACT.md`:业务 APIs 和 WorkflowController 的公开签名说明。
- `MODULES.md`:app、pages、features、workflow-controller、entities、shared 的职责边界。
- `src/shared/README.md`:公共基础层允许和禁止承载的内容。
- `../frontend-architecture-v3.md`:本次粗架构 PR 的总体设计与未冻结范围。
20 changes: 20 additions & 0 deletions frontend/src/app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# App 应用入口层

## 模块职责

`app` 只负责前端应用启动、路由挂载和全局布局。它回答的是“用户进来后先看到哪些入口、不同 URL 去哪个页面”,不回答“角色怎么生成、流程怎么推进、接口怎么调用”。

## 后续允许放入的内容

- 路由表,例如首页、Quick Start、Workflow Editor、项目详情和 Playtest 入口。
- 全局应用外壳,例如顶部导航、页面容器和全局错误边界。
- 只影响整个前端应用的 Provider,例如路由 Provider 或全局主题 Provider。

## 不允许放入的内容

- 不在这里写 Project、Character、WorkflowRun 等业务数据结构。
- 不在这里实现 Workflow 的下一步、重启、中断等业务规则。
- 不在这里直接拼服务端业务 APIs。
- 不在这里为了方便把页面内部状态提升成全局状态。

判断标准是:如果一段代码离开“应用怎么启动和怎么路由”这个问题,它就不应该放在 `app`。
25 changes: 25 additions & 0 deletions frontend/src/entities/action-template/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* ActionTemplate 实体及其公开 APIs。
*
* ActionTemplate 表示“动作模板”,用于描述可复用的动作名称与生成提示词;它与
* 角色母版 CharacterTemplate 完全不同。当前内容较少,因此遵循粗粒度原则集中在
* 一个入口文件中,不为 types/apis 额外创建空目录层级。
*/
interface ActionTemplateBase {
/** 动作模板的稳定业务标识。 */
id: string
/** 面向用户展示的动作名称,例如“行走”或“待机”。 */
name: string
/** 后端生成动作时使用的模板提示词。 */
prompt: string
}

/** 系统内置动作模板没有 Project 归属。 */
export type ActionTemplate = ActionTemplateBase &
({ scope: 'system'; projectId: null } | { scope: 'project'; projectId: string })

/** 动作模板对应的服务端 API。 */
export interface ActionTemplateAPIs {
/** 返回系统内置模板与指定项目自定义模板的可用集合。 */
listAvailable(projectId: string): Promise<ActionTemplate[]>
}
31 changes: 31 additions & 0 deletions frontend/src/entities/character/apis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Character 聚合资源对应的服务端接口集合。
*
* Character、Outfit、Action 作为一棵聚合数据更新,避免前端为尚未冻结的细粒度
* 路由提前创建多层抽象。这里只声明调用形状,不提供实现。
*/
import type {
AddActionInput,
Character,
ConfirmCharacterTemplateInput,
CreateCharacterInput,
} from './types'

/** Character 聚合数据对应的服务端 API;更新粒度以后端合同为准。 */
export interface CharacterAPIs {
/** 读取包含 Outfit 与 Action 的完整 Character。 */
get(characterId: Character['id']): Promise<Character>
/** 按 Project 归属列出角色。 */
listByProject(projectId: Character['projectId']): Promise<Character[]>
/** 创建角色基础资料;母版和动作由后续流程补充。 */
create(input: CreateCharacterInput): Promise<Character>
/** 按后端约定提交完整 Character 聚合更新。 */
update(character: Character): Promise<Character>
/** 确认某个 Outfit 的角色母版候选。 */
confirmCharacterTemplate(
characterId: Character['id'],
input: ConfirmCharacterTemplateInput,
): Promise<Character>
/** 基于动作模板或自定义提示词,为指定 Outfit 增加动作。 */
addAction(characterId: Character['id'], input: AddActionInput): Promise<Character>
}
24 changes: 24 additions & 0 deletions frontend/src/entities/character/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Character 模块的唯一公共出口。
*
* 外部模块应从此文件导入 Character 相关类型与 APIs,而不是跨目录引用内部文件。
* 这样后续调整文件布局时不会迫使所有调用方同步修改路径。
*/
export type { CharacterAPIs } from './apis'
export type {
Action,
ActionSource,
ActionStatus,
ActionType,
AddActionInput,
ActionSequence,
BaseFrame,
Character,
CharacterTemplateCandidate,
ConfirmCharacterTemplateInput,
CreateCharacterInput,
Frame,
FrameQcResult,
FrameRootMotion,
Outfit,
} from './types'
Loading