Files
solution-erp/docs/gotchas.md
pqhuy1987 c52186bed0
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m24s
[CLAUDE] Docs: gotcha #25 — Install-WindowsFeature Web-WebSockets locks webSocket section in applicationHost
2026-04-21 21:10:43 +07:00

7.8 KiB

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<TResponse> 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:

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:

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 addUnable to resolve service for type 'DbContextOptions<T>'.

Fix: Tạo IDesignTimeDbContextFactory<ApplicationDbContext> 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<>:

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 <w:t> — placeholder miss khi regex replace.

Fix: Iterate Paragraph, gom text tất cả <w:t> → replace → gán lại text đầu + clear rest. Đã implement trong DocxRenderer.

11. Word COM SaveAs PowerShell type conversion

Fix: Dùng SaveAs2:

$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 :8082taskkill /F /PID <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<IX, X>() 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.

IIS / Windows Server

25. Install-WindowsFeature Web-WebSockets khóa section <webSocket> ở applicationHost

Triệu chứng: Sau khi install WebSocket feature → TẤT CẢ IIS site có <webSocket enabled="true" /> trong web.config trả về HTTP 500.19 với error code 0x80070021 "configuration section cannot be used at this path" — kể cả site khác project không liên quan.

Nguyên nhân: Feature install thêm <webSocket> section vào applicationHost.config với overrideModeDefault="Deny". Site web.config override section đó → fail.

Fix: Unlock section ở server level:

& "$env:SystemRoot\system32\inetsrv\appcmd.exe" unlock config -section:system.webServer/webSocket

Tương tự khi dùng URL Rewrite <serverVariables> cần unlock system.webServer/rewrite/allowedServerVariables.

Cảnh báo co-existence: Trên VPS shared với project khác, enable feature mới qua Install-WindowsFeature có thể làm sập site project khác. Luôn test all site sau mỗi enable.

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