Session 15 (2026-05-07) docs update: STATUS.md: - Last updated Session 15 (1 commit `835cc7f` tooltip + working tree drastic refactor revert) - Recently Done row Session 15 chi tiết (diagnose + plan drastic + attempt 12 file edits + REVERT decision) HANDOFF.md: - TL;DR Session 15 prepend với 2 phần: Diagnose tooltip + Drastic refactor DEFER decision - 4 cảnh báo Session 16+: Drastic refactor pending (8-10h dedicated hoặc fallback Approach Y), Task 2 sample seed pending, schema-diagram defer cron audit, Hard blockers giữ nguyên migration-todos.md: - Phase 9 + Session 15 block với 1 task done (tooltip) + 1 defer (drastic refactor) + memory entry note - Defer Session 16+ list Session log NEW `2026-05-07-2600-tooltip-defer-drastic.md`: - Bối cảnh user UAT báo button silent disabled - Phần 1 — Diagnose tooltip (root cause + fix UX + "trùng ID" KHÔNG phải bug FE) - Phần 2 — Plan drastic refactor flat workflow → DEFER: * User spec mới (Phòng × Cấp × Users[] flat) * Plan 6 chunk + estimate scope realistic ~8-10h * Attempt 12 file working tree edits → REVERT decision * Memory entry capture decision rule - Plan organization sau S15 (defer queue) Memory entry NEW `feedback_drastic_refactor_scope.md`: - Quy tắc: drastic refactor cần dedicated session, scope conservative 2x buffer - Anti-patterns mid-session big refactor + commit broken state - Defer pattern (revert working tree → document → memory entry → surface trade-off cho user) - Cross-ref `feedback_per_chunk_commit.md` discipline 🎉 Session 15 wrap-up. Cumulative since session start (13h17): 16 commit (1 button removal + 6 PE N-stage + 5 Contract N-stage + 1 3-button + 1 Session 14 wrap-up + 1 tooltip + 1 Session 15 wrap-up). Verify: dotnet test 96 pass + working tree clean. Defer Session 16+ priority order: 1. Drastic refactor flat workflow (dedicated session ~8-10h) OR fallback Approach Y (FE flat UI 5 phòng, 1-2h) 2. Task 2 sample data seed N-stage 3. Hard blockers Ops (UAT, SMTP, etc.) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
159 lines
7.4 KiB
Markdown
159 lines
7.4 KiB
Markdown
# Session 2026-05-07 (S15) — Tooltip diagnose "Lưu & Gửi Duyệt" + drastic refactor DEFER
|
||
|
||
**Dev:** Claude
|
||
**Duration:** ~1h
|
||
**Base commit:** `7c83ac8` (sau Session 14 wrap-up docs)
|
||
**Final commit:** `835cc7f` (+ working tree refactor revert)
|
||
**Total commits:** 1
|
||
|
||
## Bối cảnh
|
||
|
||
User UAT live screenshot phiếu PE Bản nháp "huy test 1" (PE/2026/A/004) trên `eoffice.solutions.com.vn/purchase-evaluations/workspace?type=1&id=...`. Báo button "Lưu & Gửi Duyệt" KHÔNG hoạt động + suy đoán "Hình nó đang bị trùng ID với thằng khác? Mỗi lần tạo mới Phiếu Duyệt NCC là 1 phiếu độc lập nhé".
|
||
|
||
## Phần 1 — Diagnose tooltip (commit `835cc7f`)
|
||
|
||
### Root cause analysis
|
||
|
||
`PeDetailTabs.tsx` line 220: `disabled={!canSubmitForApproval || submitForApproval.isPending}`. Khi `canSubmitForApproval=false` button visually clickable nhưng không fire onClick → user không biết tại sao silent.
|
||
|
||
`canSubmitForApproval = mode === 'workspace' && canEditPhase && !readOnly && evaluation.workflow.nextPhases.some(p => p !== TuChoi && p !== TraLai)`.
|
||
|
||
Hypothesis: phiếu pin `WorkflowDefinitionId` của 1 version cấu hình thiếu adjacent step → `policy.NextPhasesFrom(DangSoanThao)` empty (legacy data hoặc admin chưa setup workflow).
|
||
|
||
### Fix UX (PeDetailTabs.tsx, fe-admin + fe-user mirror)
|
||
|
||
```javascript
|
||
const forwardPhase = evaluation.workflow.nextPhases.find(p =>
|
||
p !== TuChoi && p !== TraLai)
|
||
const canSubmitForApproval = mode === 'workspace' && canEditPhase && !readOnly && forwardPhase != null
|
||
|
||
const submitDisabledReason = !canEditPhase
|
||
? `Phiếu đã ở phase X — chỉ Bản nháp / Trả lại mới sửa + gửi được.`
|
||
: readOnly
|
||
? 'Chế độ chỉ đọc.'
|
||
: !forwardPhase
|
||
? `Workflow không có phase tiếp theo từ X. Liên hệ admin kiểm tra cấu hình quy trình.`
|
||
: null
|
||
```
|
||
|
||
Button:
|
||
- `title={submitDisabledReason ?? "Gửi phiếu sang \"<forward phase label>\""}` — hover tooltip show reason hoặc forward phase
|
||
- Dialog confirm thay text generic "Gửi phiếu vào quy trình duyệt?" → explicit "Sẽ chuyển sang \"Chờ Purchasing\". Sau khi gửi sẽ KHÔNG sửa được nữa (trừ khi approver Trả lại)."
|
||
|
||
Mirror fe-admin + fe-user. KHÔNG đụng BE.
|
||
|
||
Build pass cả 2 app.
|
||
|
||
### "Trùng ID" KHÔNG phải bug FE
|
||
|
||
`PurchaseEvaluationWorkspacePage.tsx` URL state đúng:
|
||
- `+ Thêm mới` → `setParams({ mode: 'new', id: null })`
|
||
- POST tạo phiếu → BE gen new GUID + MaPhieu mới (atomic SERIALIZABLE qua `PurchaseEvaluationCodeGenerator`)
|
||
- Save → URL set `id=<new>` thay thế
|
||
|
||
Mỗi PE row unique GUID + MaPhieu (UNIQUE filtered). Không có path share ID. User suy đoán có thể do button silent disabled → tưởng load lại record cũ.
|
||
|
||
## Phần 2 — Plan drastic refactor flat workflow → DEFER
|
||
|
||
User chốt drastic refactor: "bỏ phase enum hoàn toàn, dùng ChoDuyet=10 đơn nhất + currentStepIndex tracking".
|
||
|
||
### Spec mới (theo user)
|
||
|
||
Workflow = list flat (Phòng × Cấp × Users[]). Ví dụ Quy trình A:
|
||
- Phòng A (2 cấp): cấp 1 NV A, cấp 2 NV B
|
||
- Phòng B (3 cấp): cấp 1 NV C, cấp 2 [NV D 1, D 2, D 3], cấp 3 NV E
|
||
- Phòng C (1 cấp): NV C
|
||
|
||
Rules:
|
||
- Phòng 1 cấp → 1 user duyệt = pass phòng đó
|
||
- Phòng N cấp → tuần tự cấp 1 → 2 → ... → N
|
||
- Cùng cấp + cùng phòng = OR (1 user duyệt = pass cấp)
|
||
- Hết tất cả phòng → DaDuyet
|
||
- PE pin Quy trình ID, không thay đổi giữa chừng
|
||
|
||
### Plan refactor 6 chunk (theo `feedback_per_chunk_commit.md`)
|
||
|
||
| Chunk | Scope | Estimate |
|
||
|---|---|---|
|
||
| A | Domain enum + entity changes + Migration 21 | 50min |
|
||
| B | App CQRS + Policy registry rewrite | 45min |
|
||
| C | PE Service rewrite TransitionAsync flat | 2-3h |
|
||
| D | Contract Service rewrite + Tests update (drop 12 N-stage tests) | 1.5h |
|
||
| E | FE Designer flat UI (PeWorkflowsPage + WorkflowsPage) | 1.5h |
|
||
| F | FE PeWorkflowPanel + Docs | 1h |
|
||
|
||
**Tổng realistic:** ~8-10h focused. Vượt session boundary + risk session deep ~30 commits.
|
||
|
||
### Attempt → REVERT
|
||
|
||
Edit working tree 12 file (Chunk A partial):
|
||
- `PurchaseEvaluationPhase.cs`: + ChoDuyet=10 enum value
|
||
- `ContractPhase.cs`: + ChoDuyet=10
|
||
- `PurchaseEvaluation.cs`: + CurrentWorkflowStepIndex, RejectedAtStepIndex
|
||
- `Contract.cs`: + same 2 fields
|
||
- `WorkflowDefinition.cs` (Contract): drop class WorkflowStepInnerStep + nav, WorkflowStep + DepartmentId, PositionLevel
|
||
- `PurchaseEvaluationWorkflowDefinition.cs`: same pattern
|
||
- `ContractDepartmentApproval.cs`: drop InnerStepId
|
||
- `PurchaseEvaluationDepartmentApproval.cs`: drop InnerStepId
|
||
- `WorkflowDefinitionConfiguration.cs`: drop InnerStep config + add DeptId/PositionLevel cấu hình + FK Restrict
|
||
- `PurchaseEvaluationConfiguration.cs`: same
|
||
- `DepartmentApprovalsConfiguration.cs`: drop InnerStepId FK + filtered indexes, restore simple unique non-filtered
|
||
- `ApplicationDbContext.cs`: drop DbSet<*WorkflowStepInnerStep> × 2
|
||
|
||
Realize codebase chưa compile (Service + App + Tests dùng `WorkflowStepInnerStep` đã drop). Need rewrite ALL dependent code trong cùng Chunk A → blow scope vượt session.
|
||
|
||
**Decision REVERT** working tree về `835cc7f` clean. Tests 96 pass intact.
|
||
|
||
### Memory entry mới
|
||
|
||
`feedback_drastic_refactor_scope.md` — decision rule: drastic refactor cần dedicated session với context fresh, scope estimation conservative (2x buffer), tránh mid-session big refactor (risk session context deep + breaking states giữa chunk + tests rewrite biggest risk).
|
||
|
||
## Verify
|
||
|
||
- ✅ `git restore` 12 files reverted
|
||
- ✅ `dotnet test` 96 pass (54 + 42) — state intact
|
||
- ✅ working tree clean (chỉ 2 untracked .zip backup files)
|
||
- ✅ commit `835cc7f` (tooltip) pushed gitea OK
|
||
|
||
## Stats cumulative (sau Session 15)
|
||
|
||
| | Trước S15 | Sau S15 | Diff |
|
||
|---|---:|---:|---:|
|
||
| BE LOC | ~15800 | ~15800 | 0 (FE-only commit + revert) |
|
||
| Migrations | 20 | 20 | 0 |
|
||
| DB tables | 57 | 57 | 0 |
|
||
| FE pages | 32 | 32 | 0 |
|
||
| Tests | 96 | 96 | 0 |
|
||
| Docs | ~58 | ~59 | +1 (session log này) |
|
||
| Memory entries | 11 | **12** | +1 (drastic refactor scope) |
|
||
| Commits S15 | — | **+1** | `835cc7f` |
|
||
|
||
## Plan organization sau Session 15
|
||
|
||
```
|
||
Plan cha: Phase 9 active — UAT
|
||
├── Plan con A-S14: Tất cả ✅ DONE (xem session logs trước)
|
||
├── Plan con S15: Tooltip diagnose + drastic refactor DEFER
|
||
│ ├── ✅ FE PE button "Lưu & Gửi Duyệt" tooltip + dialog reason rõ
|
||
│ └── ⏸ Drastic refactor flat workflow — DEFER session sau (~8-10h)
|
||
└── Plan con Defer S16+:
|
||
├── Drastic refactor flat workflow (Mig 21, ~8-10h, dedicated session)
|
||
│ OR fallback Approach Y (FE flat UI giới hạn 5 phòng, 1-2h)
|
||
├── Task 2 sample data seed N-stage (block DesignTime vs Runtime DB)
|
||
├── Budget N-stage (cần migration `AddBudgetVersionedWorkflow`)
|
||
├── schema-diagram §17-19 Mig 18-20 (defer cron audit 2026-06-01)
|
||
└── Hard blockers Ops (UAT, SMTP, Rotate creds, SQL backup, Remove huypham.vn, win-acme)
|
||
```
|
||
|
||
## Handoff
|
||
|
||
UAT iteration mode. Phiếu PE Bản nháp giờ có tooltip rõ reason khi không gửi được. User test hover → biết admin cần kiểm tra cấu hình workflow definition.
|
||
|
||
Drastic refactor pending dedicated session. Khi resume:
|
||
1. Fresh session start với context clean
|
||
2. Plan kỹ 6 chunk per-commit
|
||
3. Buffer 2x estimate (~16h thực tế nếu phát sinh)
|
||
4. Test rewrite biggest risk — pattern reusable nhưng nội dung phải mới hoàn toàn
|
||
|
||
**Cron audit kế:** 2026-06-01 (~25 ngày).
|