## 0. Parallel boundary and file-purpose annotations

| File | File purpose (plain language) | Ownership |
|---|---|---|
| `backend/src/main/java/com/xyw/console/asset/dto/DeviceAssetPageQuery.java` | Receives device-list page and filter values. | Device feature |
| `backend/src/main/java/com/xyw/console/asset/dto/DeviceAssetSaveRequest.java` | Receives create/edit fields and the two optional image parts. | Device feature |
| `backend/src/main/java/com/xyw/console/asset/dto/DeviceAssetResponse.java` | Defines one safe device row returned to the browser. | Device feature |
| `backend/src/main/java/com/xyw/console/asset/dto/DeviceAssetPageResponse.java` | Carries rows, total count, page number, and page size. | Device feature |
| `backend/src/main/java/com/xyw/console/asset/dto/DevicePersonLookupResponse.java` | Carries compact person-search results for the device form. | Device feature |
| `backend/src/main/java/com/xyw/console/asset/exception/DeviceAssetNotFoundException.java` | Represents a missing or already deleted device request. | Device feature |
| `backend/src/main/java/com/xyw/console/asset/exception/DeviceAssetValidationException.java` | Represents invalid device fields, image files, or protected deletion. | Device feature |
| `backend/src/main/java/com/xyw/console/asset/service/DeviceAssetFileStorageService.java` | Validates, stores, reads, replaces, and retains device image files. | Device feature |
| `backend/src/main/java/com/xyw/console/asset/service/DeviceAssetService.java` | Implements device CRUD, list filtering, person resolution, and reference checks. | Device feature |
| `backend/src/main/java/com/xyw/console/asset/controller/DeviceAssetController.java` | Exposes browser endpoints for devices, images, and person lookup. | Device feature |
| `backend/src/test/java/com/xyw/console/asset/service/DeviceAssetServiceTest.java` | Verifies device business rules without a live database. | Device feature |
| `backend/src/test/java/com/xyw/console/asset/controller/DeviceAssetControllerTest.java` | Verifies HTTP contracts, multipart handling, and file access. | Device feature |
| `frontend/src/modules/device/device-api-client.js` | Sends device API requests and converts failures to readable errors. | Device feature |
| `frontend/src/modules/device/DeviceAssetView.js` | Renders list, CRUD dialogs, person selector, images, and delete flow. | Device feature |
| `frontend/src/modules/device/device-asset.css` | Holds device-only CSS to avoid modifying shared styles. | Device feature |
| `frontend/tests/device-asset.spec.js` | Verifies the user-facing device workflow. | Device feature |
| `frontend/tests/authenticated-test.js` | Provides a shared developer-session mock so protected asset-page tests can exercise their own API fixtures. | Test integration |
| `frontend/src/App.js` | Renders global sidebar navigation. | Final integration owner only |
| `frontend/src/router/index.js` | Registers global Hash routes. | Final integration owner only |

- [x] 0.1 Create a dedicated device-asset branch/worktree from the approved base; preserve the current enterprise-WeChat working tree and do not reset, stash, or edit its files.
- [x] 0.2 Keep `AssetDeviceEntity.java`, `AssetDeviceMapper.java`, all enterprise-WeChat files, and `frontend/src/styles/app.css` read-only for the device feature; record the final integration owner for `App.js` and `router/index.js`.

## 1. Device request, response, and error contract

- [x] 1.1 Add `DeviceAssetPageQuery.java` with validated page/size and device filter fields. Add beginner comments to `resolvedPage` and `resolvedSize`: code purpose (plain language), related files, and request-to-pagination data flow.
- [x] 1.2 Add `DeviceAssetSaveRequest.java` for required device name, optional active user person, approved statuses, two optional multipart images, and explicit image-removal flags; document its file purpose.
- [x] 1.3 Add `DeviceAssetResponse.java`, `DeviceAssetPageResponse.java`, and `DevicePersonLookupResponse.java`; document each file purpose and exclude physical paths and `deleteTime` from browser responses.
- [x] 1.4 Add device-specific not-found and validation exceptions, plus focused exception-to-HTTP-response handling if the existing handler cannot safely support them; document each new method and error data flow.

## 2. Local image-file support

- [x] 2.1 Add `DeviceAssetFileStorageService.java` with a configurable `./uploads/device-assets` default and an application multipart limit that permits two 20 MB files plus form data, without exposing physical paths.
- [x] 2.2 Implement and fully annotate every storage method: constructor, `store`, `resolve`, `replace`, `removeReference`, `validateImage`, `createOpaqueIdentifier`, `resolveInsideRoot`, and temporary-file cleanup helpers. Each comment MUST state code purpose (plain language), related files, and upload-to-database-to-preview data flow.
- [x] 2.3 Validate JPG, PNG, and GIF extension plus decodable image content, reject any image over 20 MB, and test path traversal, unsupported type, corrupted content, and oversized file rejection.
- [x] 2.4 Preserve original files through normal soft deletion; ensure failed create/update operations remove only files written by that failed request and never remove an existing referenced original.

## 3. Backend device CRUD and integrity protection

- [x] 3.1 Add `DeviceAssetService.java`, injecting existing device, company-person, phone, enterprise-WeChat, WeChat, and Douyin Mappers without changing their source files.
- [x] 3.2 Implement and fully annotate every service method: constructor, `page`, `create`, `update`, `softDelete`, `searchCompanyPersons`, `findImage`, `activeQuery`, `requireActiveDevice`, `validateSaveRequest`, `validateUserPerson`, `validateStatus`, `checkActiveReferences`, `collectIds`, `personNames`, `toResponse`, `hasText`, and any added helper. Each comment MUST state code purpose (plain language), related files, and Controller-to-Service-to-Mapper/file data flow.
- [x] 3.3 Enforce nonblank active-unique device names, approved values `使用中/闲置/维修中/停用` and `已关联/未关联/待确认`, optional active company-person ownership, audit-time initialization, and `delete_time = 0` list filtering.
- [x] 3.4 Enforce soft-delete protection across active phone, enterprise-WeChat, WeChat, and Douyin records; return a readable list of source types when deletion is blocked.
- [x] 3.5 Add `DeviceAssetController.java` for `GET/POST/PUT/DELETE /api/device-assets`, company-person lookup, and controlled opaque-file access. Fully annotate its constructor and every endpoint method with code purpose (plain language), related files, and HTTP-to-Service-to-response data flow.

## 4. Device Asset Management frontend

- [x] 4.1 Add `device-api-client.js`, including `request`, `listDeviceAssets`, `createDeviceAsset`, `updateDeviceAsset`, `deleteDeviceAsset`, and `searchDeviceCompanyPersons`. Add required beginner comments to each function describing purpose, related files, and view-to-API-to-Controller flow.
- [x] 4.2 Add `DeviceAssetView.js` and document the component file purpose. Implement and fully annotate `setup`, `loadPage`, `openCreate`, `openEdit`, `resetForm`, `submitForm`, `confirmDelete`, `fetchPersonSuggestions`, `validateImageBeforeSelect`, image preview callbacks, image-removal callbacks, `scheduleSearch`, `submitSearch`, `resetSearch`, `changePage`, `changePageSize`, and the mount callback. Every annotation MUST contain code purpose (plain language), related files, and user-action-to-API-to-rendered-state flow.
- [x] 4.3 Render the approved filters, paged table, create/edit dialog, remote person selector, fixed status dropdowns, save/loading/error states, and soft-delete confirmation with reference-error feedback.
- [x] 4.4 Implement two image slots that accept JPG/PNG/GIF up to 20 MB each, preview the original image in a fixed-size browser frame, allow retain/replace/remove on edit, and do not request or create a generated thumbnail file.
- [x] 4.5 Add `device-asset.css` and import it only from the device module; use device-prefixed selectors and preserve `app.css` unchanged.

## 5. Final route and menu integration

- [x] 5.1 After enterprise-WeChat work is ready, have the designated integration owner add only the `设备资产管理` menu link in `frontend/src/App.js`; preserve all existing links and add the required file/method comment if any logic changes.
- [x] 5.2 Have the same integration owner add only `/device-assets` → `DeviceAssetView` in `frontend/src/router/index.js`; preserve the enterprise-WeChat route and add the required file/function comment if any logic changes.
- [x] 5.3 Rebase or merge the device branch only after both feature branches are independently verified; resolve no business changes in shared files outside the dedicated integration commit.

## 6. Verification and handoff

- [x] 6.1 Add `DeviceAssetServiceTest.java` coverage for default pagination, every filter, active-name uniqueness, approved-status validation, person validation, all four deletion-reference sources, safe soft deletion, image preservation, replacement, explicit removal, and failed-upload cleanup. Add required comments to every test method and business callback.
- [x] 6.2 Add `DeviceAssetControllerTest.java` coverage for GET pagination, multipart create/update, image validation and controlled image reads, error responses, and hidden `deleteTime`/physical paths. Add required comments to every test method and callback.
- [x] 6.3 Add `frontend/tests/device-asset.spec.js` coverage for the new route/menu, filters, pagination, create/edit, status dropdowns, image type/20 MB checks, browser-sized preview, retained/replaced/removed images, and deletion-protection feedback. Add required comments to every test callback.
- [x] 6.4 Run `openspec validate add-device-asset-management --strict`, backend compile and focused tests, frontend build, device Playwright tests, then existing phone and enterprise-WeChat smoke tests after integration. Analyze any failure before changing code.
- [x] 6.5 Record the implementation file list, route/menu effect, API/DTO/configuration impact, database non-impact, executed verification, and any unexecuted check in the completion handoff.

## Completion handoff (2026-08-03)

### Implementation files

- Backend: `DeviceAssetMultipartConfig`, `DeviceAssetController`, `DeviceAssetExceptionHandler`, five `DeviceAsset*` DTOs, two device exceptions, `DeviceAssetFileStorageService`, and `DeviceAssetService`.
- Backend tests: `DeviceAssetServiceTest`, `DeviceAssetFileStorageServiceTest`, and `DeviceAssetControllerTest`.
- Frontend: `device-api-client.js`, `DeviceAssetView.js`, `device-asset.css`, and `playwright.device.config.js`.
- Test integration: `device-asset.spec.js` plus `authenticated-test.js`; the existing phone, enterprise-WeChat, and legacy-reference specifications now import the shared authenticated test object.

### Product and contract effect

- Route and menu: `#/device-assets` renders Device Asset Management and the sidebar exposes the Device Asset Management entry. The integration preserves the enterprise-WeChat route.
- API and DTOs: `GET/POST/PUT/DELETE /api/device-assets`, company-person lookup, and controlled opaque image reads are available. Multipart saves accept two original JPG/PNG/GIF files, each at most 20 MB; response DTOs omit physical paths and `deleteTime`.
- Configuration: `DeviceAssetMultipartConfig` permits two 20 MB uploads plus form data and `DeviceAssetFileStorageService` defaults to `./uploads/device-assets`.
- Database: no DDL, migration, or direct database operation was performed for device management; the existing `as_asset_device` table and its soft-delete fields are reused.

### Executed verification

- `openspec validate add-device-asset-management --strict` passed.
- `mvn -q test` passed.
- `npm run build` passed. Vite retained its existing third-party PURE-comment and bundle-size warnings.
- `npx playwright test tests/device-asset.spec.js --config=playwright.device.config.js --reporter=list --timeout=30000` passed: 5/5.
- `npx playwright test --config=playwright.device.config.js --reporter=list --timeout=30000` passed: 13/13, including device, phone, enterprise-WeChat, and legacy-reference tests.

### Resolution of the prior test blocker

The newly integrated authentication guard redirected protected asset pages before their business request fixtures were registered. The shared `authenticated-test.js` fixture now returns a deterministic developer session and CSRF preflight response. It changes test setup only; production authentication, permissions, APIs, and asset business behavior remain unchanged.

### Unexecuted checks

None for the approved implementation scope.
