Files
solution-erp/CLAUDE.md

146 lines
12 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.

# CLAUDE.md — AI Agent Context
> **Full content:** [`docs/CLAUDE.md`](docs/CLAUDE.md)
---
**SOLUTION_ERP** — Hệ thống Quản lý Hợp đồng Nhà cung cấp / Thầu phụ / Tổ đội + **Phiếu Duyệt NCC tiền-HĐ** cho Công ty TNHH Xây dựng Solutions.
Kiến trúc: **.NET 10 Clean Architecture + 2 React FE (admin + user) + SQL Server + IIS**.
## 🚀 BẮT ĐẦU SESSION — 5 file đọc trước tiên
```
1. docs/STATUS.md ← Snapshot HIỆN TẠI (phase nào, việc gì đang làm — PE module CÒN CHỈNH NHIỀU)
2. docs/HANDOFF.md ← Brief 5 phút: session trước làm gì + cảnh báo session tiếp
3. docs/PROJECT-MAP.md ← Bản đồ toàn cảnh
4. docs/changelog/migration-todos.md ← Atomic tasks theo phase (Phase 7 PE refinement mới)
5. docs/workflow-contract.md ← ⭐ State machine 9 phase HĐ — base pattern cho PE workflow
```
## ⚡ Quick Rules
### Backend — `.NET 10` Clean Architecture
- Solution: `SolutionErp.slnx` ở root, projects ở `src/Backend/`
- **4 layer:** `Api → Application ← Domain` + `Infrastructure → Application`
- Pattern: **CQRS + MediatR**, **FluentValidation**, **AutoMapper**
- Repository qua `IApplicationDbContext` interface (Application layer)
- Auth: **JWT Bearer + ASP.NET Identity**
- DB: **SQL Server** (LocalDB dev / SQL Server prod), **EF Core 10 Code-First migrations**
- Error handling: `GlobalExceptionMiddleware` map exception → HTTP status
- Commit scope tech stack: `Api` · `App` · `Domain` · `Infra`
### Frontend — 2 app React 18 + Vite + TS + shadcn/ui + TanStack Query
- `fe-admin/` (port **8082**) · `fe-user/` (port **8080**)
- Vite proxy `/api → http://localhost:5443` (SolutionErp.Api)
- **Named export**, không default export (trừ `App`)
- shadcn/ui copy-paste, **duplicate giữa 2 app là CÓ CHỦ ĐÍCH** (mỗi app UX riêng)
- Auth context: `solution-erp-admin-token` / `solution-erp-user-token``localStorage`
- TanStack Query cho data fetching
- **Node pin `>=20`** trong `engines`; CI pin `20.x` qua `.nvmrc` (bài học NamGroup — KHÔNG dùng Node latest trên CI)
- UI **100% tiếng Việt**
### Database conventions
- Schema: `dbo` (single schema)
- Table: **PascalCase tiếng Anh** (Contracts, Suppliers, Projects, ContractApprovals, PurchaseEvaluations, ...)
- PK: `Id` (Guid), FK: `{Entity}Id`
- Audit fields: `CreatedAt`, `UpdatedAt`, `CreatedBy`, `UpdatedBy` (`BaseEntity`)
- Soft delete: `IsDeleted`, `DeletedAt`, `DeletedBy` (`AuditableEntity`)
- Migrations: `dotnet ef migrations add <Name> --project src/Backend/SolutionErp.Infrastructure --startup-project src/Backend/SolutionErp.Api`
- **Hiện có 52 migration → 88 bảng** (+S65: Mig 51 `AddDepartmentParentId` Department.ParentId loose-Guid no-FK org-tree phân cấp + Mig 52 `AddHoSoLinkToPurchaseEvaluation` PE HoSoLink nvarchar(1000) hyperlink NAS — cả 2 AddColumn no new table, tables giữ 88. Phase 10 COMPLETE + Phase 11 P11-A→F done — Mig 34-42 HRM/Office/WorkflowApps/Attendance + Contract V2 (32-33) + WireWorkflowApps V2 (41) + LeaveBalance (42) + Holiday filtered-unique (43, S45) + Vehicle/Driver catalog (44, S51) + HRM-catalog filtered-unique 3× (45, S51) + ItTicket SLA (46, S52) + Master filtered-unique 3× (47, S53 gotcha #57 EXT) + Project master fields Year/Investor/Location/Package (48, S55 — AddColumn no new table, kèm nạp 62 dự án + 71 hạng mục + 3 NCC real data từ Excel qua `SeedRealMasterDataAsync` ungated idempotent) + PE gắn Hạng mục công việc WorkItemId loose-Guid KHÔNG FK vật lý (49, S57bis — AddColumn+CreateIndex, no new table) + **Mig 50 `ReplaceBudgetModuleWithPeWorkItemBudgets` (S61, 2026-06-13) — XÓA module Budget cũ, thay bằng `PeWorkItemBudgets` ngân sách per-gói-thầu (1 record/cặp Dự án × Hạng mục, nhập theo role PRO/CCM, vượt ngân sách = cảnh báo mềm cho lưu S62); backfill `BudgetManualAmount→BudgetPeriodAmount` TRƯỚC DropColumn (phiếu UAT giữ số); net bảng 93→88; gotcha #63/#64**. V2 schema history S29-era bên dưới giữ nguyên — Mig 32+33 Plan B Contract V2 cookie-cutter mirror PE Mig 22-26 (S29). Mig 26 `AddPeLevelOpinionsForV2`: bảng mới `PurchaseEvaluationLevelOpinions` UNIQUE composite (PEId, LevelId), FK Cascade Pe + Restrict Level. Section 5 "Ý kiến cấp duyệt" V2 dynamic theo workflow đã pin: forEach Step (Phòng) → forEach Level (Cấp) → forEach NV → 1 OpinionBox. Service `ApproveV2Async` UPSERT auto khi NV duyệt — Q1=1B (sync gắn với Duyệt, KHÔNG form input rời). SignedByUserId track signer thật, FE banner "Admin duyệt thay" khi !== ApproverUserId. Comment empty → "(duyệt — không ý kiến)" placeholder. Phiếu V1 legacy fallback Mig 15 4 box readOnly (data history). Mig 25 `AddIsUserSelectableToApprovalWorkflows`: ALTER `ApprovalWorkflows` +`IsUserSelectable bit` (admin pin/unpin workflow nào cho user pick lúc create phiếu, multi-select độc lập IsActive). Backfill `WHERE IsActive=1 SET 1` giữ behavior cũ. Designer +badge "Cho user chọn" + button Ghim/Bỏ ghim. Workspace filter dropdown chỉ workflows `IsUserSelectable=true`. Mig 22-24 V2 schema (Session 17): `ApprovalWorkflows`/Steps/Levels — Quy trình > Bước (Phòng) > Cấp (N NV cụ thể qua ApproverUserId, OR-of-N cùng cấp). PE.ApprovalWorkflowId pin V2. PE.CurrentApprovalLevelOrder track. State machine 5 trạng thái: Nháp / Đã gửi duyệt / Trả lại (Phase riêng TraLai=98) / Từ chối / Đã duyệt. PE Service V2 wire match `actor.Id == ApproverUserId`. Contract V2 ĐÃ WIRE (Mig 32+33 Plan B S29 — cookie-cutter mirror PE V2: `ApproveV2Async` + `ContractLevelOpinions` UPSERT + Workspace V2 Select dropdown). Mig 21 V1 flat workflow vẫn live cho phiếu cũ.)
### Modules
| Module | Namespace | Migration | Trạng thái |
|---|---|---|---|
| Contract (HĐ) | `Domain/Contracts/` | 1-11 | Feature-complete (7 ContractType × 9 phase) |
| PurchaseEvaluation (Duyệt NCC tiền-HĐ) | `Domain/PurchaseEvaluations/` | 12,13,15,49,50,52 | Feature-complete — +Hạng mục (Mig 49) +ngân sách per-gói-thầu role PRO/CCM (Mig 50, vượt=cảnh báo mềm S62) +**Link hồ sơ NAS hyperlink (Mig 52, S65)**. Export PDF pending |
| ~~Budget (Ngân sách dự án)~~ | — | 14 → **Mig 50 DROP** | ⚠️ **REMOVED S61** — module Budget cũ XÓA, thay bằng PE-budget-per-gói-thầu (`PeWorkItemBudgets`). FE pages/types/menu `Bg_*` gỡ hết |
| Master (Supplier/Project/Department) | `Domain/Master/` | 2, 10 | Feature-complete |
| Identity (User/Role/Permission/MenuItem) | `Domain/Identity/` | 1, 3, 11 | Feature-complete (30 demo user — 16 sample + 14 Solutions thật) |
| Forms (Template + Clause) | `Domain/Forms/` | 4 | Feature-complete |
| Notifications | `Domain/Notifications/` | 6 | In-app + SignalR OK, email SMTP TODO |
| **Tests** | `tests/SolutionErp.{Domain,Infrastructure}.Tests/` | — | **286 test pass** (45 Domain + 241 Infra) — CI gate + path filter docs-only skip |
### Commit convention
```
[CLAUDE] <scope>: <imperative message>
```
**Scope:** `Contract` · `PurchaseEvaluation` · `Budget` · `Form` · `Workflow` · `Supplier` · `Auth` · `Admin` · `Api` · `App` · `Domain` · `Infra` · `FE-Admin` · `FE-User` · `Tests` · `Docs` · `CICD` · `Scripts` · `Skill`
## 🧪 Tests (Phase 9 — Session 9 +6)
```
tests/
├── SolutionErp.Domain.Tests/ (58 test — Domain policy: Workflow / PE / Budget)
└── SolutionErp.Infrastructure.Tests/ (128 test)
├── Common/ (SqliteDbFixture + TestApplicationDbContext + IdentityFixture S9)
├── Services/ (17 codegen + 6 PE 2-stage approval S9)
└── Application/ (6 test - PeWorkflowDefinition versioning)
```
**263 unit test pass** (45 Domain + 218 Infra). CI gate + path filter live. (S61 +22 `PeWorkItemBudgetTests` 14 `BudgetPolicyTests` 1 → 263; S60 +14 `PeSubmitGuardAndBypassTests` +2 spec → 256; S57bis +12 `PeWorkItemGuardTests`. Domain giảm 58→45 do drop BudgetPolicyTests cùng module Budget.)
```bash
dotnet test SolutionErp.slnx # chạy cả 2 test project
```
**Quy tắc timing test:** feature mới = test-after (UAT ổn → viết). Bug fix = test-before BẮT BUỘC (reproduce → fix). Critical algorithm (codegen/guard/financial/security) = test-before merge. Spec change = update test cũ + code chung commit. Skip: DTO mapping, CRUD master, FE snapshot. Detail `docs/rules.md §7`.
### CI/CD pipeline (3 fix lớn 29/04)
- ✅ Manual checkout bypass github.com (fix gotcha #39 TCP timeout)
- ✅ Path filter docs-only skip — `paths-ignore` (gotcha #41)
- ⏸️ npm cache (gotcha #40 — failed, rolled back)
**Tốc độ:** code commit ~3 phút / docs-only commit **0s** (skip).
## 🛠️ Skills (.claude/skills/) — 6 skill PHẢI dùng khi task khớp
| Domain (3) | Ops (3) |
|---|---|
| `contract-workflow` — state machine + versioned WF | `dependency-audit-erp` — npm/dotnet CVE scan |
| `form-engine` — render docx/xlsx + PDF | `ef-core-migration` — EF migration + 3-file rule |
| `permission-matrix` — role × menu × CRUD | `iis-deploy-runbook` — 3 site IIS + win-acme + runner |
**Audit định kỳ:** đầu mỗi tháng — combined skill + doc drift audit theo `docs/rules.md §6.4 + §9.4`. Cron `solution-erp-skill-audit-monthly` fire 9:00 ngày 1. Lần kế: **2026-07-01** (S44 đã chạy 06-01).
Quy tắc:
- KHÔNG bulk-clone repo skill 3rd party. Chỉ thêm skill PROJECT-SPECIFIC. Xem `docs/rules.md §9` đầy đủ.
- KHÔNG rewrite toàn bộ MD định kỳ. Chỉ compact + patch drift. Xem `docs/rules.md §6.4` đầy đủ.
## 📖 Tài liệu quan trọng
| File | Nội dung |
|---|---|
| [`docs/STATUS.md`](docs/STATUS.md) | **🔥 Current state** — đọc đầu tiên |
| [`docs/HANDOFF.md`](docs/HANDOFF.md) | Brief 5 phút: session trước làm gì + next tasks |
| [`docs/rules.md`](docs/rules.md) | ⭐ Coding conventions (BE Clean Arch, FE React, DB, Git, Docs) |
| [`docs/architecture.md`](docs/architecture.md) | ⭐ Layered architecture + request lifecycle + deployment |
| [`docs/PROJECT-MAP.md`](docs/PROJECT-MAP.md) | Bản đồ tổng quan |
| [`docs/changelog/migration-todos.md`](docs/changelog/migration-todos.md) | Roadmap 5 phase + atomic tasks |
| [`docs/CLAUDE.md`](docs/CLAUDE.md) | Full context — tech stack chi tiết |
| [`docs/workflow-contract.md`](docs/workflow-contract.md) | State machine 9 phase HĐ + role matrix |
| [`docs/forms-spec.md`](docs/forms-spec.md) | Catalog 8 form + quy định mã HĐ RG-001 |
| [`docs/database/database-guide.md`](docs/database/database-guide.md) | DB conventions + migration workflow + cheatsheet |
| [`docs/database/schema-diagram.md`](docs/database/schema-diagram.md) | ⭐ ERD + luồng DB + data flow 88 table (+ §11 PE + §12 ~~Budget~~ DROP + §13 PEDeptOpinions + §14 Contract V2 LevelOpinions; §16+ Mig 32-52 pending) |
| [`docs/flows/README.md`](docs/flows/README.md) | Index 6 flow (auth, permission, contract, form, SLA) |
| [`docs/gotchas.md`](docs/gotchas.md) | ⭐ 65 bẫy đã gặp — đọc trước khi debug tương tự |
| [`.claude/skills/`](.claude/skills/README.md) | 6 skill: contract-workflow, form-engine, permission-matrix, dependency-audit-erp, ef-core-migration, iis-deploy-runbook |
| [`docs/guides/vps-setup.md`](docs/guides/vps-setup.md) | ⭐ Master runbook deploy VPS shared với VIETREPORT |
## ⚠️ Kết thúc session
1. Update `docs/STATUS.md` (`In Progress``Recently Done`)
2. Tick checklist tương ứng trong `docs/changelog/migration-todos.md`
3. Tạo session log `docs/changelog/sessions/YYYY-MM-DD-HHMM-{topic}.md` nếu đáng ghi
4. Commit `[CLAUDE] <scope>: <message>`
5. ⚠️ **Update `SolutionErp.slnx`** nếu có `.cs/.csproj` mới
> Bỏ qua nếu chỉ trả lời câu hỏi, không sửa file nào.