feat: bootstrap auto virtual tryon admin frontend
This commit is contained in:
@@ -0,0 +1,592 @@
|
||||
# Auto Virtual Tryon Admin Frontend Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Build a standalone Next.js admin console with a shared dashboard shell, a BFF data layer, four real-integration pages backed by `auto-virtual-tryon`, and honest placeholder modules for unsupported backend capabilities.
|
||||
|
||||
**Architecture:** Manually scaffold a Next.js App Router app in this existing non-empty directory instead of using `create-next-app`. Route all UI data access through a Next.js BFF layer in `app/api/*`, with adapters normalizing both proxied FastAPI responses and mock placeholder data into stable frontend view models. Keep operational pages focused: submit, review, order detail, and workflow detail do the real work; home, library, login, and settings pages preserve information architecture without pretending backend capabilities already exist.
|
||||
|
||||
**Tech Stack:** Next.js App Router, React, TypeScript, Tailwind CSS, Zod, Vitest, React Testing Library, jsdom, Lucide React
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Bootstrap The Next.js Workspace
|
||||
|
||||
**Files:**
|
||||
- Create: `package.json`
|
||||
- Create: `tsconfig.json`
|
||||
- Create: `next.config.ts`
|
||||
- Create: `next-env.d.ts`
|
||||
- Create: `postcss.config.mjs`
|
||||
- Create: `eslint.config.mjs`
|
||||
- Create: `vitest.config.ts`
|
||||
- Create: `vitest.setup.ts`
|
||||
- Create: `app/layout.tsx`
|
||||
- Create: `app/page.tsx`
|
||||
- Create: `app/globals.css`
|
||||
- Create: `app/(dashboard)/layout.tsx`
|
||||
- Create: `src/components/layout/dashboard-shell.tsx`
|
||||
- Create: `src/components/layout/nav-config.ts`
|
||||
- Test: `tests/ui/dashboard-shell.test.tsx`
|
||||
|
||||
- [ ] **Step 1: Create the package and toolchain files for a manual scaffold**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "auto-virtual-tryon-frontend",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "eslint .",
|
||||
"test": "vitest"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Install runtime and test dependencies**
|
||||
|
||||
Run: `npm install next@latest react@latest react-dom@latest zod clsx tailwind-merge lucide-react && npm install -D typescript @types/node @types/react @types/react-dom eslint eslint-config-next postcss tailwindcss @tailwindcss/postcss vitest vite @vitejs/plugin-react vite-tsconfig-paths jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom`
|
||||
Expected: install completes with `added` packages and no missing peer dependency errors
|
||||
|
||||
- [ ] **Step 3: Write the first failing shell smoke test**
|
||||
|
||||
```tsx
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { DashboardShell } from "@/components/layout/dashboard-shell";
|
||||
|
||||
test("renders the primary dashboard navigation", () => {
|
||||
render(<DashboardShell>content</DashboardShell>);
|
||||
|
||||
expect(screen.getByText("订单总览")).toBeInTheDocument();
|
||||
expect(screen.getByText("提单工作台")).toBeInTheDocument();
|
||||
expect(screen.getByText("审核工作台")).toBeInTheDocument();
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run the shell smoke test to verify it fails**
|
||||
|
||||
Run: `npm run test -- tests/ui/dashboard-shell.test.tsx`
|
||||
Expected: FAIL with a module-not-found error for `@/components/layout/dashboard-shell` or a missing test environment configuration
|
||||
|
||||
- [ ] **Step 5: Add the minimal app shell and root redirect**
|
||||
|
||||
```tsx
|
||||
// app/page.tsx
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function HomePage() {
|
||||
redirect("/orders");
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Re-run the shell smoke test to verify it passes**
|
||||
|
||||
Run: `npm run test -- tests/ui/dashboard-shell.test.tsx`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 7: Start the dev server for a compile smoke check**
|
||||
|
||||
Run: `npm run dev`
|
||||
Expected: Next.js starts and serves `http://localhost:3000`
|
||||
|
||||
- [ ] **Step 8: Commit the bootstrap if this directory is a git repo**
|
||||
|
||||
```bash
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
git add package.json tsconfig.json next.config.ts next-env.d.ts postcss.config.mjs eslint.config.mjs vitest.config.ts vitest.setup.ts app src tests
|
||||
git commit -m "feat: bootstrap next admin frontend"
|
||||
fi
|
||||
```
|
||||
|
||||
### Task 2: Define Shared Types, Status Maps, And Adapters
|
||||
|
||||
**Files:**
|
||||
- Create: `src/lib/types/backend.ts`
|
||||
- Create: `src/lib/types/view-models.ts`
|
||||
- Create: `src/lib/types/status.ts`
|
||||
- Create: `src/lib/adapters/orders.ts`
|
||||
- Create: `src/lib/adapters/reviews.ts`
|
||||
- Create: `src/lib/adapters/workflows.ts`
|
||||
- Create: `src/lib/mock/orders.ts`
|
||||
- Create: `src/lib/mock/libraries.ts`
|
||||
- Create: `src/lib/mock/workflows.ts`
|
||||
- Test: `tests/lib/adapters/orders.test.ts`
|
||||
- Test: `tests/lib/adapters/reviews.test.ts`
|
||||
- Test: `tests/lib/adapters/workflows.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write failing adapter tests for business-empty and mock states**
|
||||
|
||||
```ts
|
||||
import { adaptOrderDetail } from "@/lib/adapters/orders";
|
||||
|
||||
test("marks mock asset uris as mock previews", () => {
|
||||
const viewModel = adaptOrderDetail({
|
||||
order_id: 1,
|
||||
final_asset: { id: 10, uri: "mock://result-10", asset_type: "image", step_name: "export", metadata_json: null, created_at: "2026-03-27T00:00:00Z", order_id: 1, parent_asset_id: null, root_asset_id: null, version_no: 1, is_current_version: true },
|
||||
} as any);
|
||||
|
||||
expect(viewModel.finalAsset?.isMock).toBe(true);
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the adapter tests to verify they fail**
|
||||
|
||||
Run: `npm run test -- tests/lib/adapters/orders.test.ts tests/lib/adapters/reviews.test.ts tests/lib/adapters/workflows.test.ts`
|
||||
Expected: FAIL with missing adapter module exports
|
||||
|
||||
- [ ] **Step 3: Implement backend DTO types, frontend view models, and adapter functions**
|
||||
|
||||
```ts
|
||||
export type AssetViewModel = {
|
||||
id: number;
|
||||
uri: string;
|
||||
label: string;
|
||||
isMock: boolean;
|
||||
};
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Add shared status labels and badge variants**
|
||||
|
||||
```ts
|
||||
export const ORDER_STATUS_META = {
|
||||
created: { label: "已创建", tone: "neutral" },
|
||||
running: { label: "处理中", tone: "info" },
|
||||
waiting_review: { label: "待审核", tone: "warning" },
|
||||
succeeded: { label: "已完成", tone: "success" },
|
||||
failed: { label: "失败", tone: "danger" },
|
||||
} as const;
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Re-run the adapter tests to verify they pass**
|
||||
|
||||
Run: `npm run test -- tests/lib/adapters/orders.test.ts tests/lib/adapters/reviews.test.ts tests/lib/adapters/workflows.test.ts`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 6: Commit the shared model layer if git is available**
|
||||
|
||||
```bash
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
git add src/lib tests/lib
|
||||
git commit -m "feat: add frontend view models and adapters"
|
||||
fi
|
||||
```
|
||||
|
||||
### Task 3: Build The BFF Layer For Real And Placeholder Data
|
||||
|
||||
**Files:**
|
||||
- Create: `src/lib/env.ts`
|
||||
- Create: `src/lib/http/backend-client.ts`
|
||||
- Create: `src/lib/http/response.ts`
|
||||
- Create: `src/lib/validation/create-order.ts`
|
||||
- Create: `src/lib/validation/review-action.ts`
|
||||
- Create: `app/api/orders/route.ts`
|
||||
- Create: `app/api/orders/[orderId]/route.ts`
|
||||
- Create: `app/api/orders/[orderId]/assets/route.ts`
|
||||
- Create: `app/api/reviews/pending/route.ts`
|
||||
- Create: `app/api/reviews/[orderId]/submit/route.ts`
|
||||
- Create: `app/api/workflows/[orderId]/route.ts`
|
||||
- Create: `app/api/dashboard/orders-overview/route.ts`
|
||||
- Create: `app/api/dashboard/workflow-lookup/route.ts`
|
||||
- Create: `app/api/libraries/[libraryType]/route.ts`
|
||||
- Test: `tests/app/api/orders-create.route.test.ts`
|
||||
- Test: `tests/app/api/reviews-pending.route.test.ts`
|
||||
- Test: `tests/app/api/libraries.route.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write failing BFF tests for one proxied endpoint and one mock endpoint**
|
||||
|
||||
```ts
|
||||
import { GET } from "@/app/api/libraries/[libraryType]/route";
|
||||
|
||||
test("returns mock library data for unsupported backend modules", async () => {
|
||||
const response = await GET(new Request("http://localhost/api/libraries/models"), {
|
||||
params: Promise.resolve({ libraryType: "models" }),
|
||||
} as any);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the BFF tests to verify they fail**
|
||||
|
||||
Run: `npm run test -- tests/app/api/orders-create.route.test.ts tests/app/api/reviews-pending.route.test.ts tests/app/api/libraries.route.test.ts`
|
||||
Expected: FAIL with missing route handler modules
|
||||
|
||||
- [ ] **Step 3: Implement the backend fetch helper and environment parsing**
|
||||
|
||||
```ts
|
||||
export function getBackendBaseUrl() {
|
||||
return process.env.BACKEND_BASE_URL ?? "http://127.0.0.1:8000/api/v1";
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Implement the proxied route handlers and placeholder route handlers**
|
||||
|
||||
```ts
|
||||
return NextResponse.json({
|
||||
mode: "placeholder",
|
||||
items: MODEL_LIBRARY_FIXTURES,
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Normalize transport, validation, and system errors in one helper**
|
||||
|
||||
```ts
|
||||
return NextResponse.json(
|
||||
{ error: "BACKEND_UNAVAILABLE", message: "后端暂时不可用,请稍后重试。" },
|
||||
{ status: 502 },
|
||||
);
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Re-run the BFF tests to verify they pass**
|
||||
|
||||
Run: `npm run test -- tests/app/api/orders-create.route.test.ts tests/app/api/reviews-pending.route.test.ts tests/app/api/libraries.route.test.ts`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 7: Commit the BFF layer if git is available**
|
||||
|
||||
```bash
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
git add app/api src/lib/http src/lib/env.ts src/lib/validation tests/app/api
|
||||
git commit -m "feat: add bff routes for proxy and placeholder data"
|
||||
fi
|
||||
```
|
||||
|
||||
### Task 4: Implement The Shared Dashboard UI System
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/ui/button.tsx`
|
||||
- Create: `src/components/ui/card.tsx`
|
||||
- Create: `src/components/ui/status-badge.tsx`
|
||||
- Create: `src/components/ui/empty-state.tsx`
|
||||
- Create: `src/components/ui/page-header.tsx`
|
||||
- Create: `src/components/ui/section-title.tsx`
|
||||
- Modify: `app/globals.css`
|
||||
- Modify: `src/components/layout/dashboard-shell.tsx`
|
||||
- Test: `tests/ui/status-badge.test.tsx`
|
||||
- Test: `tests/ui/dashboard-shell.test.tsx`
|
||||
|
||||
- [ ] **Step 1: Write a failing test for status badge labels and tones**
|
||||
|
||||
```tsx
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { StatusBadge } from "@/components/ui/status-badge";
|
||||
|
||||
test("renders the waiting review label", () => {
|
||||
render(<StatusBadge status="waiting_review" />);
|
||||
expect(screen.getByText("待审核")).toBeInTheDocument();
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the UI primitive tests to verify they fail**
|
||||
|
||||
Run: `npm run test -- tests/ui/status-badge.test.tsx tests/ui/dashboard-shell.test.tsx`
|
||||
Expected: FAIL with missing `StatusBadge` export
|
||||
|
||||
- [ ] **Step 3: Implement the warm-console theme tokens and UI primitives**
|
||||
|
||||
```css
|
||||
:root {
|
||||
--bg-canvas: #f6f1e8;
|
||||
--bg-surface: #fffdf8;
|
||||
--ink-strong: #23303a;
|
||||
--accent-primary: #6e7f52;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Update the dashboard shell to use the approved navigation, type hierarchy, and side rail**
|
||||
|
||||
```tsx
|
||||
<aside className="bg-[var(--ink-strong)] text-stone-100">
|
||||
{/* primary navigation */}
|
||||
</aside>
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Re-run the UI primitive tests to verify they pass**
|
||||
|
||||
Run: `npm run test -- tests/ui/status-badge.test.tsx tests/ui/dashboard-shell.test.tsx`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 6: Commit the shared UI system if git is available**
|
||||
|
||||
```bash
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
git add app/globals.css src/components tests/ui
|
||||
git commit -m "feat: add dashboard shell and shared ui primitives"
|
||||
fi
|
||||
```
|
||||
|
||||
### Task 5: Implement The Submit Workbench
|
||||
|
||||
**Files:**
|
||||
- Create: `src/features/orders/components/create-order-form.tsx`
|
||||
- Create: `src/features/orders/components/resource-picker-card.tsx`
|
||||
- Create: `src/features/orders/components/order-summary-card.tsx`
|
||||
- Create: `src/features/orders/submit-workbench.tsx`
|
||||
- Modify: `app/(dashboard)/submit-workbench/page.tsx`
|
||||
- Test: `tests/features/orders/submit-workbench.test.tsx`
|
||||
|
||||
- [ ] **Step 1: Write a failing test for the customer-level/service-mode constraint**
|
||||
|
||||
```tsx
|
||||
test("forces low customers to use auto_basic", async () => {
|
||||
render(<SubmitWorkbench />);
|
||||
|
||||
await user.selectOptions(screen.getByLabelText("客户层级"), "low");
|
||||
|
||||
expect(screen.getByDisplayValue("auto_basic")).toBeInTheDocument();
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the submit workbench test to verify it fails**
|
||||
|
||||
Run: `npm run test -- tests/features/orders/submit-workbench.test.tsx`
|
||||
Expected: FAIL with missing `SubmitWorkbench` component
|
||||
|
||||
- [ ] **Step 3: Implement the mock-backed selectors, validation, and summary card**
|
||||
|
||||
```ts
|
||||
if (customerLevel === "low") {
|
||||
form.service_mode = "auto_basic";
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Add the submit action with loading, success, and inline error states**
|
||||
|
||||
```tsx
|
||||
const [isPending, startTransition] = useTransition();
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Re-run the submit workbench test to verify it passes**
|
||||
|
||||
Run: `npm run test -- tests/features/orders/submit-workbench.test.tsx`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 6: Manually verify the happy path in the browser against a running backend**
|
||||
|
||||
Run: `npm run dev`
|
||||
Expected: a created order redirects to `/orders/<id>` and shows the returned `workflow_id`
|
||||
|
||||
- [ ] **Step 7: Commit the submit workbench if git is available**
|
||||
|
||||
```bash
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
git add app/(dashboard)/submit-workbench src/features/orders tests/features/orders
|
||||
git commit -m "feat: implement submit workbench"
|
||||
fi
|
||||
```
|
||||
|
||||
### Task 6: Implement The Review Workbench
|
||||
|
||||
**Files:**
|
||||
- Create: `src/features/reviews/components/review-queue.tsx`
|
||||
- Create: `src/features/reviews/components/review-image-panel.tsx`
|
||||
- Create: `src/features/reviews/components/review-action-panel.tsx`
|
||||
- Create: `src/features/reviews/components/review-workflow-summary.tsx`
|
||||
- Create: `src/features/reviews/review-workbench.tsx`
|
||||
- Modify: `app/(dashboard)/reviews/workbench/page.tsx`
|
||||
- Test: `tests/features/reviews/review-workbench.test.tsx`
|
||||
|
||||
- [ ] **Step 1: Write a failing test that `rerun_face` requires a comment**
|
||||
|
||||
```tsx
|
||||
test("requires a comment before rerun_face submission", async () => {
|
||||
render(<ReviewWorkbench />);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "重跑 Face" }));
|
||||
|
||||
expect(screen.getByText("请填写审核备注")).toBeInTheDocument();
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the review workbench test to verify it fails**
|
||||
|
||||
Run: `npm run test -- tests/features/reviews/review-workbench.test.tsx`
|
||||
Expected: FAIL with missing `ReviewWorkbench` component
|
||||
|
||||
- [ ] **Step 3: Implement the queue, current-order selection, and image inspection layout**
|
||||
|
||||
```tsx
|
||||
const [selectedOrderId, setSelectedOrderId] = useState<number | null>(null);
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Implement approve and rerun actions with non-optimistic queue refresh**
|
||||
|
||||
```tsx
|
||||
await submitReview(payload);
|
||||
await refreshQueue();
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Re-run the review workbench test to verify it passes**
|
||||
|
||||
Run: `npm run test -- tests/features/reviews/review-workbench.test.tsx`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 6: Manually verify review actions against a running backend**
|
||||
|
||||
Run: `npm run dev`
|
||||
Expected: pending items remain visible until the refreshed backend response says otherwise
|
||||
|
||||
- [ ] **Step 7: Commit the review workbench if git is available**
|
||||
|
||||
```bash
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
git add app/(dashboard)/reviews src/features/reviews tests/features/reviews
|
||||
git commit -m "feat: implement review workbench"
|
||||
fi
|
||||
```
|
||||
|
||||
### Task 7: Implement Order Detail And Workflow Detail
|
||||
|
||||
**Files:**
|
||||
- Create: `src/features/orders/components/order-detail-header.tsx`
|
||||
- Create: `src/features/orders/components/order-assets-panel.tsx`
|
||||
- Create: `src/features/orders/components/order-workflow-card.tsx`
|
||||
- Create: `src/features/orders/order-detail.tsx`
|
||||
- Create: `src/features/workflows/components/workflow-status-card.tsx`
|
||||
- Create: `src/features/workflows/components/workflow-timeline.tsx`
|
||||
- Create: `src/features/workflows/workflow-detail.tsx`
|
||||
- Modify: `app/(dashboard)/orders/[orderId]/page.tsx`
|
||||
- Modify: `app/(dashboard)/workflows/[orderId]/page.tsx`
|
||||
- Test: `tests/features/orders/order-detail.test.tsx`
|
||||
- Test: `tests/features/workflows/workflow-detail.test.tsx`
|
||||
|
||||
- [ ] **Step 1: Write failing tests for a mock asset banner and an empty final-result state**
|
||||
|
||||
```tsx
|
||||
test("shows a mock asset banner when the final asset uses a mock uri", () => {
|
||||
render(<OrderDetail viewModel={mockOrderDetailVm} />);
|
||||
|
||||
expect(screen.getByText("当前资产来自 mock 流程")).toBeInTheDocument();
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the detail page tests to verify they fail**
|
||||
|
||||
Run: `npm run test -- tests/features/orders/order-detail.test.tsx tests/features/workflows/workflow-detail.test.tsx`
|
||||
Expected: FAIL with missing detail components
|
||||
|
||||
- [ ] **Step 3: Implement the order detail page with business-empty handling**
|
||||
|
||||
```tsx
|
||||
{!viewModel.finalAsset ? <EmptyState title="最终图暂未生成" /> : <FinalAssetCard asset={viewModel.finalAsset} />}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Implement the workflow detail page with step timeline and failure emphasis**
|
||||
|
||||
```tsx
|
||||
<ol>{viewModel.steps.map((step) => <WorkflowStepRow key={step.name} step={step} />)}</ol>
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Re-run the detail page tests to verify they pass**
|
||||
|
||||
Run: `npm run test -- tests/features/orders/order-detail.test.tsx tests/features/workflows/workflow-detail.test.tsx`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 6: Commit the detail pages if git is available**
|
||||
|
||||
```bash
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
git add app/(dashboard)/orders app/(dashboard)/workflows src/features/orders src/features/workflows tests/features/orders tests/features/workflows
|
||||
git commit -m "feat: implement order and workflow detail pages"
|
||||
fi
|
||||
```
|
||||
|
||||
### Task 8: Implement Placeholder Home, Workflow Lookup, Libraries, Login, And Settings
|
||||
|
||||
**Files:**
|
||||
- Create: `src/features/orders/orders-home.tsx`
|
||||
- Create: `src/features/workflows/workflow-lookup.tsx`
|
||||
- Create: `src/features/libraries/library-page.tsx`
|
||||
- Create: `src/features/settings/settings-placeholder.tsx`
|
||||
- Create: `src/features/auth/login-placeholder.tsx`
|
||||
- Modify: `app/(dashboard)/orders/page.tsx`
|
||||
- Modify: `app/(dashboard)/workflows/page.tsx`
|
||||
- Create: `app/(dashboard)/libraries/models/page.tsx`
|
||||
- Create: `app/(dashboard)/libraries/scenes/page.tsx`
|
||||
- Create: `app/(dashboard)/libraries/garments/page.tsx`
|
||||
- Create: `app/(dashboard)/settings/page.tsx`
|
||||
- Create: `app/login/page.tsx`
|
||||
- Test: `tests/features/orders/orders-home.test.tsx`
|
||||
- Test: `tests/features/libraries/library-page.test.tsx`
|
||||
|
||||
- [ ] **Step 1: Write failing tests for the honest placeholder messaging**
|
||||
|
||||
```tsx
|
||||
test("explains that the orders list depends on a future backend api", () => {
|
||||
render(<OrdersHome />);
|
||||
|
||||
expect(screen.getByText("当前未接入真实订单列表接口")).toBeInTheDocument();
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the placeholder page tests to verify they fail**
|
||||
|
||||
Run: `npm run test -- tests/features/orders/orders-home.test.tsx tests/features/libraries/library-page.test.tsx`
|
||||
Expected: FAIL with missing placeholder components
|
||||
|
||||
- [ ] **Step 3: Implement the `/orders` home page with direct lookup, recent visits, and transition copy**
|
||||
|
||||
```tsx
|
||||
<EmptyState title="当前未接入真实订单列表接口" description="可通过订单号直达详情,或从最近访问记录继续处理。" />
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Implement the workflow lookup, library placeholders, settings, and login placeholders**
|
||||
|
||||
```tsx
|
||||
<LibraryPage title="模特库" placeholderMode />
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Re-run the placeholder page tests to verify they pass**
|
||||
|
||||
Run: `npm run test -- tests/features/orders/orders-home.test.tsx tests/features/libraries/library-page.test.tsx`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 6: Commit the placeholder pages if git is available**
|
||||
|
||||
```bash
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
git add app/(dashboard)/orders app/(dashboard)/workflows app/(dashboard)/libraries app/(dashboard)/settings app/login src/features/orders src/features/workflows src/features/libraries src/features/settings src/features/auth tests/features
|
||||
git commit -m "feat: add placeholder dashboard modules"
|
||||
fi
|
||||
```
|
||||
|
||||
### Task 9: Verify The Full Build And Document Local Setup
|
||||
|
||||
**Files:**
|
||||
- Create: `README.md`
|
||||
- Modify: `package.json`
|
||||
- Modify: `docs/superpowers/specs/2026-03-27-auto-virtual-tryon-admin-frontend-design.md`
|
||||
|
||||
- [ ] **Step 1: Add a README with local run instructions and backend environment notes**
|
||||
|
||||
```md
|
||||
BACKEND_BASE_URL=http://127.0.0.1:8000/api/v1
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the full automated test suite**
|
||||
|
||||
Run: `npm run test`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 3: Run lint and production build verification**
|
||||
|
||||
Run: `npm run lint && npm run build`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 4: Perform a final manual flow check against the FastAPI backend**
|
||||
|
||||
Run: `npm run dev`
|
||||
Expected: submit, review, order detail, and workflow detail all work against `/Volumes/DockCase/codes/auto-virtual-tryon`
|
||||
|
||||
- [ ] **Step 5: Commit the verified frontend if git is available**
|
||||
|
||||
```bash
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
git add README.md package.json docs/superpowers/specs/2026-03-27-auto-virtual-tryon-admin-frontend-design.md
|
||||
git commit -m "docs: add frontend runbook and verification notes"
|
||||
fi
|
||||
```
|
||||
@@ -0,0 +1,512 @@
|
||||
# Auto Virtual Tryon Admin Frontend Design
|
||||
|
||||
Date: 2026-03-27
|
||||
|
||||
## 1. Background
|
||||
|
||||
This project will be a standalone Next.js admin frontend for the virtual try-on pipeline described in the root PRD:
|
||||
|
||||
- PRD source: `2026-03-27-frontend-admin-prd.md`
|
||||
- Backend reference: adjacent project `/Volumes/DockCase/codes/auto-virtual-tryon`
|
||||
|
||||
The frontend is not being designed against an abstract future system. It must respect the current backend reality.
|
||||
|
||||
### 1.1 Current Backend Reality
|
||||
|
||||
The current backend project already exposes stable APIs for:
|
||||
|
||||
- `POST /api/v1/orders`
|
||||
- `GET /api/v1/orders/{order_id}`
|
||||
- `GET /api/v1/orders/{order_id}/assets`
|
||||
- `GET /api/v1/reviews/pending`
|
||||
- `POST /api/v1/reviews/{order_id}/submit`
|
||||
- `GET /api/v1/workflows/{order_id}`
|
||||
|
||||
The root PRD also describes manual revision flows and additional endpoints such as:
|
||||
|
||||
- `POST /api/v1/orders/{order_id}/revisions`
|
||||
- `GET /api/v1/orders/{order_id}/revisions`
|
||||
- `POST /api/v1/reviews/{order_id}/confirm-revision`
|
||||
|
||||
Those endpoints are not present in the currently implemented backend code at `/Volumes/DockCase/codes/auto-virtual-tryon/app`.
|
||||
|
||||
### 1.2 Design Consequence
|
||||
|
||||
The frontend must therefore distinguish between:
|
||||
|
||||
- real integration modules backed by implemented APIs
|
||||
- placeholder or mock-backed modules that preserve the intended information architecture
|
||||
|
||||
The design does not fake backend completeness. It preserves product structure while keeping technical truth explicit.
|
||||
|
||||
## 2. Product Goal
|
||||
|
||||
Build a complete admin console shell in Next.js that:
|
||||
|
||||
- feels like a real internal operations product rather than a demo
|
||||
- supports true end-to-end integration for the currently implemented backend workflows
|
||||
- preserves the full first-phase information architecture from the PRD
|
||||
- keeps future backend completion low-cost by isolating mocks and adapters away from page components
|
||||
|
||||
## 3. Approved Scope
|
||||
|
||||
### 3.1 Scope Baseline
|
||||
|
||||
The approved direction is:
|
||||
|
||||
- follow the PRD as the product baseline
|
||||
- prioritize real integration pages first
|
||||
- do not let the rest of the console feel unfinished or structurally hollow
|
||||
|
||||
### 3.2 Integration Strategy
|
||||
|
||||
The approved data strategy is:
|
||||
|
||||
- pages only request the Next.js app itself
|
||||
- Next.js provides a BFF layer under `app/api/*`
|
||||
- the BFF decides whether to proxy to the real FastAPI backend or return mock / placeholder data
|
||||
|
||||
This keeps page code unaware of whether a module is currently real or mocked.
|
||||
|
||||
## 4. Information Architecture
|
||||
|
||||
### 4.1 Primary Navigation
|
||||
|
||||
The first-level navigation is:
|
||||
|
||||
- `订单总览`
|
||||
- `提单工作台`
|
||||
- `审核工作台`
|
||||
- `流程追踪`
|
||||
- `资源库`
|
||||
- `系统设置`
|
||||
|
||||
### 4.2 Route Structure
|
||||
|
||||
The approved page tree is:
|
||||
|
||||
- `/orders`
|
||||
- `/orders/[orderId]`
|
||||
- `/submit-workbench`
|
||||
- `/reviews/workbench`
|
||||
- `/workflows`
|
||||
- `/workflows/[orderId]`
|
||||
- `/libraries/models`
|
||||
- `/libraries/scenes`
|
||||
- `/libraries/garments`
|
||||
- `/settings`
|
||||
- `/login`
|
||||
|
||||
### 4.3 Default Entry
|
||||
|
||||
The default landing page remains `/orders`.
|
||||
|
||||
This is intentionally retained even though the backend does not yet provide a real orders list API. The page will act as the official home of the console using a transitional strategy:
|
||||
|
||||
- direct order lookup
|
||||
- recent-visit history
|
||||
- mock or placeholder overview content
|
||||
- explicit messaging that full list/search depends on future backend support
|
||||
|
||||
## 5. Layout and Visual Direction
|
||||
|
||||
### 5.1 Approved Visual Direction
|
||||
|
||||
The approved visual direction is:
|
||||
|
||||
`A. Gallery-First Warm Console`
|
||||
|
||||
This means:
|
||||
|
||||
- warm neutral page background instead of pure white
|
||||
- deep ink navigation shell
|
||||
- restrained green accent for key CTA states
|
||||
- review surfaces designed around image inspection first
|
||||
|
||||
### 5.2 Visual Character
|
||||
|
||||
The UI should feel:
|
||||
|
||||
- professional
|
||||
- calm
|
||||
- high-density but readable
|
||||
- distinct from generic enterprise dashboards
|
||||
|
||||
It should not feel:
|
||||
|
||||
- cold and generic
|
||||
- decorative for decoration’s sake
|
||||
- overly editorial on operational pages
|
||||
|
||||
### 5.3 Typography and Color Rules
|
||||
|
||||
- Chinese UI text uses `Noto Sans SC`
|
||||
- IDs, order numbers, and technical labels use `IBM Plex Mono`
|
||||
- the primary accent is reserved for high-value actions such as submit and approve
|
||||
- state colors are managed separately from brand accent colors
|
||||
- the review workbench remains visually more restrained than marketing-style pages
|
||||
|
||||
## 6. Technical Architecture
|
||||
|
||||
### 6.1 Framework Direction
|
||||
|
||||
The frontend will be built as a standalone Next.js application using:
|
||||
|
||||
- Next.js App Router
|
||||
- TypeScript
|
||||
- Tailwind CSS
|
||||
|
||||
### 6.2 Route Grouping
|
||||
|
||||
The application will be organized as:
|
||||
|
||||
```text
|
||||
app/
|
||||
(dashboard)/
|
||||
orders/page.tsx
|
||||
orders/[orderId]/page.tsx
|
||||
submit-workbench/page.tsx
|
||||
reviews/workbench/page.tsx
|
||||
workflows/page.tsx
|
||||
workflows/[orderId]/page.tsx
|
||||
libraries/models/page.tsx
|
||||
libraries/scenes/page.tsx
|
||||
libraries/garments/page.tsx
|
||||
settings/page.tsx
|
||||
login/page.tsx
|
||||
api/*
|
||||
```
|
||||
|
||||
The dashboard route group owns the shared shell:
|
||||
|
||||
- side navigation
|
||||
- top bar
|
||||
- page content container
|
||||
- shared empty states
|
||||
- shared badges and status treatments
|
||||
|
||||
### 6.3 BFF Layer
|
||||
|
||||
The BFF layer under `app/api/*` is responsible for:
|
||||
|
||||
- request validation
|
||||
- backend proxying
|
||||
- response normalization
|
||||
- mock response generation
|
||||
- environment-based backend URL routing
|
||||
- mapping backend responses into stable frontend-facing contracts
|
||||
|
||||
Pages do not call FastAPI directly.
|
||||
|
||||
## 7. Data Model Strategy
|
||||
|
||||
### 7.1 Frontend View Models
|
||||
|
||||
The UI consumes stable frontend view models rather than raw backend payloads.
|
||||
|
||||
Approved shared view models:
|
||||
|
||||
- `OrderSummaryVM`
|
||||
- `OrderDetailVM`
|
||||
- `ReviewQueueItemVM`
|
||||
- `WorkflowDetailVM`
|
||||
- `LibraryItemVM`
|
||||
|
||||
### 7.2 Adapter Rules
|
||||
|
||||
All cross-source differences are handled in adapters:
|
||||
|
||||
- missing backend fields are converted into explicit fallback copy or null-safe UI states
|
||||
- business-empty responses are not treated as system failures
|
||||
- mock asset URIs such as `mock://...` are displayed honestly as mock assets
|
||||
- backend enum values are mapped once, not repeatedly in page components
|
||||
|
||||
### 7.3 File Decomposition
|
||||
|
||||
The frontend should be split along responsibility boundaries:
|
||||
|
||||
```text
|
||||
src/
|
||||
lib/
|
||||
api/
|
||||
adapters/
|
||||
mock/
|
||||
types/
|
||||
features/
|
||||
orders/
|
||||
reviews/
|
||||
workflows/
|
||||
libraries/
|
||||
components/
|
||||
layout/
|
||||
ui/
|
||||
```
|
||||
|
||||
The key rule is that mock-vs-real complexity must live in `lib`, not in page UI trees.
|
||||
|
||||
## 8. Real Modules vs Placeholder Modules
|
||||
|
||||
### 8.1 Real Integration Modules
|
||||
|
||||
The first implementation phase will perform true integration for:
|
||||
|
||||
- `提单工作台`
|
||||
- `审核工作台`
|
||||
- `订单详情`
|
||||
- `流程详情页 /workflows/[orderId]`
|
||||
|
||||
### 8.2 Placeholder or Transitional Modules
|
||||
|
||||
The first implementation phase will preserve full route structure for:
|
||||
|
||||
- `/orders`
|
||||
- `/workflows`
|
||||
- `/libraries/models`
|
||||
- `/libraries/scenes`
|
||||
- `/libraries/garments`
|
||||
- `/settings`
|
||||
- `/login`
|
||||
|
||||
These are not “missing pages”. They are real screens with:
|
||||
|
||||
- proper layout
|
||||
- proper states
|
||||
- mock or transitional data
|
||||
- explicit product messaging about current backend limitations
|
||||
|
||||
## 9. Core Page Responsibilities
|
||||
|
||||
### 9.1 `/submit-workbench`
|
||||
|
||||
Purpose:
|
||||
|
||||
- the only first-class order creation workspace
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- customer level selection
|
||||
- service mode selection
|
||||
- mock-backed resource selection for model, scene, garment
|
||||
- local validation of backend-supported combinations
|
||||
- request submission to create orders
|
||||
- success feedback and redirect to `/orders/[orderId]`
|
||||
|
||||
Non-responsibilities:
|
||||
|
||||
- no review actions
|
||||
- no workflow timeline deep-dive
|
||||
- no list monitoring behavior
|
||||
|
||||
### 9.2 `/reviews/workbench`
|
||||
|
||||
Purpose:
|
||||
|
||||
- the highest-frequency manual review surface
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- display the pending review queue
|
||||
- switch between orders quickly without route churn
|
||||
- show the current candidate asset and key order context
|
||||
- perform `approve` and `rerun_*` review decisions
|
||||
- surface compact workflow summary and errors relevant to review
|
||||
|
||||
Non-responsibilities:
|
||||
|
||||
- not the canonical archive for full order history
|
||||
- not the main workflow forensic page
|
||||
- not a fake implementation of unbuilt revision-chain APIs
|
||||
|
||||
Because the current backend lacks revision endpoints, first implementation should present those PRD concepts as clearly marked placeholders rather than simulate unsupported actions as if they were real.
|
||||
|
||||
### 9.3 `/orders/[orderId]`
|
||||
|
||||
Purpose:
|
||||
|
||||
- the canonical shared order detail page
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- order metadata
|
||||
- current status
|
||||
- asset list
|
||||
- final result area
|
||||
- workflow summary
|
||||
- navigation to review and workflow detail pages
|
||||
|
||||
Non-responsibilities:
|
||||
|
||||
- no heavy review action UI
|
||||
- no full process forensics
|
||||
- no order creation
|
||||
|
||||
### 9.4 `/workflows/[orderId]`
|
||||
|
||||
Purpose:
|
||||
|
||||
- focused workflow inspection and troubleshooting
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- workflow status card
|
||||
- current step
|
||||
- step timeline
|
||||
- failure and anomaly details
|
||||
- direct order-id-based lookup
|
||||
|
||||
Non-responsibilities:
|
||||
|
||||
- no primary image review experience
|
||||
- no review decision submission
|
||||
- no resource selection
|
||||
|
||||
## 10. UX Rules and State Handling
|
||||
|
||||
### 10.1 Submit Workbench Rules
|
||||
|
||||
- `low` must only allow `auto_basic`
|
||||
- `mid` must only allow `semi_pro`
|
||||
- submission failure must preserve form state
|
||||
- success must show `order_id` and `workflow_id`, then redirect to order detail
|
||||
|
||||
### 10.2 Review Workbench Rules
|
||||
|
||||
- queue items are never removed optimistically on action submission
|
||||
- `rerun_scene`, `rerun_face`, and `rerun_fusion` require comment input
|
||||
- action failures are shown inline in the action area
|
||||
- queue refresh should be explicit and predictable after successful actions
|
||||
|
||||
### 10.3 Order Detail Rules
|
||||
|
||||
- absence of final asset is a valid business state
|
||||
- absence of assets is a valid business empty state
|
||||
- unsupported revision-chain behavior is displayed as “not currently backed by backend” rather than as an error
|
||||
|
||||
### 10.4 Workflow Rules
|
||||
|
||||
- “not found” workflow responses must be distinguished from transport or server failures
|
||||
- workflow step rendering should emphasize current step, failed step, and rerun lineage where available
|
||||
|
||||
## 11. Error Model
|
||||
|
||||
The UI uses three error/state categories:
|
||||
|
||||
### 11.1 Business Empty State
|
||||
|
||||
Examples:
|
||||
|
||||
- no final image yet
|
||||
- no assets yet
|
||||
- no real orders list yet
|
||||
- no resource library backend yet
|
||||
|
||||
These render as valid explanatory UI states, not error banners.
|
||||
|
||||
### 11.2 Retryable Error
|
||||
|
||||
Examples:
|
||||
|
||||
- temporary network failure
|
||||
- backend timeout
|
||||
- proxy failure
|
||||
|
||||
These render with retry affordances.
|
||||
|
||||
### 11.3 System Error
|
||||
|
||||
Examples:
|
||||
|
||||
- unexpected response shape
|
||||
- unrecoverable server failure
|
||||
- application-level state contradiction
|
||||
|
||||
These render as hard failure states with diagnostic framing.
|
||||
|
||||
## 12. Mock and Placeholder Policy
|
||||
|
||||
Placeholder modules are first-class citizens in the shell, but they must remain honest.
|
||||
|
||||
Rules:
|
||||
|
||||
- never imply an unavailable backend capability is actually live
|
||||
- never silently replace missing backend data with fabricated “real-looking” data on core real-integration pages
|
||||
- keep mock data isolated to modules explicitly designated as transitional
|
||||
- label unavailable capability clearly where it matters to task completion
|
||||
|
||||
## 13. Testing Strategy
|
||||
|
||||
First-phase testing will prioritize correctness over exhaustive visual snapshot coverage.
|
||||
|
||||
### 13.1 Must-Test Areas
|
||||
|
||||
- BFF route handlers
|
||||
- adapter mapping logic
|
||||
- submit workbench validation rules
|
||||
- submit and review action request flows
|
||||
- key page state rendering for loading, empty, success, and failure
|
||||
|
||||
### 13.2 Lower Priority for Phase 1
|
||||
|
||||
- pixel-perfect visual snapshots
|
||||
- exhaustive placeholder-page snapshots
|
||||
- animation-heavy testing
|
||||
|
||||
The purpose of the first test layer is to protect data contracts and operational flows.
|
||||
|
||||
## 14. Delivery Boundary
|
||||
|
||||
### 14.1 First-Phase Hard Acceptance
|
||||
|
||||
The frontend must be able to:
|
||||
|
||||
- create an order from the submit workbench
|
||||
- review pending orders from the review workbench
|
||||
- execute `approve`
|
||||
- execute `rerun_scene`
|
||||
- execute `rerun_face`
|
||||
- execute `rerun_fusion`
|
||||
- inspect order detail data
|
||||
- inspect workflow detail data
|
||||
|
||||
### 14.2 First-Phase Structural Acceptance
|
||||
|
||||
The console must also provide:
|
||||
|
||||
- complete navigation shell
|
||||
- `/orders` as the official entry page
|
||||
- resource library placeholders
|
||||
- workflow lookup index page
|
||||
- settings and login route placeholders
|
||||
|
||||
## 15. Risks
|
||||
|
||||
- The root PRD is ahead of the currently implemented backend in revision-related capabilities.
|
||||
- The default home page is structurally important but cannot yet be backed by a real list API.
|
||||
- Mock asset URIs limit the realism of image preview experiences.
|
||||
- Without authentication in phase 1, the console assumes a trusted environment.
|
||||
|
||||
## 16. Implementation Direction
|
||||
|
||||
The implementation should proceed by:
|
||||
|
||||
1. scaffolding the Next.js app shell and BFF layer
|
||||
2. establishing shared types, adapters, and placeholder data contracts
|
||||
3. implementing the four real-integration modules
|
||||
4. filling in the transitional modules with honest placeholder behavior
|
||||
5. validating the accepted states and operational flows with tests
|
||||
|
||||
## 17. Local Setup Notes
|
||||
|
||||
Implementation assumes the frontend runs with:
|
||||
|
||||
- `BACKEND_BASE_URL=http://127.0.0.1:8000/api/v1`
|
||||
|
||||
Recommended local verification commands:
|
||||
|
||||
- `npm run test`
|
||||
- `npm run lint`
|
||||
- `npm run typecheck`
|
||||
- `npm run build`
|
||||
- `npm run verify`
|
||||
|
||||
The adjacent backend project must be started separately when manually checking the four real-integration pages.
|
||||
Reference in New Issue
Block a user