Vấn đề persistent (run #108 và #109 đều fail trong 21-22s):
Get "https://github.com/actions/checkout/info/refs?service=git-upload-pack":
dial tcp 20.205.243.166:443: connectex: connection failed/timeout
act_runner v0.2.13 mỗi run đều `git fetch` actions/checkout từ github.com
để check update — VPS network → github.com TCP timeout 21s liên tục →
toàn job fail TRƯỚC khi tới test gate.
Fix: thay actions ngoài bằng native shell, eliminate github.com dependency.
- Replace `uses: actions/checkout@v4` → manual `git init` + `git fetch`
từ Gitea internal network (luôn ổn định, không qua public internet)
- Auth: github.token (act_runner cũng dùng tên này) — tự sẵn per job
- Fetch by ref (branch) thay vì SHA, depth=30 đủ buffer nếu main commit
thêm trong lúc job pickup
- Checkout đúng commit SHA của event push
- Log 1-line để confirm checkout đúng
- Replace `uses: actions/upload-artifact@v4` (cũng phụ thuộc github.com)
→ step "List test results" local. TRX file vẫn save trong workspace
test-results/, đọc qua runner workspace nếu cần debug.
Test gate giữ nguyên (Domain + Infra). dotnet test local 71 pass / 2s.
Long-term option (nếu Gitea Actions thêm hỗ trợ): config `github_mirror`
trong gitea-runner config.yaml để mirror github.com → Gitea internal,
hoặc pre-cache actions/* repos vào runner cache dir.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 2 — chống regression code generator. 17 test mới integration với
DB thật (SQLite in-memory) tổng cộng 71 test pass < 3 giây.
Test project:
- tests/SolutionErp.Infrastructure.Tests/ (xUnit + FluentAssertions + EF SQLite 10)
- ProjectReference SolutionErp.Infrastructure (transitively get Application + Domain)
- Added vào SolutionErp.slnx
Test fixtures:
- Common/SqliteDbFixture.cs:
- SQLite ":memory:" + shared connection + EnsureCreated() từ DbContext model
- TestApplicationDbContext subclass — override OnModelCreating replace
'nvarchar(max)' → 'TEXT' (SQLite không support max keyword)
- FixedDateTime stub IDateTime cho deterministic year boundary test
Test files:
- Services/ContractCodeGeneratorTests.cs (10 test):
- Format per ContractType (5 type × Project scope) — RG-001 spec
- Framework HĐ (NguyenTacNCC + NguyenTacDV) → year scope thay vì project
- Sequence increment per prefix (3 calls → /01, /02, /03)
- Different prefixes (project / supplier) → independent sequences
- Year change (2026 → 2027) → reset sequence vì prefix khác
- PersistsSequenceRow LastSeq verification
- Services/PurchaseEvaluationCodeGeneratorTests.cs (7 test):
- Format A/B (DuyetNcc → 'A', DuyetNccPhuongAn → 'B')
- Seq là 3-digit padded (001..012)
- Type A và B sequence độc lập trong cùng năm
- Year boundary reset cả A và B
CI gate update (.gitea/workflows/deploy.yml):
- Step "Run integration tests (Infrastructure)" thêm sau Domain tests
- TRX log saved riêng (infra-tests.trx)
- Cả 2 step đều exit non-zero → no deploy
Verify local:
- dotnet test SolutionErp.slnx → Total tests: 71 (54 Domain + 17 Infra) / Passed: 71 / 2.1s
- dotnet build SolutionErp.slnx → 0 error
Phase 3+ pending:
- Application handler tests (CQRS) với EF InMemory hoặc SQLite (~1 ngày)
- API smoke tests qua WebApplicationFactory (~0.5 ngày)
- FE Vitest cho lib utility (~0.5 ngày)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CICD: check app pool state before Stop-WebAppPool (idempotent).
FE: new SlaTimer component with color-coded countdown (emerald/amber/red)
and progress bar. Two variants:
- inline: used in list tables (Inbox, Contracts list x2, MyContracts)
- full: used in ContractDetail card with progress bar + deadline timestamp
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
VPS runner has only windows-latest label (no ubuntu) and lives on the
same VPS as IIS, so WinRM + multi-job artifact handoff is unnecessary.
Changes:
- Single build-deploy job on windows-latest self-hosted
- Uses pre-installed Node 20 and .NET 10 SDK (avoids 500MB setup-*
downloads per run)
- Deploys directly to C:\inetpub\solution-erp\ — no WinRM
- appsettings.Production.json rendered from template via secrets
(ConvertFrom-Json + ConvertTo-Json keeps JSON structure intact)
- Fixed site name mismatch: SolutionErp-Api (was SolutionErpApi)
- Removed IIS_HOST/USER/PASSWORD secrets — no longer needed
- Added smoke test step hitting https://api.huypham.vn/health/live
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>