# Gotchas — SOLUTION_ERP > Bẫy/pitfall đã gặp + cách xử lý. Đọc trước khi debug tương tự để không mất thời gian. Cập nhật liên tục khi gặp bug mới. ## Tech stack constraints (.NET 10 + TS 6 + Vite 8) ### 1. MediatR 14.x không tương thích → pin 12.4.1 **Triệu chứng:** `Unable to resolve service for type 'MediatR.IMediator'` — `AddMediatR` vẫn chạy nhưng không register IMediator. **Fix:** Pin `MediatR 12.4.1`. Khi đó `RequestHandlerDelegate` là delegate không tham số (v14 có thêm CancellationToken). ### 2. Swashbuckle 10.x + Microsoft.OpenApi 2.x breaking change **Triệu chứng:** Build fail `The type or namespace 'Models' does not exist in 'Microsoft.OpenApi'`. Swagger 404. **Fix:** - Remove `Microsoft.AspNetCore.OpenApi` khỏi Api - Downgrade Swashbuckle về `6.9.0` ### 3. TypeScript 6 `erasableSyntaxOnly` cấm `enum` **Fix:** Dùng `const + as const + typeof[keyof]` pattern: ```ts export const SupplierType = { NhaCungCap: 1 } as const export type SupplierType = typeof SupplierType[keyof typeof SupplierType] ``` ### 4. TypeScript 6 deprecate `baseUrl` **Fix:** Bỏ `baseUrl` trong tsconfig, chỉ giữ `paths`. Paths resolve relative tsconfig location. ### 5. Node 22 local vs CI pin 20 **Bài học NamGroup:** CI build fail trên Node latest. **Fix:** - `package.json` engines: `">=20"` (min, không upper) - `.nvmrc` = `20` cho CI - GitHub/Gitea Actions: `actions/setup-node@v4` với `node-version: '20.x'` ## EF Core 10 ### 6. Expression tree không support switch expression **Triệu chứng:** `CS8514: An expression tree may not contain a switch expression`. **Fix:** Tách switch ra ngoài LINQ: ```csharp var hasPermission = action switch { "Read" => await query.AnyAsync(p => p.CanRead), "Create" => await query.AnyAsync(p => p.CanCreate), _ => false, }; ``` ### 7. Design-time DbContext resolve fail **Triệu chứng:** `dotnet ef migrations add` → `Unable to resolve service for type 'DbContextOptions'`. **Fix:** Tạo `IDesignTimeDbContextFactory` trong Infrastructure. ### 8. `AddDefaultTokenProviders()` không có trong `AddIdentityCore` **Fix:** Bỏ call nếu chưa cần password reset. Khi cần, chuyển `AddIdentity` hoặc add package `Microsoft.AspNetCore.Identity.UI`. ## OpenXml / ClosedXML ### 9. `SpaceProcessingModeValues` namespace **Fix:** Full path + wrap `EnumValue<>`: ```csharp textElement.Space = new DocumentFormat.OpenXml.EnumValue< DocumentFormat.OpenXml.SpaceProcessingModeValues>( DocumentFormat.OpenXml.SpaceProcessingModeValues.Preserve); ``` ### 10. Placeholder `{{field}}` bị split runs **Vấn đề:** Word hay split text thành nhiều `` — placeholder miss khi regex replace. **Fix:** Iterate Paragraph, gom text tất cả `` → replace → gán lại text đầu + clear rest. Đã implement trong `DocxRenderer`. ### 11. Word COM `SaveAs` PowerShell type conversion **Fix:** Dùng `SaveAs2`: ```powershell $doc.SaveAs2($outPath, 16) # 16 = wdFormatDocumentDefault ``` ### 12. Word COM stuck **Fix:** - `$word.DisplayAlerts = 0` - Nếu stuck → `Get-Process WINWORD | Stop-Process -Force` - Fallback: LibreOffice headless `soffice --headless --convert-to docx` ## System.Text.Json ### 13. Record deserialization fail với Unicode qua CLI **Triệu chứng:** POST JSON tiếng Việt từ Windows bash/curl → 400 "JSON value could not be converted". **Fix:** Dùng `curl --data-binary @file.json` (file UTF-8). API handle đúng qua axios/Swagger. ## File operations ### 14. Dropbox sync có thể revert file đang edit **Triệu chứng:** Write thành công, build pass, runtime chạy code cũ. **Fix:** Sau Write quan trọng → Read lại verify. Nếu revert → Write lại. ### 15. `.gitignore` wwwroot rules - `wwwroot/uploads/` → **ignore** (user files) - `wwwroot/templates/` → **commit** (source of truth) - `wwwroot/exports/` → ignore (temp) ## Dev workflow ### 16. Port conflict khi restart dev server **Fix:** `TaskStop` task cũ, hoặc `netstat -ano | findstr :8082` → `taskkill /F /PID `. ### 17. EF migration 3-file rule Mỗi migration tạo: `{name}.cs` + `{name}.Designer.cs` + `ApplicationDbContextModelSnapshot.cs`. Commit đủ 3. ## Claude Code harness quirks ### 18. Edit tool "File not read" sau system-reminder **Triệu chứng:** Edit file vừa Read, lỗi "File has not been read yet". **Nguyên nhân:** System reminder interrupt reset read-cache. **Fix:** Read lại file rồi Write/Edit. Hoặc dùng Write (ghi đè full) thay Edit. ### 19. Build pass nhưng DI thiếu registration **Triệu chứng:** `dotnet build` → 0 errors nhưng runtime throw `Unable to resolve service`. **Nguyên nhân:** C# compiler chỉ check type, không check DI graph. **Fix:** Sau thêm interface mới + impl → luôn add `services.AddScoped()` trong `DependencyInjection.cs`. Test API start up là OK check. ## Contract workflow ### 20. Mã HĐ gen 2 lần sau reject → approve lại **Fix:** Check `if (contract.MaHopDong is null)` trước khi gen. Đã implement trong `ContractWorkflowService.TransitionAsync`. ### 21. BE adjacency vs FE NEXT_PHASES sync **Triệu chứng:** FE hiển thị nút chuyển phase, click → BE 403. **Nguyên nhân:** FE `NEXT_PHASES` map phải khớp BE `Transitions` dict. **Fix:** Khi đổi adjacency BE → sync FE `src/pages/contracts/ContractDetailPage.tsx` ngay lập tức (cả 2 app). ### 22. Race condition gen mã HĐ khi 2 user cùng transition tới DangDongDau **Fix:** `IsolationLevel.Serializable` transaction trong `ContractCodeGenerator`. Không skip. ## Permission matrix ### 23. Permission update không real-time **Triệu chứng:** Admin tick permission cho role X → user X vẫn thấy menu cũ. **Nguyên nhân:** FE cache menu trong `localStorage`, không auto refetch. **Fix:** User phải logout/login. Phase 3 iteration 2 có thể thêm SignalR push "permission-changed" → FE tự refetch `/menus/me`. ### 24. MenuKey typo — không check type **Fix:** Luôn dùng `MenuKeys.Contracts` const (BE) + `MenuKeys.Contracts` (FE `menuKeys.ts`). Không hardcode string. ## Checklist debug bug mới 1. Build pass không? → fail → check using + package version compat 2. DI register đủ? → runtime error "Unable to resolve" → add `AddScoped/Singleton` 3. API log startup có error ẩn? → `tail` output file 4. File đã persist đúng chưa? → `head -5` verify sau Write 5. Nếu package exotic → thử downgrade về stable trước 6. Nếu TS error → check `erasableSyntaxOnly`, `verbatimModuleSyntax` 7. Nếu EF expression tree → tách logic ra ngoài query 8. Nếu Unicode CLI → dùng file payload 9. Nếu workflow 403 → check FE NEXT_PHASES sync BE