[CLAUDE] Docs: chốt Session 18 wrap-up — PE V2 polish + Clone B + Mig 25 IsUserSelectable + 4 bug fix UAT
Session 18 (16:56 → 19:45, 7 commit `aaa1c6c` → `32a8d4d`): - B1 Pe Duyệt filter cứng "Đã gửi duyệt" - B2 HistoryTab filter Trả lại / Gửi lại - B3 Clone V2 cho B (DuyetNccPhuongAn) — audit reuse pattern - B4 Fix silent 403 ApprovalWorkflowsV2Controller - B5 Fix sidebar highlight queryMatches transient keys - B6 Mig 25 IsUserSelectable + Designer pin toggle + bỏ "(clone)" + Workspace filter - B7 Cleanup orphan zip files Updates: - STATUS — header 24→25 mig + 43→44 gotcha + 1 row Recently Done top + session log link - HANDOFF — TL;DR S18 đầy đủ + cảnh báo S19+ (giữ S17 narrative §6.5) - CLAUDE.md root — count 25 mig + Mig 25 description block - schema-diagram §14 — heading 22→25 + cột IsUserSelectable + filter logic section + Pending S19+ Mig 26/27 - gotchas — +#44 silent 403 + checklist debug 21 - migration-todos — Phase 9 S18 done section - session log mới đầy đủ E2E narrative Stats: 25 mig, 58 tables, ~141 endpoints, 81 test pass (no change), 44 gotcha, 14 memory entries, 6 skill, 7 commit S18. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -157,6 +157,38 @@ Session log: `2026-04-28-chot-session-4-budget.md`.
|
||||
|
||||
## 📝 Phase 9 — UAT + Ops + carry over (Session 6+ active)
|
||||
|
||||
### ✅ Session 18 done (2026-05-08 19:45) — PE V2 polish + Clone B + Mig 25 IsUserSelectable + 4 bug fix UAT (7 commit `aaa1c6c` → `32a8d4d`)
|
||||
|
||||
User UAT live tiếp Session 17, chuỗi polish nhỏ + clone V2 cho type B. Áp memory `feedback_uat_skip_verify` (skip dotnet test mỗi chunk, push ngay) + lesson rename/remove → bắt buộc `npm run build`.
|
||||
|
||||
- [x] **B1 (`aaa1c6c`) Pe Duyệt filter cứng "Đã gửi duyệt"** — bỏ dropdown trạng thái + filter cứng client-side `getPeDisplayStatus === DaGuiDuyet`. Hint amber "Lọc cố định". Workaround BE /inbox loose UAT trả phiếu Nháp (phân quyền strict V2 pending).
|
||||
|
||||
- [x] **B2 (`917446d`) HistoryTab filter Trả lại / Gửi duyệt lại** — FE filter (BE keep audit data đầy đủ): chỉ events Workflow Transition về TraLai (phaseAtChange=98) + từ TraLai (summary "TraLai →") + sửa nội dung khi phaseAtChange=TraLai.
|
||||
|
||||
- [x] **B3 (`937eb24`) Clone V2 cho B (DuyetNccPhuongAn)** — Audit reuse trước thay vì duplicate. Schema chung qua ApplicableType discriminator → chỉ 3 file ~60 LOC: MenuKeys.cs +const + All array, DbInitializer.SeedMenusAsync +leaf B (Order=2) + new SeedSampleApprovalWorkflowsV2Async (idempotent skip nếu admin đã tạo workflow B), fe-admin/menuKeys.ts +const. Memory `feedback_audit_reuse_before_clone.md` capture pattern.
|
||||
|
||||
- [x] **B4 (`f77ea38`) Fix silent 403 ApprovalWorkflowsV2** — Drafter `nv.test` Workspace dropdown empty silent. Root: class-level `[Authorize(Policy = "Workflows.Read")]` → non-admin 403, TanStack Query catch silent. Fix: class-level `[Authorize]` only, GET cho any authenticated; POST/DELETE giữ `Workflows.Create` admin-only. Gotcha #44.
|
||||
|
||||
- [x] **B5 (`a9c0857`) Fix sidebar highlight queryMatches transient keys** — Click row → URL có id transient → exact-set mismatch → menu unhighlight. Fix: `TRANSIENT_QUERY_KEYS = {id, q, editHeader, page, phase, awId}` strip trước compare. Mirror fe-admin + fe-user Layout.tsx.
|
||||
|
||||
- [x] **B6 (`2a53107`) Mig 25 + Designer pin toggle + bỏ "(clone)" + Workspace filter** — Migration 25 `AddIsUserSelectableToApprovalWorkflows`: ALTER `IsUserSelectable bit` + Sql backfill `WHERE IsActive=1 SET 1`. Domain +property. DTO +field. CreateAwDefinitionCommand set default true. New SetAwUserSelectableCommand + Handler. API PATCH `/api/approval-workflows-v2/{id}/user-selectable`. DbInitializer SeedSample +`IsUserSelectable=true`. FE Designer +badge "Cho user chọn" + button Ghim/Bỏ ghim + mutation toggleSelectable. Designer name auto-fill bỏ "(clone)" suffix. FE Workspace fetch filter `w.isUserSelectable === true` (cả fe-admin + fe-user).
|
||||
|
||||
- [x] **B7 (`32a8d4d`) Cleanup orphan zip** — `.claude.zip + docs.zip` lỡ tay vào commit B6 (`git add -A`). Untrack + add `*.zip` rule .gitignore.
|
||||
|
||||
**Stats final Session 18:** 25 mig (+1), 58 DB tables (no new — Mig 25 chỉ ALTER cột), ~141 endpoints (+1 PATCH), 33 FE pages, **81 test pass** (no change — feature mới UAT defer test §7), 44 gotcha (+1 #44 silent 403). Memory +1 entry.
|
||||
|
||||
**Defer Session 19+:**
|
||||
|
||||
- [ ] **Contract V2 wire (Mig 26)** — mirror PE pattern: thêm `Contract.ApprovalWorkflowId` + `CurrentApprovalLevelOrder` + `ContractWorkflowService.ApproveV2Async` + Workspace Select V2 trong ContractCreatePage. Pin V2 mặc định cho ContractType.
|
||||
- [ ] **Phân quyền strict V2** — hiện loose UAT (mọi authenticated thấy mọi phiếu V2). List = Drafter + approver any-Step + Admin. Cũng giải quyết bug "/inbox loose trả phiếu Nháp" — sau khi BE filter strict, B1 FE filter có thể relax.
|
||||
- [ ] **Drop legacy V1 (Mig 27 cleanup)** sau khi không còn phiếu pin `WorkflowDefinitionId` (V1): drop `WorkflowDefinitions` + `WorkflowSteps` + `WorkflowStepApprovers` + drop deprecated columns `RejectedAtStepIndex` / `RejectedFromPhase`. Drop `ApproveV1LegacyAsync` branch trong Service.
|
||||
- [ ] **Test V2 Service wire** (defer khi UAT confirm + có sample data thật) — Domain test ApproveV2Async + match logic + TraLai entry → Cấp 1 reset.
|
||||
- [ ] **Budget V2 wire** (defer xa hơn — sau Contract V2)
|
||||
- [ ] **Sample seed B** — sau UAT có thể remove (admin đã tạo workflow thật), hoặc giữ làm fallback. Idempotent skip không clobber.
|
||||
- [ ] **schema-diagram §17-21 Mig 18-21** vẫn chưa update (defer cron audit 2026-06-01)
|
||||
- [ ] **Skill `ef-core-migration` frontmatter** "21 migration" stale (thực 25). Defer cron audit 2026-06-01.
|
||||
- [ ] **Skill `dependency-audit-erp`** "26+/41 bẫy" stale (thực 44). Defer cron audit 2026-06-01.
|
||||
|
||||
### ✅ Session 17 done (2026-05-08) — PE Workflow V2 schema + Service wire end-to-end (Mig 22-24, 13 commit `c847dc0` → `de0f38d`)
|
||||
|
||||
User chốt sau Session 16 drastic refactor flat (Mig 21) vẫn chưa đúng intent. Yêu cầu schema riêng + Menu mới "Duyệt NCC (Mới)" — Quy trình > Bước (Phòng) > Cấp (NV cụ thể qua ApproverUserId). State machine 5 trạng thái với Trả lại = Phase RIÊNG (Option A user chốt diagram).
|
||||
|
||||
@ -0,0 +1,270 @@
|
||||
# Session 18 — 2026-05-08 (16:56 → 19:45) — PE V2 polish + Clone B + Mig 25 IsUserSelectable + 4 bug fix UAT
|
||||
|
||||
**Dev:** Claude
|
||||
**Duration:** ~2h49m
|
||||
**Base commit:** `8680f4c` (Session 17 wrap-up)
|
||||
**Final HEAD:** `32a8d4d`
|
||||
**Commits:** 7
|
||||
|
||||
## Bối cảnh
|
||||
|
||||
Tiếp Session 17 (PE V2 schema end-to-end DONE). User UAT live trên prod `eoffice.solutions.com.vn` test phiếu A (DuyetNcc), feedback chuỗi polish nhỏ + clone V2 cho type B (DuyetNccPhuongAn). Áp memory `feedback_uat_skip_verify` (skip dotnet test mỗi chunk, push ngay) + lesson hotfix CI `0ae3fe2` (rename/remove → bắt buộc `npm run build`).
|
||||
|
||||
7 batch deliverable theo thứ tự user feedback:
|
||||
|
||||
## B1 (`aaa1c6c`) — Pe Duyệt filter cứng "Đã gửi duyệt"
|
||||
|
||||
User: "Duyệt bỏ cái trạng thái đi, chỉ load những trạng thái 'Đã gửi duyệt' là đc."
|
||||
|
||||
Screenshot UAT cho thấy leaf "Duyệt" hiển thị 3 phiếu: 1 phiếu Nháp + 2 phiếu Đã gửi duyệt. Phiếu Nháp KHÔNG nên hiện ở leaf "Duyệt".
|
||||
|
||||
**Root cause:** `/purchase-evaluations/inbox` BE endpoint hiện loose UAT (mọi authenticated user thấy tất cả phiếu, không filter theo actor là approver Cấp hiện tại). Phân quyền strict V2 đã pending Session 19+.
|
||||
|
||||
**Fix FE-only (workaround):**
|
||||
- `PurchaseEvaluationsListPage.tsx` (cả fe-admin + fe-user):
|
||||
- Khi `pendingMe=true` → ẩn dropdown "Tất cả trạng thái", thay bằng hint amber "Lọc cố định: Đã gửi duyệt (phiếu đang chờ duyệt)"
|
||||
- Filter cứng client-side: `allRows.filter(p => getPeDisplayStatus(p.phase) === PeDisplayStatus.DaGuiDuyet)` — loại Nháp/Trả lại/Đã duyệt/Từ chối
|
||||
- Header count dùng `rows.length` khi `pendingMe` (inbox không paged, không phải `list.data?.total`)
|
||||
- `PurchaseEvaluationsListPage.tsx` cả 2 app: KHÔNG đụng dropdown ở Danh sách (`pendingMe=false`) — vẫn cho user filter mọi trạng thái
|
||||
|
||||
Verify: `npm run build` × 2 pass · 0 TS error.
|
||||
|
||||
## B2 (`917446d`) — HistoryTab filter Trả lại / Gửi duyệt lại
|
||||
|
||||
User: "Lịch sử thay đổi: Chỉ bắt các dòng thay đổi khi trả lại và gửi duyệt lại thôi nhé, không cần bắt trạng thái duyệt và các thay đổi trước khi trả lại."
|
||||
|
||||
**Approach:** FE filter (BE giữ audit data đầy đủ — reversible nếu user đổi ý / cần audit trail compliance / legal).
|
||||
|
||||
Logic giữ rows match một trong:
|
||||
- Workflow transition về TraLai: `entityType === 5 (Workflow) && phaseAtChange === 98 (TraLai)`
|
||||
- Workflow transition từ TraLai: `entityType === 5 && summary?.includes('TraLai →')`
|
||||
- Mọi thay đổi nội dung (Header/Detail/Supplier/Quote/Attachment) khi `phaseAtChange === 98`
|
||||
|
||||
Logic loại:
|
||||
- Workflow Approve cùng cấp/phase (Cấp 1→2→DaDuyet): `entityType === 5 && phaseAtChange ≠ 98 && summary KHÔNG chứa 'TraLai →'`
|
||||
- Sửa nội dung khi phase ≠ TraLai (lần soạn thảo gốc, ChoDuyet đầu)
|
||||
|
||||
Empty state: "Chưa có lịch sử trả lại / gửi duyệt lại."
|
||||
|
||||
Mirror `PeDetailTabs.tsx` HistoryTab fe-admin + fe-user.
|
||||
|
||||
## B3 (`937eb24`) — Clone V2 cho B (DuyetNccPhuongAn)
|
||||
|
||||
User: "OK đồng ý cứ giữ đúng thiết kế như thế này, hiện tại, tao chốt: Quy trình chọn thầu phụ - NCC → Duyệt NCC → Đã đúng chính xác với yêu cầu của tao. Plan cho tao kế hoạch clone toàn bộ các cập nhật từ lúc đổi lại quy trình → Đến thời điểm hiện tại và clone nó sang: Quy trình chọn thầu phụ - NCC → Duyệt NCC và Giải pháp."
|
||||
|
||||
**Audit reuse trước khi clone** — phát hiện 80% đã chung qua `ApplicableType` discriminator:
|
||||
|
||||
| Layer | Đã chung cho B? |
|
||||
|---|---|
|
||||
| Schema V2 (Mig 22-24) | ✅ `ApplicableType` enum 1=A / 2=B / 3=Contract |
|
||||
| BE Service `ApproveV2Async` | ✅ không hardcode type |
|
||||
| App CQRS `GetAwAdminOverview` / `CreateAwDefinition` / Validator | ✅ chung |
|
||||
| API `/api/approval-workflows-v2?applicableType=N` | ✅ dynamic |
|
||||
| FE Designer `ApprovalWorkflowsV2Page` | ✅ `TYPE_CODE_TO_INT` cả 3 type |
|
||||
| FE Layout regex `^AwV2_(.+)$` | ✅ match dynamic typeCode |
|
||||
| FE App.tsx route `:typeCode` | ✅ dynamic |
|
||||
| FE Workspace + List + Pending | ✅ chung qua `?type=N` |
|
||||
| Menu `Pe_DuyetNccPhuongAn_*` (List/Create/Pending) | ✅ đã seed Mig 12 |
|
||||
|
||||
Chỉ thiếu (3 file ~60 LOC):
|
||||
- `Domain/Identity/MenuKeys.cs` +const `ApprovalWorkflowDuyetNccPhuongAnV2 = "AwV2_DuyetNccPhuongAn"` + add vào `All[]`
|
||||
- `Infrastructure/Persistence/DbInitializer.cs`:
|
||||
- `SeedMenusAsync` +leaf "Duyệt NCC và Giải pháp (Mới)" (Order=2 cạnh leaf A Order=1) dưới root `ApprovalWorkflowsV2`
|
||||
- +method `SeedSampleApprovalWorkflowsV2Async` (idempotent — skip nếu admin đã tạo workflow B nào hoặc thiếu test user `nv.test@solutions.com.vn` / Phòng CCM):
|
||||
- Seed `QT-DN-PA-V2-001 v01` `IsActive=true`
|
||||
- 1 Bước "Phòng CCM" (DepartmentId resolve từ `Code="CCM"`)
|
||||
- 1 Cấp 1 NV: test user `nv.test@solutions.com.vn`
|
||||
- `fe-admin/src/lib/menuKeys.ts` +`AwV2_DuyetNccPhuongAn`
|
||||
|
||||
KHÔNG cần migration / Service code mới / Designer page mới. Memory mới `feedback_audit_reuse_before_clone.md` capture pattern.
|
||||
|
||||
User feedback: "OK khá tốt, 1 phát chạy luôn :))" → confirm approach worked.
|
||||
|
||||
## B4 (`f77ea38`) — Fix silent 403 ApprovalWorkflowsV2Controller
|
||||
|
||||
**Triệu chứng:** UAT user `nv.test` (Drafter) login Workspace tạo phiếu B → dropdown "Quy trình duyệt" empty mặc dù Admin Designer cùng URL endpoint thấy v01 sample + v02 admin clone đầy đủ. KHÔNG có toast error / network panel hint.
|
||||
|
||||
**Root cause:** `ApprovalWorkflowsV2Controller` class-level `[Authorize(Policy = "Workflows.Read")]` → non-admin role (Drafter chỉ có `PurchaseEvaluations.Read`) bị 403 Forbidden khi GET `/api/approval-workflows-v2`. TanStack Query catch HTTP error trả `data=undefined`, FE component render dropdown empty không có "loading" / "error" state visible → silent fail.
|
||||
|
||||
**Fix:**
|
||||
```csharp
|
||||
[ApiController]
|
||||
[Route("api/approval-workflows-v2")]
|
||||
[Authorize] // ← any authenticated, không hardcode policy
|
||||
public class ApprovalWorkflowsV2Controller(IMediator mediator) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<...> Overview(...) { ... } // ← inherit class policy = any authenticated
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = "Workflows.Create")] // ← admin Designer
|
||||
public async Task<...> Create(...) { ... }
|
||||
|
||||
[HttpPatch("{id:guid}/user-selectable")]
|
||||
[Authorize(Policy = "Workflows.Create")]
|
||||
public async Task<...> SetUserSelectable(...) { ... } // (added at B6)
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
[Authorize(Policy = "Workflows.Create")]
|
||||
public async Task<...> Delete(...) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
Pattern reusable cho Contract V2 Mig 26 sau (cùng controller). Add gotcha #44.
|
||||
|
||||
## B5 (`a9c0857`) — Fix sidebar highlight queryMatches transient keys
|
||||
|
||||
**Triệu chứng:** Ở leaf "Danh sách" `/purchase-evaluations?type=1`, click chọn 1 phiếu → URL thành `?type=1&id=abc` → leaf bị mất highlight box (gotcha #34 cũ tái phát theo cách khác).
|
||||
|
||||
**Root cause:** `queryMatches` exact-set equality:
|
||||
```ts
|
||||
if (aKeys.length !== bKeys.length) return false
|
||||
```
|
||||
target `{type}` (1 key) vs current `{type, id}` (2 keys) length mismatch → no match.
|
||||
|
||||
**Fix:**
|
||||
```ts
|
||||
const TRANSIENT_QUERY_KEYS = new Set(['id', 'q', 'editHeader', 'page', 'phase', 'awId'])
|
||||
|
||||
function queryMatches(current, target) {
|
||||
const a = new URLSearchParams(current)
|
||||
const b = new URLSearchParams(target)
|
||||
const aKeys = [...a.keys()].filter(k => !TRANSIENT_QUERY_KEYS.has(k)).sort()
|
||||
const bKeys = [...b.keys()].filter(k => !TRANSIENT_QUERY_KEYS.has(k)).sort()
|
||||
if (aKeys.length !== bKeys.length) return false
|
||||
return aKeys.every((k, i) => bKeys[i] === k && a.get(k) === b.get(k))
|
||||
}
|
||||
```
|
||||
|
||||
Strip transient state keys (selection / search / filter / pagination) → giữ navigation identity (`type`, `pendingMe`, `mode`) check exact-set như cũ.
|
||||
|
||||
Edge cases verified:
|
||||
|
||||
| URL hiện tại | Target leaf | Match |
|
||||
|---|---|---|
|
||||
| `?type=1&id=abc` | Danh sách `?type=1` | ✓ giữ highlight |
|
||||
| `?type=1&pendingMe=1` | Danh sách `?type=1` | ✗ distinct (không cross-highlight Pending) |
|
||||
| `?type=1&phase=10` | Danh sách `?type=1` | ✓ giữ highlight (filter dropdown) |
|
||||
| `?type=1&pendingMe=1&awId=xyz` | Duyệt `?type=1&pendingMe=1` | ✓ giữ highlight |
|
||||
|
||||
Mirror fe-admin + fe-user `Layout.tsx`.
|
||||
|
||||
## B6 (`2a53107`) — Mig 25 IsUserSelectable + Designer pin toggle + bỏ "(clone)" + Workspace filter
|
||||
|
||||
User feedback Admin Designer (screenshot v01 sample + v02 + v03 admin clone): "Bỏ chữ Clone đi nhé, ghi v02, v03... là đủ rồi, khi tao kế thừa tạo quy trình mới. Thêm cho tao nút stick để chọn các quy trình nào mà User đc select bên ngoài khi tạo phiếu."
|
||||
|
||||
**Bỏ "(clone)" auto-suffix:**
|
||||
- `fe-admin/ApprovalWorkflowsV2Page.tsx` Designer line 403: `name = cloneFrom.name` (giữ nguyên), không append " (clone)". Version số (v02, v03, ...) đã đủ phân biệt.
|
||||
|
||||
**Pin toggle "Cho user chọn":**
|
||||
|
||||
Decision approach: Schema field riêng `IsUserSelectable` thay vì reuse `IsActive`. Lý do:
|
||||
- `IsActive` semantic = "đang áp dụng (default new version)" — max 1 per ApplicableType (atomic deactivate ở `CreateAwDefinitionCommand`)
|
||||
- User yêu cầu "chọn các quy trình nào" — implies multiple → cần multi-select field độc lập
|
||||
- Default behavior không break: backfill `IsUserSelectable=1 WHERE IsActive=1` giữ active workflows visible cho user
|
||||
|
||||
**Migration 25** `AddIsUserSelectableToApprovalWorkflows`:
|
||||
```sql
|
||||
ALTER TABLE ApprovalWorkflows ADD IsUserSelectable bit NOT NULL DEFAULT 0;
|
||||
UPDATE ApprovalWorkflows SET IsUserSelectable = 1 WHERE IsActive = 1; -- backfill
|
||||
```
|
||||
|
||||
3-file rule commit đủ (.cs + Designer + Snapshot).
|
||||
|
||||
**BE:**
|
||||
- Domain `ApprovalWorkflow.IsUserSelectable` property — independent với `IsActive`
|
||||
- DTO `AwDefinitionDto` +field
|
||||
- `CreateAwDefinitionCommand` Handler set default `IsUserSelectable = true` cho version mới (mirror IsActive default)
|
||||
- New `SetAwUserSelectableCommand(Guid Id, bool IsUserSelectable)` + Handler — toggle stick/unstick
|
||||
- API endpoint `PATCH /api/approval-workflows-v2/{id}/user-selectable` (policy `Workflows.Create` admin only)
|
||||
- `DbInitializer.SeedSampleApprovalWorkflowsV2Async` set `IsUserSelectable = true` cho sample
|
||||
|
||||
**FE Designer (`fe-admin/ApprovalWorkflowsV2Page.tsx`):**
|
||||
- `DefinitionDto` +field `isUserSelectable: boolean`
|
||||
- `TypePanel` +mutation `toggleSelectable` call PATCH endpoint, invalidate query
|
||||
- `DefinitionCard` props +`onToggleSelectable: () => void`
|
||||
- Badge amber "📌 Cho user chọn" (lucide `Pin` icon) cạnh Đang áp dụng/Archived khi `def.isUserSelectable === true`
|
||||
- Button "📌 Ghim cho user / 🚫 Bỏ ghim" (lucide `Pin` / `PinOff`) trong action group
|
||||
|
||||
**FE Workspace (cả fe-admin + fe-user `PeWorkspaceCreateView.tsx`):**
|
||||
- `approvalWorkflows` useQuery filter `(typeBucket?.history ?? []).filter(w => w.isUserSelectable)` — chỉ workflows admin đã ghim hiển thị dropdown user
|
||||
|
||||
## B7 (`32a8d4d`) — Cleanup orphan zip files
|
||||
|
||||
`.claude.zip` + `docs.zip` từ Claude harness session start (orphan dump untracked). B6 commit `git add -A` lỡ tay cuốn cả 2 file.
|
||||
|
||||
Fix:
|
||||
- `git rm --cached` 2 file
|
||||
- `rm -f` xóa local
|
||||
- Add `*.zip` rule vào `.gitignore`
|
||||
- Commit cleanup
|
||||
|
||||
## E2E verified
|
||||
|
||||
- ✅ `dotnet build SolutionErp.slnx` 0 error
|
||||
- ✅ `dotnet test SolutionErp.slnx` **81 pass** (58 Domain + 23 Infra) — no change S18 (feature mới UAT defer test §7)
|
||||
- ✅ `dotnet ef migrations add AddIsUserSelectableToApprovalWorkflows` 3-file rule OK
|
||||
- ✅ Migration 25 apply LocalDB OK qua `DbInitializer.MigrateAsync` startup
|
||||
- ✅ `npm run build` × fe-admin + fe-user pass mỗi commit có FE changes
|
||||
- ✅ CI deploy commit B6 `2a53107` success (Gitea Actions)
|
||||
- ✅ User UAT confirm B chạy 1 phát đúng (commit `937eb24`)
|
||||
- ✅ User UAT confirm Designer toggle pin work (manual test sau commit B6)
|
||||
|
||||
## Bug gặp + fix
|
||||
|
||||
| Bug | Fix |
|
||||
|---|---|
|
||||
| Drafter Workspace dropdown V2 empty silent (Workflows.Read 403) | Class-level `[Authorize]` only, GET cho any authenticated (B4) |
|
||||
| Sidebar leaf mất highlight khi click row (URL có id transient) | Strip TRANSIENT_QUERY_KEYS trước queryMatches compare (B5) |
|
||||
| Phiếu Nháp lọt vào leaf "Duyệt" (BE /inbox loose UAT) | FE filter cứng `getPeDisplayStatus === DaGuiDuyet` (B1, workaround) |
|
||||
| Workspace dropdown hiện cả archived versions (UX không rõ admin pick gì cho user) | Mig 25 `IsUserSelectable` + Designer pin toggle + Workspace filter (B6) |
|
||||
| Designer auto-fill "(clone)" suffix khi clone version (xấu, version đã đủ phân biệt) | `name = cloneFrom.name` (B6) |
|
||||
| 2 file `.zip` orphan vào commit B6 (`git add -A`) | `git rm --cached` + `*.zip` .gitignore (B7) |
|
||||
|
||||
## Docs updates
|
||||
|
||||
- `docs/STATUS.md` — header 24→25 mig + 43→44 gotcha + 1 row Recently Done Session 18 (top)
|
||||
- `docs/HANDOFF.md` — TL;DR Session 18 mới + cảnh báo Session 19+ (giữ TL;DR S17 nguyên văn theo §6.5 không cắt narrative)
|
||||
- `CLAUDE.md` (root) — count 24→25 mig + Mig 25 description block
|
||||
- `docs/database/schema-diagram.md §14` — heading "Migration 22-24" → "22-25" + +cột `IsUserSelectable` + section "IsUserSelectable filter logic" + Pending Session 19+ update Mig 26/27
|
||||
- `docs/gotchas.md` — +#44 silent 403 from over-restrictive Authorize policy + checklist debug item 21
|
||||
- `docs/changelog/migration-todos.md` — Phase 9 Session 18 done section đầy đủ + Defer Session 19+ checklist
|
||||
- `docs/changelog/sessions/2026-05-08-1945-s18-pe-v2-polish-clone-b.md` — file này
|
||||
|
||||
KHÔNG đụng (per §6.5 không cố sửa khi không cần):
|
||||
- `docs/rules.md` — không có rule mới
|
||||
- `docs/architecture.md` — không có changes structural
|
||||
- `docs/PROJECT-MAP.md` — không có structural changes
|
||||
- `docs/workflow-contract.md` — Contract V2 chưa wire (S19+)
|
||||
- `docs/forms-spec.md` — không liên quan
|
||||
- `docs/database/database-guide.md` — count migration không hardcode trong header
|
||||
- Skills (6) — không tạo mới, không refresh; drift ef-core-migration / dependency-audit-erp defer cron audit 2026-06-01
|
||||
|
||||
## Memory updates
|
||||
|
||||
- ✅ Add `feedback_audit_reuse_before_clone.md` (commit `937eb24` block context, B3 confirm pattern). MEMORY.md index +1 row.
|
||||
|
||||
## Handoff to Session 19+
|
||||
|
||||
Đọc `docs/HANDOFF.md` "## ⚠️ Điều quan trọng cho Session 19+" cho 6 cảnh báo đầy đủ.
|
||||
|
||||
Top priorities:
|
||||
1. **Contract V2 wire (Mig 26)** — apply audit-reuse pattern, mirror PE
|
||||
2. **Phân quyền strict V2** — list/inbox/detail filter theo actor role + approver scope
|
||||
3. **Drop legacy V1 cleanup (Mig 27)** sau khi không còn phiếu pin V1
|
||||
|
||||
## Thông số cumulative
|
||||
|
||||
| | Trước S18 | Sau S18 | Δ |
|
||||
|---|---:|---:|---:|
|
||||
| Migrations | 24 | **25** | +1 |
|
||||
| DB tables | 58 | 58 | 0 (Mig 25 chỉ ALTER cột) |
|
||||
| API endpoints | ~140 | **~141** | +1 PATCH user-selectable |
|
||||
| FE pages | 33 | 33 | 0 (modify existing) |
|
||||
| Test pass | 81 | 81 | 0 (UAT defer test §7) |
|
||||
| Gotchas | 43 | **44** | +1 #44 silent 403 |
|
||||
| Memory entries | 13 | **14** | +1 audit reuse pattern |
|
||||
| Skills | 6 | 6 | 0 |
|
||||
| Commits | (after S17) | **+7** | aaa1c6c → 32a8d4d |
|
||||
| BE LOC | ~16100 | ~16200 | +~100 (Mig 25 + Set command + endpoint + sample seed) |
|
||||
| FE LOC | ~17500 | ~17600 | +~100 (Designer pin toggle + Workspace filter + filter helpers) |
|
||||
Reference in New Issue
Block a user