Files
solution-erp/.claude/agent-memory/database-agent/MEMORY.md
2026-07-29 19:44:56 +07:00

39 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# database-agent — MEMORY (L1 HOT)
- **S161 (07-29) W1 KHKK design-review Mig 69 `[hmw wf_a95c9909-14b · return CLEAN + sub-md 21KB]`:** **PASS 8/8 + DB11, 0 blocker** — Mig `20260729122015_AddContractSigningPlans` 7 CreateTable/20 CreateIndex/0 ALTER. Phép đo đáng giữ làm khuôn review sau: (1) **Down-proof KHÔNG destructive**: `dotnet ef migrations script <mig> <prev> --no-build` sinh script Down atomic (1 transaction) — thay cho apply-rollback thật trên DB đang dùng (DB2); (2) **đo `sys.foreign_keys`/`sys.indexes.filter_definition`/`sys.columns.max_length` thay đọc code** — nvarchar max_length = BYTE = 2× ký tự; (3) **multiple-cascade-path né bằng loose-Guid+HasIndex** (Attachments.DossierItemId — FK Cascade ở đó = err 1785 từ chối CREATE); (4) **snapshot-drift check rẻ**: diff Designer-vs-Snapshot bỏ blank/comment → chỉ được phép lệch header (Migration attr/BuildTargetModel); (5) **twin-parity làm chuẩn thiếu-index**: 4 cột không IX đều parity PE (cột hiển thị không vào WHERE site nào đã wire); LevelOpinions unique KHÔNG filter = ĐÚNG (đo cả 2 twin PE/Contract cùng dạng — UPSERT 1-row-per-level); (6) IX_SlaDeadline VẮNG là ĐÚNG (SlaExpiryJob chỉ quét Contracts; entity tự khai SLA=display-only) — index không job quét = index chết; (7) parity 2 DB LocalDB: TABLECOUNT 96 ×2 + MIGTOP ×2 + IXCOUNT 27 (=20 IX + 7 PK) khớp 1:1 file. Rủi ro khai: SERIALIZABLE read-modify-write có thể deadlock 1205 fail-safe (parity 4 module Office prod). Tag `[s161, mig69-review, down-script-proof-no-destructive, sys-catalog-over-code, twin-parity-index-baseline]`
> READ-advisory DB specialist SOLUTION_ERP (.NET 10 EF Core 10 + SQL Server, single `ApplicationDbContext` dbo). Adopt AI_INFRA broadcast `2026-06-08-Agent-database-codebase-agents` (floor DB1DB11), S52 2026-06-08. Seed = em main. **Nấc hiện: executed-file — verified-runtime CHỜ anh restart CLI + spawn-test.**
## Vai trò (FORM tailored SE)
- **READ-advisory tier** — DESIGN/REVIEW/PERF/CONCURRENCY-advise, KHÔNG author file. `implementer-backend` author entity+config+migration; em main solo quyết schema-design cuối. database-agent = deep-DB lens hỗ trợ + review.
- Floor DB1DB11 (canonical, KHÔNG hạ) — chi tiết `.claude/agents/database-agent.md`.
- Skill: `sql-database-assistant` (SQL Server raw, KHÔNG cover EF-Core) + `ef-core-migration` (EF Core 10 pin + 3-file rule). Verify present TRƯỚC wire.
- `store_memory` STRIPPED → ghi finding vào FILE này; em main + re-index → RAG.
## SE facts cốt lõi (DB10 evidence-based — re-ground khi cần)
- **45 migration → 92 tables** (S51). `sys.tables` = ground-truth (narrative count drift "incremented-per-session" → re-ground).
- 2 DB instance: LocalDB `SolutionErp_Dev` (runtime) / `SolutionErp_Design` (design-time) — gotcha designtime-vs-runtime DB (apply migration cả 2 qua `--connection` override). Prod = `.\SQLEXPRESS\SolutionErp`.
- Soft-delete UNIQUE index PHẢI `.HasFilter("[IsDeleted]=0")` (gotcha #57 — 13× pattern; S45 Holiday + S51 LeaveType/Shift/OtPolicy/Vehicle/Driver). EXT backlog: Department/Supplier/Project (Mig 46 worktree).
- Codegen atomic = `WorkflowAppCodeGen.GenerateMaDonTuAsync` dùng `IsolationLevel.Serializable` tx (Prefix-keyed sequence) — pattern ĐÚNG tham chiếu cho concurrency.
## 🎯 DB11 gap đã biết (concurrency — vai trò chính)
- **S43/S56 LeaveBalance lost-update — FIX DESIGNED S56 (approach A, NO migration).** `ApproveLeaveRequestHandler` terminal DaDuyet branch (LeaveOtApprovalFeatures.cs:355-386) đọc `bal.UsedDays` in-memory + `+= p.NumDays` + bare SaveChanges → 2 concurrent terminal-approve cùng (User,Type,Year) lost-update. **Fix:** wrap terminal-branch trong explicit `BeginTransactionAsync` → (1) SaveChanges persist opinion-upsert + status=DaDuyet + ensure balance-row exists (insert UsedDays=0 nếu absent), (2) `ExecuteUpdateAsync(SET UsedDays = UsedDays + n)` atomic DB-side race-free, (3) Commit. Atomic-with-approval preserved (1 tx all-or-nothing). Exactly-once untouched (early `Status != DaGuiDuyet` guard :296). NO ambient TransactionBehavior (chỉ ValidationBehavior) → handler own tx boundary. **Cast `(DbContext)db` để reach Database** (IApplicationDbContext chỉ expose DbSet+SaveChangesAsync). Existing terminal test (Case 4 :226) assert Status/Level/opinion-count only — KHÔNG assert UsedDays-on-tracked → ExecuteUpdate (bypass tracker) WON'T break suite. Spec authoritative → implementer-backend author.
- OtRequest terminal KHÔNG trừ phép (chỉ status) → no lost-update bên OT.
- P11-D SLA flags (`SlaWarnedSent`/`SlaBreached`) + P11-F codegen = concurrency-sensitive → DB11 lens áp được.
## Boundary (⟂)
- vs implementer-backend: DESIGN/REVIEW vs AUTHOR (KHÔNG double-touch migration file).
- vs investigator-codebase: deep DB-layer (introspection/query-plan/concurrency) vs broad grep/audit.
- vs reviewer: DB-layer design-review (DB6/DB11/DB5) TRƯỚC author vs adversarial pre-commit cross-stack.
- KHÔNG: FE · business-logic · deploy · session-lifecycle audit.
## Accuracy (G-015)
- DB7 scope-DB-only = PHÂN-VAI, KHÔNG "read-only enforced" (giữ `Bash` → write-channel shell mở; containment = em main single-writer + git-diff post-session).
- Schema/perf-claim từ introspection THẬT (`sqlcmd`/`dotnet ef`), KHÔNG narrative.
## Log
- **S52 (2026-06-08):** Seeded (em main, adap-apply database-agent). Roster 10→11. Nấc executed-file. CHỜ restart + spawn-test → verified-runtime.
- **S56 (2026-06-09) — pre-golive verify (2nd real spawn, verified-runtime ✓):** Schema/Mig integrity P11 + S55 master-data = SOLID. Mig 42-48 applied IDENTICALLY Dev+Design+prod `.\SQLEXPRESS` (48 mig / 92 tables, **NO S53-style unapplied-local drift**); 0 pending model-snapshot diff; **9 gotcha-#57 filtered-unique** confirmed BOTH EF config (HasFilter×13) AND DB (`filter_definition=([IsDeleted]=(0))`) incl Vehicle/Driver day-1; FK đúng (LeaveBalance→LeaveType Restrict + UNIQUE(User,Type,Year); 4× LevelOpinions Cascade(parent)/Restrict(Level)+UNIQUE composite; ItTicket SLA nullable). **DB11 FAIL (1 major, fast-follow KHÔNG blocker):** `LeaveBalance.UsedDays += NumDays` @ `LeaveOtApprovalFeatures.cs:361-386` chạy bare SaveChanges (no tx / no RowVersion / READ COMMITTED) → concurrent double-approve lost-update. **S43 gap STILL OPEN.** Fix-pattern sẵn repo: Serializable tx (codegen `:34`) HOẶC RowVersion+retry (1 mig). Low-prob ~30 user, recoverable Admin Adjustment. Tag [s56, pre-golive-verify, schema-pass, db11-lostupdate-open].
- **S57bis (2026-06-11) — PE gắn Hạng mục design (3rd real spawn, DELIVERED — on-behalf em main ghi hộ, H2-proposed):** Introspect LocalDB → design `PurchaseEvaluations.WorkItemId Guid?` scalar **loose-Guid + IX, KHÔNG FK vật lý** — nhất quán convention PE (ProjectId/SelectedSupplierId đều loose; duy nhất ApprovalWorkflowId có FK). Guard = validator + handler mirror S43 FK-invariant. KHÔNG đụng CodeSequences (mã phiếu giữ `PE/{YYYY}/{A|B}/{Seq}`). LEARNED: PE FK-convention map (loose-Guid là norm module này — FK vật lý là exception). SURPRISE: WorkItems = catalog GLOBAL (KHÔNG ProjectId) → 2 dropdown độc lập; "Dự án (năm) Hạng mục" chỉ là chuỗi ghép hiển thị, không ràng buộc quan hệ. Ship: Mig 49 deploy Run #381 prod-applied. Tag `[s57bis, mig49-design, on-behalf]`.
- **S97 (2026-07-01) — PE prod-điều-tra A/005 + deep-review lane (4th+5th real spawn, on-behalf em main ghi hộ, H2-proposed @S98):** (4th) Điều tra prod (API+sqlcmd): A/005/A/008 Phase=7 `endsBeforeCeo=False`, lịch-sử 4 record dừng "[Bước 2 — Cấp 2]" KHÔNG có record CEO; đối chứng A/010 9-record có CEO. **Chẩn đoán:** A/005/A/008 finalize-CCM Cấp 2 (KHÔNG qua CEO) — lịch-sử ĐÚNG, sai là badge do `EndedByLevelFinalize=0` → phát hiện **Mig 60 backfill WRONG-TABLE** (query `Approvals.Comment` nhưng marker do `LogTransitionAsync:1073` ghi `Changelogs.ContextNote`) → dẫn tới Mig 61 + gotcha #79. (5th — `wf_4951c347` lane prod-data-integrity) **CLEAN:** flag-vs-marker 3 phiếu DaDuyet khớp (A/005/A/008=1+marker · A/010=0+no-marker), 0 miss/0 over-reach, Mig 60/61 applied, NCC=21, 0 orphan changelog, DB11 pointer-NULL đúng. LEARNED: **PE 2 bảng lịch-sử TÁCH VAI**`PurchaseEvaluationApprovals` = per-approver record (:745) vs `PurchaseEvaluationChangelogs.ContextNote` = transition+marker (`LogTransitionAsync:1073`); backfill PHẢI xác định đúng bảng-writer + verify marker-count prod TRƯỚC. SURPRISE: backfill=0 rows @ cicd #482 lẽ ra là CỜ ĐỎ nhưng bị bỏ qua ("tưởng no-pre-Mig60 data"). Evidence: `docs/changelog/sessions/2026-07-01-S97-pe-finalize-wording-default-flip.md:97-133`. Tag `[s97, mig60-wrongtable, gotcha79, prod-integrity-clean, on-behalf]`.