Skip to content

refactor(frontend): consolidate workflow architecture and Playtest - #73

Closed
xyh202131 wants to merge 52 commits into
mainfrom
feat/playtest-on-module-skeleton
Closed

refactor(frontend): consolidate workflow architecture and Playtest#73
xyh202131 wants to merge 52 commits into
mainfrom
feat/playtest-on-module-skeleton

Conversation

@xyh202131

@xyh202131 xyh202131 commented Jul 30, 2026

Copy link
Copy Markdown

说明

本 PR 在现有 Playtest 与 WorkflowRun 基础上完成前端骨架整合,保留 Project、Character Assets、Creation Workflow、Generation Execution、Review and Publishing、Playtest and Delivery 六个业务模块,并接入仓库现有真实后端接口。

主要改动

  • Quick Start 与 Workflow Editor 共用同一个 WorkflowControllerWorkflowRunStore
  • 合并重复的 Task、Generation、adapter 和页面私有工作流状态。
  • 将 Project、Character、Generation、Media 的 DTO 转换归入对应 Entity API。
  • 动作生成保存完整动画帧,支持任务订阅、中断、刷新恢复和旧存储迁移。
  • 审核状态落盘后才发布 Character;发布失败可重试,未审核资产不会进入资产库。
  • 补齐项目列表、项目创建、项目详情、资产库和历史记录页面。
  • Playtest 保持独立只读核验台;下载包能力迁入 features/export-package
  • 增加模块边界、API 合同、恢复时序和发布行为测试。
  • 使用仓库 oxfmt 统一格式化整个 frontend。

验证

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm test:34 个测试文件、196 个测试通过
  • npm run build
  • 真实后端项目、资产库、工作流恢复和 16 帧 Playtest 浏览器验证通过

huyanxius and others added 30 commits July 30, 2026 15:33
The MS2 frontend needs a reproducible workspace before any module code can land.

Add the Vite entry, the pinned dependency manifest and lockfile, the three referenced TypeScript configs, and the ignore rules.

The workspace installs and builds from a clean checkout.
Style and lint rules should be fixed before contributors start writing modules.

Add the oxlint rule set and the oxfmt formatting profile for the frontend workspace.

Formatting and lint results are identical on every machine and in CI.
The skeleton carries no test suite yet, but the test runner has to be wired for later work.

Add the vitest config so it resolves the same path aliases as the application build.

Tests can be added to any module without further setup.
Every upper layer needs a place for cross-module primitives that belong to no single domain.

Add the shared layer with its pagination contract and a README stating what may live here.

Modules have one agreed home for shared primitives instead of duplicating them.
The frontend has to state which business objects it owns and how each one is reached.

Add one contract file per entity for character, project, task, generation, media, action template, playtest inspection and workflow run, plus the aggregate export.

Upper layers depend on declared entity interfaces rather than on transport details.
The workflow steps the mentor reviewed need an explicit home separate from both entities and pages.

Add contracts for character setup, generation, review, export and the workflow controller.

Each use case has a named boundary that pages call instead of reaching into entities.
Routing targets have to exist before the application shell can wire them together.

Add the home, projects, project detail, quick start, workflow editor, asset library, playtest and not found page modules.

Every route in the product design maps to exactly one page module.
The page modules need a composition root that owns routing and layout.

Add the app shell with its layout and route table, the browser entry point, and the base stylesheet.

The application runs end to end and every page is reachable.
Reviewers need the branch checked automatically and a running preview to look at.

Add the frontend workflow running lint, typecheck, test and build, and scope Vercel previews to frontend changes.

Every pull request reports its own build status and preview URL.
The module boundaries and the interfaces expected from the backend must be reviewable without reading the code.

Add the architecture document, the frontend README, and the API contract listing every endpoint the frontend calls.

Backend and frontend can align on one written list of interfaces.
A run reopened after a refresh could not tell that a generation was still running, so the page had to either resubmit it or stall.

Record the in-flight task id on WorkflowStep so it is saved with the run, and drop WorkflowTaskLink, which no structure ever held.

Reopening a run recovers the pending task from its step instead of starting a second generation.
The vitest config sat outside every tsconfig include, so a type error in it would only surface when the runner started.

Add it to the node project alongside the vite config.

Both build-side configs are now covered by tsc -b.
A character is written when the user exports to the asset library, so it cannot hold work-in-progress state; the backend also returns no QC verdict and the product has no per-frame reject.

Drop the action generation status, the frame qc and rejected fields, and the standalone playtest inspection entity; review now only reads frames.

The asset tree describes confirmed assets only, and review results no longer need a second home.
Three structures carried assumptions a reader could not distinguish from settled decisions.

State that multi-direction frame storage is undefined, that the MVP runs a single revision, and that an action id is unique only inside its outfit.

Open questions are visible in the contracts instead of being rediscovered later.
The reduced module skeleton no longer includes playtest inspection or shared UI.

Remove obsolete API and entity references and align the layout comment with app ownership.

Documentation now matches the contracts and directories present in this branch.
The backend character contract has no standalone name field.

Remove name from Character and CreateCharacterInput.

The frontend now matches the confirmed character payload boundary.
The fixed workflow is not a backend resource.

Remove WorkflowRunApis and update the public and controller contracts.

Backend responsibilities now stop at generation and confirmed asset storage.
The API notes still described stale workflow and generation assumptions.

Document frontend-owned workflow state, generation mapping, and assigned follow-ups.

The architecture now reflects the latest backend reference and team decisions.
The backend scopes generation-task queries by both project and task identifiers.

Add projectId to generation reads and task reads and subscriptions.

Callers can now map directly to the documented task query endpoint.
Task lookup ownership is now confirmed against the backend API.

Mark projectId plus taskId as resolved and remove the stale mismatch and question.

Reviewers can see the current task query boundary without reopening the decision.
Workflow execution needs a stable boundary between generation records and backend tasks.

Parse character-template results and bind generation IDs to task IDs.

Require subscriptions to replay a current snapshot before later updates.
Workflow execution needs a frontend-owned snapshot that can survive page refreshes.

Add the fixed step model, versioned local storage, and runtime hydration validation.

Keep memory authoritative when persistence fails or stored data is invalid.
Quick Start and the editor need one frontend-owned progression boundary.

Add character setup updates, generation submission, task recovery, and interruption handling.

Advance valid results to candidate selection without exposing unfinished steps.
Workflow state and async recovery need regression coverage before page integration.

Test persistence, submission deduplication, task replay, and interruption races.

Verify the first generation slice through the real store and controller.
The skeleton documentation no longer reflects the implemented workflow slice.

Record controller scope, recovery behavior, task replay, and local persistence limits.

Keep editor, Quick Start automation, and later steps explicitly out of scope.
The workflow controller mixed process coordination, state transitions, and asynchronous task recovery in one file.

Extract pure WorkflowRun transitions and the character-template task lifecycle behind the existing controller facade.

Keep the public API and runtime behavior unchanged while making later workflow steps easier to add.
The new pure state boundary needs direct regression coverage alongside the existing controller tests.

Cover fixed workflow creation, character setup normalization, and activation of the character-template step.

Protect the extracted rules without changing production behavior.
The Character Setup feature exposed the asset creation DTO while the workflow controller expects step-local input.

Change the submit callback to accept CharacterSetupStepInput.

Allow Quick Start and Workflow Editor to connect without translating through an unrelated asset contract.
The Character Setup boundary previously drifted to an unrelated asset DTO.

Add a type assertion for the submit callback parameter.

Prevent the page-to-workflow contract from regressing.
- A/D keys now continue the currently selected action instead of
  forcing a switch to walk; mirror direction only set for walk actions
- BFS flood fill uses pre-allocated Int32Array queue instead of dynamic
  array, eliminating GC pressure on large sprites
- Largest component size tracked during BFS, removing Math.max+map
- Fingerprint calculation merged into single pass over subject pixels
  instead of iterating all bounding box pixels first
- Canvas element reused across frame reads via module-level singleton
- Quality policy extracts hardcoded 256px thresholds into adaptive
  scale-aware policy derived from the sequence's own canvas baseline
- README updated to reflect new A/D behavior
huyanxius and others added 3 commits July 31, 2026 07:31
Quick Start needs to drive the frontend WorkflowRun without entering the editor.

Add the page UI and an injectable service that prepares a project and delegates execution to WorkflowController.

Unconfigured production wiring now fails explicitly instead of falling back to fake data.
Quick Start needs regression coverage across its page and controller boundary.

Exercise the real WorkflowRun store and WorkflowController with only external ports substituted.

Lock same-page execution, failure persistence, unexpected errors, and candidate delivery.
…, Generation, Media

- http-client.ts: shared fetch wrapper with baseURL, JSON envelope
  parsing, and typed error handling
- project.ts: ProjectApis adapter with snake_case↔camelCase mapping,
  perspective (1/2/3) and movement (1/2/3) enum conversion
- character.ts: CharacterApis adapter mapping nested character_data
  outfits/actions/frames to flat frontend Character entity, with
  sensible defaults for backend-missing fields (rootMotion, kind,
  keyFrameIndex)
- task.ts: TaskApis adapter with 2s polling fallback for subscribe()
  since backend has no WebSocket/SSE push
- generation.ts: GenerationApis adapter routing character_template to
  POST /generation/image and first_frame/complete_animation to
  POST /generation/action
- media.ts: MediaApis adapter for POST /media/upload with FormData
- index.ts: unified re-export entry point

All adapters conform to existing entity interfaces (ProjectApis,
CharacterApis, GenerationApis, TaskApis) and are page-agnostic.
The article element for each node was missing an onClick binding,
so clicking a node never called onNodeSelect — the inspector panel
was permanently stuck on the initial master-gen node.
Align workflow editor with the asset-lab skeleton studio:

- Add studio bar with brand, project info, mode selector, and actions
- Add studio mode chooser (workflow vs natural creation)
- Update node canvas to match asset-lab's paper-like design language
- Add drag-to-connect from output ports (not just click)
- Add armed link state for pending connections
- Add node-canvas-hint bottom bar with contextual instructions
- Add node-zoom controls with reset button
- Add custom-action node type (06+ · CUSTOM)
- Add description field to each node
- Update node styling to match asset-lab's card design
- Update connection visualization (solid for connected, dashed for suggested)
- Update color palette to match asset-lab (--workspace-white, --ink, --muted, etc.)
- Update inspection panel to match asset-lab's inspector design
- Fix node click handler to properly update activeNode
The workflow editor was using custom CSS classes (studio-bar, node-canvas,
node-card, etc.) but had no CSS file defining these styles, causing the
page to render as unstyled content.

- Add workflow-editor.css with styles ported from asset-lab/workflow-shell.css
- Import CSS in index.tsx
- Match asset-lab's paper-like design (--wf-white, --wf-ink, --wf-muted)
- Style studio bar, node canvas, node cards, ports, hint bar, zoom controls
- Style inspection panel with overline typography
- Add responsive breakpoint for mobile (hide sidebar)
- Copy workflow-shell.css from asset-lab instead of custom CSS
- Use exact class names: graph-node, graph-port, node-status, studio-bar,
  studio-mode-gateway, studio-mode-card, node-graph-workspace, etc.
- Remove AI 智能生成 (natural creation) mode option
- Match asset-lab's HTML structure for nodes, ports, and status indicators
- Use asset-lab's overline typography and design tokens
…as-workspace

CSS selector .production-canvas-workspace:has(> .studio-mode-gateway) requires
studio-mode-gateway to be a direct child of production-canvas-workspace.
Move it inside and add the footer note element.
@xyh202131 xyh202131 closed this Jul 31, 2026
@xyh202131
xyh202131 deleted the feat/playtest-on-module-skeleton branch July 31, 2026 03:23
@xyh202131
xyh202131 restored the feat/playtest-on-module-skeleton branch July 31, 2026 03:37
@xyh202131 xyh202131 reopened this Jul 31, 2026

@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.

The current head has blocking build/test failures and several integration regressions; concrete findings are attached inline.

Validation: npm run format:check fails on 8 files; npm run typecheck and npm run build fail with TypeScript errors; npm test -- --maxWorkers=2 reports 2 failures (159 passing). npm run lint completes with 2 warnings.

View job run

Comment thread frontend/src/app/app.tsx Outdated
<Route path="/workflow-editor/:runId" element={<WorkflowEditorPage />} />
<Route path="/workflow-editor/:runId/:stage" element={<WorkflowEditorPage />} />
<Route path="/playtest/demo" element={<PlaytestDemoPage />} />
<Route path="/playtest/:characterId/:outfitId" element={<PlaytestPage />} />

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] Wire the production character adapter into this route. PlaytestPage treats an omitted apis prop as an error, so every visit to /playtest/:characterId/:outfitId currently renders “Playtest 角色接口尚未配置” and never loads the requested character. The newly added createCharacterApis() is not used anywhere else in the application.

Comment thread frontend/src/app/adapters/generation.ts Outdated
return {
id: String(raw.id),
projectId: String(raw.project_id),
type: raw.task_type as T,

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] Translate backend task types instead of only casting them. /generation/image returns task_type: "character_image", so this object exposes that runtime value even when typed as Generation<'character_template'>. character-template-task.ts then rejects it because generation.type !== 'character_template', causing every real character-template submission to fail immediately. Reuse the mapping already present in task.ts.

Comment thread frontend/src/app/adapters/generation.ts Outdated

const GENERATION_ENDPOINTS: Record<string, string> = {
character_template: '/generation/image',
first_frame: '/generation/action',

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] Route first_frame through the image-generation endpoint. The checked-in API contract explicitly maps first_frame to POST /generation/image with the confirmed character image as reference; sending this payload to /generation/action uses the wrong request schema and backend task type, so first-frame generation cannot work as documented.


export class ApiError extends Error {
constructor(
public readonly status: number,

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] Avoid constructor parameter properties under this repository's TypeScript settings. tsconfig.app.json enables erasableSyntaxOnly, and these public readonly parameters trigger TS1294, which makes both npm run typecheck and npm run build fail. Declare the fields separately and assign them in the constructor.

Comment thread frontend/src/app/adapters/character.ts Outdated
Outfit,
} from '@/entities'

import { del, get, patch, post } from './http-client'

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] Remove the unused del import. noUnusedLocals is enabled, so TS6133 here blocks npm run typecheck and npm run build on the current head.

[],
)

const handleWheel = useCallback((event: ReactWheelEvent) => {

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] Import/use React's wheel-event type and a JSX element type that is available with this TS configuration. ReactWheelEvent is undefined here and JSX.Element at line 126 has no namespace in scope, producing TS2552/TS2503 and preventing the frontend build.


function getSharedContext(width: number, height: number): CanvasRenderingContext2D | null {
if (sharedCanvas === null) {
sharedCanvas = document.createElement('canvas')

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] Reset or recreate the shared canvas for each image before reading pixels. If one remote image taints this canvas, getImageData throws and the same-size canvas remains tainted for subsequent frames because width/height are not reassigned; later valid frames are then all reported as cross-origin failures. The module-level cached context also causes the two new image-geometry tests to reuse stale mocked contexts and fail.

Unify Quick Start and Workflow Editor around one controller, move transport and export behavior into stable entity and feature boundaries, and preserve complete animation results through review and publishing. Add real project and asset pages, recovery coverage, architecture guards, documentation, and repository-wide frontend formatting.\n\nCo-Authored-By: Codex <codex@openai.com>
@xyh202131 xyh202131 changed the title feat(frontend): integrate Playtest with module skeleton refactor(frontend): consolidate workflow architecture and Playtest Aug 2, 2026
Keep the integrated frontend pages and workflow controller while syncing the backend skeleton and CI from main. Remove the superseded action-template model and preserve the architecture boundary checks.
@xyh202131

Copy link
Copy Markdown
Author

按提交者要求暂时关闭;未合入 main,保留分支供后续重新整理。

@xyh202131 xyh202131 closed this Aug 3, 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