完成五人团队正式内用最小收口(07-18-small-team-internal-readiness)

这个提交包含在:
2026-07-18 15:46:14 +08:00
父节点 58c8decef9
当前提交 5d0a5f9a38
共修改 134 个文件,包含 10790 行新增和 1413 行删除
@@ -938,6 +938,69 @@ validation prevent repeated re-entry and reduce support/debugging cost.
- Focused Playwright coverage for draft save, submit validation, unsaved-change
protection and server-validation failure paths when changing form behavior.
## Scenario: Data-Router Unsaved-Change Protection
### 1. Scope / Trigger
- Trigger: a React form can lose unsaved work through in-app navigation,
browser back/forward, reload, closing its panel or switching records.
### 2. Signatures
- Router: `createBrowserRouter(...)` rendered through `RouterProvider`.
- Navigation blocker: React Router `useBlocker(isDirty)`.
- Reload/close guard: `beforeunload` while `isDirty === true`.
- Shared UI contract: one unsaved-change dialog with continue-editing and
discard actions.
### 3. Contracts
- Block navigation before the route or selected record changes; do not restore
old UI state after navigation has already occurred.
- `blocker.reset()` keeps the current route and form values. `blocker.proceed()`
is called only after explicit discard confirmation.
- Record switching and panel closing use the same pending-action contract as
route navigation. Successful save or explicit discard clears dirty state.
- Register `beforeunload` only while dirty and remove it during cleanup.
### 4. Validation & Error Matrix
- Clean form navigation -> continue without a dialog.
- Dirty in-app navigation or browser back -> block and show one dialog.
- Continue editing -> URL, record selection and values remain unchanged.
- Discard -> execute exactly one pending navigation/selection and clear dirty.
- Reload/close while dirty -> browser-level unload warning remains active.
### 5. Good/Base/Bad Cases
- Good: reimbursement, procurement, contract and asset forms reuse one guard
while keeping their own save and dirty-field logic.
- Base: a short non-editable filter form does not register the guard.
- Bad: listen to history after navigation, then push the previous URL back; the
user can see state flicker or lose form data before confirmation.
### 6. Tests Required
- Playwright covers link navigation, browser back, reload and record switch.
- Assert cancel preserves URL and values; discard changes target once; save
removes the warning.
- Frontend typecheck and build after router or shared guard changes.
### 7. Wrong vs Correct
#### Wrong
```ts
window.addEventListener("popstate", () => navigate(previousUrl));
```
#### Correct
```ts
const blocker = useBlocker(isDirty);
// reset to keep editing; proceed only after explicit discard.
```
## Convention: Detail Evidence Layout
**What**: Detail pages use one evidence-first structure so users can understand