You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dianshang-qianduan/docs/superpowers/plans/2026-08-07-new-product-surv...

233 lines
11 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# New Product Survey Step Four 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:** Deliver the student-only fourth step that collects three AI application-value analyses and blocks final task submission until all are filled.
**Architecture:** Keep the existing `StudentTrainingAnswer.step4Answer` JSON persistence and add a stateless student-only validation endpoint. The Vue page retains a local draft and calls the validation endpoint only on final submission; the demo client enforces the same non-empty rule locally.
**Tech Stack:** Vue 3 Composition API, Element Plus, Vite, Spring Boot, Java 8, JUnit 5, Mockito.
## Global Constraints
- Only change the student `new-product-survey` page and its supporting student validation API; do not change teacher, admin, table schema, prior steps, or material download behavior.
- Persist `{ coreValue, tangibleValue, extendedValue }` in the existing `step4Answer` field.
- A value is valid only when `trim()` leaves non-empty text; validation does not score analysis quality.
- Saving a draft remains allowed with empty fields; final `SUBMIT` is guarded by validation.
- Keep legacy fourth-step JSON restoration compatible.
- Do not start the backend automatically; the user starts it manually.
---
### Task 1: Add server-side fourth-step validation
**Files:**
- Create: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/main/java/com/sztzjy/linkCommerce/entity/dto/NewProductSurveyStepFourValidationRequest.java`
- Create: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/main/java/com/sztzjy/linkCommerce/entity/dto/NewProductSurveyStepFourValidationResult.java`
- Create: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/main/java/com/sztzjy/linkCommerce/service/NewProductSurveyStepFourService.java`
- Create: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/main/java/com/sztzjy/linkCommerce/service/impl/NewProductSurveyStepFourServiceImpl.java`
- Modify: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java`
- Test: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/test/java/com/sztzjy/linkCommerce/service/impl/NewProductSurveyStepFourServiceImplTest.java`
- Test: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java`
**Interfaces:**
- Consumes: authenticated `JwtUser` and `NewProductSurveyStepFourValidationRequest { String coreValue, String tangibleValue, String extendedValue }`.
- Produces: `NewProductSurveyStepFourValidationResult { boolean valid, String message }` from `POST /api/student-training-answers/new-product-survey/step-4/validate`.
- [ ] **Step 1: Write the failing service tests**
```java
@Test
void acceptsStudentWithAllThreeNonBlankValues() {
NewProductSurveyStepFourValidationRequest request = request("核心分析", "有形分析", "延伸分析");
assertTrue(service.validate(request, student()).isValid());
}
@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = {" ", "\t"})
void rejectsBlankCoreValue(String value) {
assertThrows(ServiceException.class, () -> service.validate(request(value, "有形", "延伸"), student()));
}
@Test
void rejectsNonStudent() {
assertThrows(ServiceException.class, () -> service.validate(request("核心", "有形", "延伸"), teacher()));
}
```
- [ ] **Step 2: Run the service test to verify it fails**
Run: `mvn -B '-Dtest=NewProductSurveyStepFourServiceImplTest' test`
Expected: FAIL because fourth-step request and service types do not exist.
- [ ] **Step 3: Implement DTOs and service**
```java
public interface NewProductSurveyStepFourService {
NewProductSurveyStepFourValidationResult validate(NewProductSurveyStepFourValidationRequest request, JwtUser user);
}
private void requireNonBlank(String value, String message) {
if (StringUtils.isBlank(value)) {
throw new ServiceException(HttpStatus.BAD_REQUEST, message);
}
}
```
Require the existing student role and user id, then require `coreValue`, `tangibleValue`, and `extendedValue` after trimming. Return `valid=true` and `校验通过` on success.
- [ ] **Step 4: Run the service test to verify it passes**
Run: `mvn -B '-Dtest=NewProductSurveyStepFourServiceImplTest' test`
Expected: PASS with nonblank, blank, and authorization behavior covered.
- [ ] **Step 5: Write the failing controller test**
```java
@Test
void validateStepFourUsesAuthenticatedStudentAndReturnsValidationResult() {
NewProductSurveyStepFourValidationResult result = new NewProductSurveyStepFourValidationResult(true, "校验通过");
when(newProductSurveyStepFourService.validate(any(), any())).thenReturn(result);
ResultEntity<NewProductSurveyStepFourValidationResult> response = controller
.validateNewProductSurveyStepFour(request("核心", "有形", "延伸"), authenticatedRequest());
assertEquals(HttpStatus.OK, response.getCode());
assertSame(result, response.getData());
}
```
- [ ] **Step 6: Run the controller test to verify it fails**
Run: `mvn -B '-Dtest=StudentTrainingAnswerControllerTest' test`
Expected: FAIL because `validateNewProductSurveyStepFour` does not exist.
- [ ] **Step 7: Add the controller endpoint**
```java
@PostMapping("/new-product-survey/step-4/validate")
public ResultEntity<NewProductSurveyStepFourValidationResult> validateNewProductSurveyStepFour(
@RequestBody NewProductSurveyStepFourValidationRequest answer, HttpServletRequest request) {
try {
return new ResultEntity<>(HttpStatus.OK, "校验通过",
newProductSurveyStepFourService.validate(answer, TokenProvider.getJWTUser(request)));
} catch (ServiceException e) {
return new ResultEntity<>(e.getCode(), e.getMessage());
}
}
```
- [ ] **Step 8: Run focused server tests**
Run: `mvn -B '-Dtest=NewProductSurveyStepFourServiceImplTest,StudentTrainingAnswerControllerTest' test`
Expected: PASS with fourth-step service behavior and endpoint delegation covered.
- [ ] **Step 9: Commit server validation**
```bash
git add src/main/java/com/sztzjy/linkCommerce/entity/dto/NewProductSurveyStepFourValidationRequest.java src/main/java/com/sztzjy/linkCommerce/entity/dto/NewProductSurveyStepFourValidationResult.java src/main/java/com/sztzjy/linkCommerce/service/NewProductSurveyStepFourService.java src/main/java/com/sztzjy/linkCommerce/service/impl/NewProductSurveyStepFourServiceImpl.java src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java src/test/java/com/sztzjy/linkCommerce/service/impl/NewProductSurveyStepFourServiceImplTest.java src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java
git commit -m "feat: validate new product survey step four"
```
### Task 2: Update the fourth-step student UI and submission flow
**Files:**
- Modify: `E:/workspace/dianshang/e-commerce-internet/.worktrees/new-product-survey-step3/src/api/studentTrainingAnswer.js`
- Modify: `E:/workspace/dianshang/e-commerce-internet/.worktrees/new-product-survey-step3/src/views/foundation/new-product-survey.vue`
- Modify: `E:/workspace/dianshang/e-commerce-internet/.worktrees/new-product-survey-step3/tests/new-product-survey-step-one.static.test.cjs`
**Interfaces:**
- Consumes: `checkNewProductSurveyStepFour(payload)` returning `{ code: 200, data: { valid: true, message: "校验通过" } }`.
- Produces: guarded `submitTask()` that saves `step4Answer` only after successful validation.
- [ ] **Step 1: Add failing static source assertions**
```js
assert.match(page, /AI技术是否实现产品功能突破是否形成差异化卖点/, "step four must show the core-layer prototype question");
assert.match(page, /AI技术是否影响产品形态如产品外形包装、电商主图设计、参数配置、价格带定位。/, "step four must show the tangible-layer prototype question");
assert.match(page, /AI技术如何通过服务升级、内容更新提升用户粘性推动付费服务/, "step four must show the extended-layer prototype question");
assert.match(page, /checkNewProductSurveyStepFour\(step4Form\.value\)/, "step four must validate before submission");
assert.match(api, /new-product-survey\/step-4\/validate/, "the API must expose the step-four validation route");
```
- [ ] **Step 2: Run the static test to verify it fails**
Run: `& 'E:\Program Files\nodejs\node.exe' tests\new-product-survey-step-one.static.test.cjs`
Expected: FAIL because the fourth-step question copy and validation call are absent.
- [ ] **Step 3: Implement client validation and prototype-aligned form**
```js
function validateNewProductSurveyStepFourDemo(form) {
const value = form || {};
for (const [field, label] of [["coreValue", "核心层"], ["tangibleValue", "有形层"], ["extendedValue", "延伸层"]]) {
if (!String(value[field] || "").trim()) throw new Error(`请填写${label}AI应用价值分析`);
}
return { valid: true, message: "校验通过" };
}
async function submitTask() {
checking.value = true;
try {
await checkNewProductSurveyStepFour(step4Form.value);
await saveAnswer("SUBMITTED");
} catch (error) {
proxy?.$modal?.msgWarning(error?.message || "请完成三层次AI应用价值分析");
} finally {
checking.value = false;
}
}
```
Replace the existing generic field labels with the three prototype questions, keep their bindings as `coreValue`, `tangibleValue`, and `extendedValue`, and preserve draft saving and restoration.
- [ ] **Step 4: Run the static test to verify it passes**
Run: `& 'E:\Program Files\nodejs\node.exe' tests\new-product-survey-step-one.static.test.cjs`
Expected: PASS with prior step contracts still intact.
- [ ] **Step 5: Commit student UI and client validation**
```bash
git add src/api/studentTrainingAnswer.js src/views/foundation/new-product-survey.vue tests/new-product-survey-step-one.static.test.cjs
git commit -m "feat: add new product survey step four"
```
### Task 3: Run full verification
**Files:**
- Modify: none.
**Interfaces:**
- Consumes: both committed fourth-step implementations.
- Produces: verification evidence before integration; no application process is started.
- [ ] **Step 1: Run complete backend tests**
Run: `mvn -B test`
Expected: Maven reports `BUILD SUCCESS` and zero failures.
- [ ] **Step 2: Run the frontend source contract**
Run: `& 'E:\Program Files\nodejs\node.exe' tests\new-product-survey-step-one.static.test.cjs`
Expected: `new product survey step-one contract passed`.
- [ ] **Step 3: Run the production frontend build**
Run: `& 'E:\Program Files\nodejs\node.exe' 'E:\workspace\dianshang\e-commerce-internet\node_modules\vite\bin\vite.js' build`
Expected: Vite exits with code 0. Existing `::v-deep`, unresolved `Navbar.vue` top1 asset, and large-chunk warnings may remain.
- [ ] **Step 4: Inspect repository state**
Run: `git status --short; git log --oneline --max-count=5`
Expected: only the intended fourth-step commits are present; do not start the backend.