Skip to content

feat(frontend): add module boundaries and API contracts - #69

Closed
huyanxius wants to merge 84 commits into
1024XEngineer:mainfrom
huyanxius:refactor/frontend-module-skeleton
Closed

feat(frontend): add module boundaries and API contracts#69
huyanxius wants to merge 84 commits into
1024XEngineer:mainfrom
huyanxius:refactor/frontend-module-skeleton

Conversation

@huyanxius

@huyanxius huyanxius commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

前端的模块划分、依赖规则与模块接口。本 PR 只提交边界与接口,实现按模块拆成后续 PR。

结构

frontend/src/
├── app/                     启动与路由
├── entities/                业务模块
│   ├── project              项目:视角、朝向、精灵尺寸、画风
│   ├── character            角色:造型、动作、帧是它内部的一棵树
│   ├── action-template      能跨角色复用的动作配方
│   ├── generation           一次生成任务这份业务数据
│   ├── media                已上传媒体的不透明引用
│   ├── task                 后端异步步骤的状态
│   ├── workflow-run         制作流程的运行记录
│   ├── playtest-inspection  核验结论
│   └── index.ts             唯一对外入口
├── features/                角色设置 / 生成 / 审核 / 导出 / 流程推进
├── pages/                   八个路由页面
└── shared/pagination/

依赖方向 pages → features → entities → shared,只能向下,同层不互相导入。跨模块只从模块目录的 index.ts 进入。app 只做启动与路由,不构造服务、不向下注入。

每个模块一个 index.ts,不再有 model/ local/ adapters/ 这类内部分层。

模块判据

这个东西能不能被单独取到。

能单独取,说明它需要自己的一套取数逻辑,才值得一个模块;取不到的,它只是别人身上的一个字段。

按这条判据,OutfitActionFrame 没有独立模块——它们不能脱离 Character 被取到。ActionTemplate 有独立模块,因为它能被不同角色复用。

接口

每个模块暴露一组服务端接口,统一叫 XxxApis

ProjectApis  CharacterApis  ActionTemplateApis  GenerationApis
TaskApis  WorkflowRunApis  PlaytestInspectionApis

不做接口与实现的分离,实现跟着接口放在同一模块里。

流程推进

features/workflow-controller 是 Quick Start 与手动工作流共用的推进边界,不含界面。节点固定八步:

角色资料 → 角色图 → 候选选择 → 动作资料 → 首帧 → 完整动画 → 审核 → 导出

节点怎么走由前端决定,WorkflowRunApis 只负责存取运行记录。从历史节点重开会追加新 Revision,旧 Revision 保留为只读历史。

Quick Start 与手动模式共用同一份推进逻辑,区别只是前者连续调用、后者一次一步。隐藏节点不等于跳过节点——门禁写在流程模型里,不在界面里。

检查

format:checklinttypechecktestbuild 五项在 CI 通过。

与后端不一致的部分

明细见 frontend/API_CONTRACT.md。其中五处是前端预期有、后端 PR #64 目前没有的,需要后端明确做或不做

  • WorkflowRunApis(后端无 workflow 模块)
  • ActionTemplateApis(后端无 action template 模块)
  • PlaytestInspectionApis(后端无对应模块)
  • TaskApis.cancelGenerationService 无取消接口)
  • 独立的 task 模块(后端 Task 在 generation 内)

另有两处形状问题:动作生成前端两步、后端一步;Frame.qcFrame.rejected 在后端 character_data 结构里没有落点,审核结果无处保存。

本次不包含

实现代码、测试文件、图片上传模块、穿戴道具、第三方登录。页面当前是占位外壳,只声明路由与模块边界。

huyan and others added 30 commits July 27, 2026 15:02
The repository has no frontend workspace yet, so Issue 1024XEngineer#58 needs a buildable base before any module code can land.

Add the Vite + React + TypeScript project with Tailwind, oxlint and Vitest configuration, the @/ path alias, and a dev proxy forwarding /api to the local backend on port 8000.

The workspace now builds, type-checks and runs tests, giving later commits somewhere to put shared, entities and page code.
Business code needs one way to reach the backend that works both before and after the API exists, without touching call sites when switching.

Add shared/api with real fetch client, mock handlers and response mappers behind a single request surface, plus the async-state hook, PageHeader component and test helpers.

Entities can now read and write data through one entry point, and the mock and real implementations stay interchangeable via VITE_USE_MOCK.
Every business module depends on the data layer, so its exports have to be fixed before page or feature code can be written against them.

Add the entities module with project, character, workflow-run, action-template and wearable slices behind a single index, including workflow selectors and local persistence while the backend does not store workflows yet.

The backend can now read one file to see which endpoints and fields are expected, and callers keep the same signatures once the API takes over.
Issue 1024XEngineer#58 requires the module boundaries named in MODULES.md to exist as real code with declared interfaces, not just as directories.

Add the workflow editor and inspection preview page modules with explicit props and no Router dependency, four feature slices, the routing shell, a global error boundary and a not-found route.

Quick start now creates a run and the editor loads it by the same runId, and each page module can be rendered and tested outside the router.
Layer rules and module entries are only real if something fails when they are broken; manual grep review misses export-from and dynamic imports.

Add unit tests for workflow selectors, mock contract and the error boundary, plus integration tests that parse every import with the TypeScript AST to enforce layering, slice isolation, module entries and cycle freedom.

Twenty-nine tests now guard the architecture, and violations such as deep cross-slice imports or page-to-page references fail the suite.
The 07-24 review noted that a layered directory tree does not by itself show which modules were chosen or why, and readers cannot tell settled contracts from proposals.

Add MODULES.md declaring four module boundaries with their entries, responsibilities, explicit non-responsibilities and unfrozen items, and a README covering setup, layering and the state of every backend contract.

Reviewers can now see the module list, what each one refuses to own, and which interfaces still need a joint frontend-backend walkthrough.
The submit call ignored its command argument, so add-action never appended anything and the two entry points could not share one advance path.

Take a command instead of a step id, guard it against availableCommands, append paired action steps, and derive status from remaining work rather than hardcoding running.

AI suggestions and manual clicks now advance the same run through one interface, and a run with no pending step is no longer reported as running.
Quick Start navigated to the workflow editor after creating a run, turning two parallel entry points into a chain and defeating the purpose of the AI shortcut.

Drive the run in place with suggestNextCommand and submitWorkflowStep under a step ceiling, subscribe by runId instead of holding a snapshot, and surface the run even when advancing fails.

The AI entry now completes a whole workflow without leaving the page, and both entries are proven to share one command interface.
Nothing failed when Quick Start navigated away, because no test rendered the router or checked the resulting location.

Render the whole App, run the AI flow to completion and assert the pathname stays at the root with no workflow editor heading present.

A future reintroduction of the navigation call now breaks the suite instead of passing silently.
Both documents still described Quick Start as the way into the workflow editor, and the module contract implied a single entry chain.

Rewrite the entry description so the AI page and the manual editor are parallel, and note that reject-frame does not yet create rework steps.

Readers and reviewers now see two independent entries sharing one workflow boundary, with the remaining gap stated instead of implied.
Replace the parallel shortcut flow with a unified WorkflowRun revision model, strict five-node execution, history, quality gates, and non-blocking Playtest import. Preserve backend and provider boundaries without fabricated success states.
Workflow rules lived in entities and wrote straight to localStorage, so the frontend owned a state machine that belongs to the server.

Add a mock workflow-run backend holding the DTO shape, storage, node advancement, quality gate and restart-revision logic, exposed over create, fetch and command routes, and register it in the mock dispatcher.

Validation and state transitions now sit behind a network call; dropping the directory is all it takes once the real API lands.
createWorkflowRun, fetchWorkflowRun and submitWorkflowCommand each carried their own persistence and rule checks.

Reduce them to request() calls with DTO translation, add the mapper module, and delete the local store.

The public interface is unchanged, so pages and features keep compiling untouched.
The AI entry navigated to the workflow editor as soon as a run was created, which contradicts the agreed flow where the two entries never hand off to each other.

Render the run status and generation panel inline, and offer the editor as a link the user chooses to follow.

The route stays at /quick-start after submission; the flow test asserts that again.
The adapters README still described a localStorage adapter owned by entities.

Point it at the mock backend that now stands in for the server.

The directory keeps its placeholder role for real backend differences.
Keep AI-assisted creation in a focused route while sharing the existing workflow state underneath.
Document the public API facade, real route coverage, and the current Quick Start completion limits.
Keep the architecture status aligned with the current API boundary implementation.
Include the existing editor component and its interaction tests in the architecture tree.
Expose current API contract status and reject files beyond the backend upload limit locally.
明确公开契约的字段归属、单位、空值语义及前后端边界。
统一 ActionTemplate、characterTemplate 和 baseFrames 术语,并同步公开契约与架构文档。
The add-action input typed kind and actionTemplateId independently, so a caller could declare a preset action and leave out the template it was supposed to use. Nothing rejected that combination.

Turn the input into a named discriminated union: the preset branch carries actionTemplateId, the custom branch carries none. Export AddActionInput from the entities facade so the shape is part of the public contract.

The contradictory combination no longer type-checks.
…r one

Two fields hold an uploaded image and both read like "the reference picture", which invites callers to reach for the wrong one.

Say that sampleImageUrl constrains the visual style of every character in the project, and point at CreateCharacterInput.referenceImageUrl for the per-character image.

Readers can tell the two layers apart without tracing call sites.
huyan and others added 14 commits July 29, 2026 16:25
Preview and production builds must select different project adapters.

Cover the preview environment and clear its flag in the production case.

The test guards demo availability without allowing mocks into production.
Pull requests need a deployable frontend artifact with stable client-side routes.

Add Vite build settings, an SPA rewrite, and ignore local Vercel metadata.

Vercel can publish review links without committing account data or tokens.
Reviewers need the environment boundary and hosting setup recorded near the frontend.

Document the Preview composition, root directory, and required environment flag.

The setup stays reproducible while production remains free of demo data.
Quick Start service types are consumed only by the route page.

Move the contract into the page model and export it through the page entry.

This removes the duplicate ownership signal without changing behavior.
App composition referenced a page-only contract through the Feature layer.

Point service typing at the page entry and remove the old Feature contract.

Quick Start now has one explicit module owner.
The contract test still lived under the removed Feature slice.

Relocate it beside the page service and update the declared slice registry.

The same control boundary remains enforced at its new owner.
The URL can change before React renders the destination page.

Wait for the session heading with the existing asynchronous query.

This removes timing sensitivity without altering product behavior.
The module inventory still described Quick Start as both a Page and a Feature.

Record the page-owned service contract and remove the duplicate Feature entry.

The documented ownership now matches the enforced directory boundary.
Consumer documentation still named the removed Feature-layer port.

Use the QuickStartService name in composition and control-boundary examples.

Readers now see the same contract name exposed by the page module.
The 2026-07-30 review asked this pull request to carry module boundaries only, so test files are out of scope for it.

Delete the 19 colocated test files together with the shared tests directory holding the architecture and end-to-end placeholders.

Coverage returns per module in the follow-up pull requests that add the implementations.
Vitest exits with code 1 when it finds no test files, which turns the pipeline red now that the suite is gone.

Add the passWithNoTests flag to the test script.

The five pipeline steps pass again on a skeleton that carries no tests.
The review found the interface and implementation split unnecessary at this size, and the nested sub-module directories too fine-grained.

Delete the composition, capabilities and application layers, rename Repository and Port to Apis, merge the three application slices into features/workflow-controller, and reduce every module to one index file.

Source drops from 79 files and 4793 lines to 28 files and 891 lines.
The existing documents described the layers and naming this branch just removed, and referenced them over a hundred times.

Rewrite the architecture document and README against the current structure, replace API_CONTRACT with a per-item comparison against backend pull request 64, and delete the superseded MODULES document.

The comparison records five interfaces the frontend expects that the backend does not currently provide.
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

@huyanxius is attempting to deploy a commit to the huyan's projects Team on Vercel.

A member of the Team first needs to authorize it.

@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
windup Ignored Ignored Preview Jul 30, 2026 5:02am

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

发现 2 个需要修正的接口/文档一致性问题,具体见行内评论。

验证通过:format:checklinttypechecktestbuild,以及生产依赖 npm audit --omit=dev --audit-level=high

)

/** 前端编排关联;后端 Task 不需要认识 WorkflowRun、Revision 或页面节点。 */
export interface WorkflowTaskLink {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 为 WorkflowTaskLink 提供持久化入口。当前这个关联类型既不属于 WorkflowRun 快照,也没有任何 Apis 方法负责保存或查询它。GenerationApis.create() 返回任务后,controller 因而无法按公开契约持久化 taskId -> run/revision/node 的映射;页面刷新后即使通过 TaskApis 恢复任务,也无法确定结果应回填到哪个节点。请将 links 纳入运行快照,或增加明确的读写接口。


**Goal:** Reorganize the complete frontend module tree by responsibility, remove transport-level business mocks and cross-entity leakage, and enforce the resulting ownership rules in tests.

**Architecture:** Add a `capabilities` layer between features and entities for computation and upload ports. Keep entity lifecycle access in repositories, inject the Project repository from app composition, and leave shared as business-agnostic transport and utilities. Page and Feature public behavior stays the same.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 不要把已废弃架构作为仍可执行的计划提交。这里要求新增 capabilities、Repository、app composition 和多层内部目录,正好与本 PR 的新架构(删除这些层并收敛为单文件模块)相反,而且文档还明确指示 agentic workers 按步骤执行。后续维护者可能据此重新引入本 PR 刚删除的结构;请删除这些旧计划,或在文件开头明确标记整份计划已废弃并链接到当前架构。

The eight plan and spec documents describe the capability and orchestration layers this skeleton no longer has, and each one opens by marking itself historical.

Delete the superpowers plans and specs directory.

The pull request drops 2329 lines that would otherwise contradict the current structure.
@huyanxius huyanxius changed the title refactor(frontend): 精简为模块骨架,只提交划分与接口 feat(frontend): add module boundaries and API contracts Jul 30, 2026
The team and the review both refer to this concept as step data, while the code called it a node.

Rename WorkflowNode and its status, type and order companions to the step wording, and widen the controller to own step updates, server result write-back and interruption.

Naming now matches how the flow is discussed, and every operation that touches step data sits behind one interface.
The backend project service exposes an update path that the frontend interface did not declare.

Add UpdateProjectInput and the update method to ProjectApis.

Project settings can be changed after creation instead of only on create.
The backend generation service offers submission and lookup only, so a frontend cancel method would promise something no endpoint backs.

Remove cancel from TaskApis and note the reason on the interface.

The interface no longer claims capability the server side has not agreed to.
The frontend does not call an image generation capability; it creates a generation and then follows its state, which the previous shape did not express.

Add the Generation snapshot with its own id and status, and give GenerationApis both create and get.

The module now matches how the server exposes generation, and the typed per-kind results are kept.
Adding an action is expressed as a character update, so the dedicated input type had no consumer left.

Remove AddActionInput and the action template import it required.

The module carries no type without a caller.
The layer had no written rule, which is how business types drift into it.

Add a README with the admission test, the currently allowed directories and an explicit exclusion list.

Anything needing Windup business vocabulary is now out of bounds by a stated rule.
Both documents still described flow nodes and listed a cancel api the interface no longer declares.

Update the step wording, record that the controller owns every step operation, and drop the resolved cancel row from the comparison.

The documents match the interfaces they describe.
@huyanxius

Copy link
Copy Markdown
Collaborator Author

#70 取代。内容完全一致,区别只在提交历史:本 PR 的 84 个 commit 是迭代过程,#70 从 main 最新提交重起、压成 10 条原子提交。

@huyanxius huyanxius closed this Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants