feat(frontend): add module boundaries and API contracts - #69
Closed
huyanxius wants to merge 84 commits into
Closed
Conversation
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.
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.
|
@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. |
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
| ) | ||
|
|
||
| /** 前端编排关联;后端 Task 不需要认识 WorkflowRun、Revision 或页面节点。 */ | ||
| export interface WorkflowTaskLink { |
Contributor
There was a problem hiding this comment.
[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. |
Contributor
There was a problem hiding this comment.
[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.
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.
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
前端的模块划分、依赖规则与模块接口。本 PR 只提交边界与接口,实现按模块拆成后续 PR。
结构
依赖方向
pages → features → entities → shared,只能向下,同层不互相导入。跨模块只从模块目录的index.ts进入。app只做启动与路由,不构造服务、不向下注入。每个模块一个
index.ts,不再有model/local/adapters/这类内部分层。模块判据
这个东西能不能被单独取到。
能单独取,说明它需要自己的一套取数逻辑,才值得一个模块;取不到的,它只是别人身上的一个字段。
按这条判据,
Outfit、Action、Frame没有独立模块——它们不能脱离Character被取到。ActionTemplate有独立模块,因为它能被不同角色复用。接口
每个模块暴露一组服务端接口,统一叫
XxxApis:不做接口与实现的分离,实现跟着接口放在同一模块里。
流程推进
features/workflow-controller是 Quick Start 与手动工作流共用的推进边界,不含界面。节点固定八步:节点怎么走由前端决定,
WorkflowRunApis只负责存取运行记录。从历史节点重开会追加新 Revision,旧 Revision 保留为只读历史。Quick Start 与手动模式共用同一份推进逻辑,区别只是前者连续调用、后者一次一步。隐藏节点不等于跳过节点——门禁写在流程模型里,不在界面里。
检查
format:check、lint、typecheck、test、build五项在 CI 通过。与后端不一致的部分
明细见
frontend/API_CONTRACT.md。其中五处是前端预期有、后端 PR #64 目前没有的,需要后端明确做或不做:WorkflowRunApis(后端无 workflow 模块)ActionTemplateApis(后端无 action template 模块)PlaytestInspectionApis(后端无对应模块)TaskApis.cancel(GenerationService无取消接口)task模块(后端 Task 在 generation 内)另有两处形状问题:动作生成前端两步、后端一步;
Frame.qc与Frame.rejected在后端character_data结构里没有落点,审核结果无处保存。本次不包含
实现代码、测试文件、图片上传模块、穿戴道具、第三方登录。页面当前是占位外壳,只声明路由与模块边界。