[CLAUDE] Phase4: Report MVP + Docs Consolidation (rules, architecture, schema-diagram)
Backend Report: - Application/Reports/Dtos/DashboardStatsDto: 5 KPI + PhaseCount + SupplierCount + ProjectCount + MonthlyValue - Application/Reports/Queries/GetDashboardStats handler: total/active/overdue/published this month/totalValueActive + byPhase + top 5 NCC/du an + 12 thang monthly (fill zero khi thang empty) - Application/Reports/Services/IContractExcelExporter interface - Infrastructure/Reports/ContractExcelExporter: ClosedXML workbook 10 cot, header style bold+blue, number format #,##0, formula SUM, auto-fit, freeze header - Application/Reports/Commands/ExportContractsToExcelCommand: filter phase/supplier/project/date range - Api/Controllers/ReportsController: GET /reports/dashboard, GET /reports/contracts/export - DI register IContractExcelExporter (Scoped) Frontend fe-admin: - types/reports.ts: DashboardStats type - components/BarChart.tsx: generic horizontal bar chart — chi Tailwind, khong thu vien ngoai - pages/DashboardPage.tsx REWRITE: 5 KPI card (FileText/TrendingUp/AlertTriangle/CheckCircle2/Coins) + by-phase bar + monthly 12-month chart + top 5 NCC + top 5 du an + skeleton loader - pages/ReportsPage.tsx MOI: filter phase/fromDate/toDate → export Excel button - Route /reports vao App.tsx E2E verified: - GET /api/reports/dashboard → 200 voi day du KPI + monthly fill 12 thang - GET /api/reports/contracts/export → 200 xlsx 7229 bytes (Microsoft Excel 2007+) Docs consolidation (theo yeu cau user): - docs/rules.md MOI: 9 section coding conventions (ngon ngu UI/code/DB/docs, BE Clean Arch, CQRS+MediatR, Validation FluentValidation, Error handling, Async, Entity rules, DI, Package pinning, FE React/TS erasableSyntaxOnly, path alias, TanStack Query, Permission guard, Toast+error, DB convention, Git commit format, Docs structure, Testing, Security) - docs/architecture.md MOI: layered overview ASCII art, request lifecycle (1 POST/api/contracts qua 10 step), workflow state machine 9 phase, permission model, data flow sequence diagram 4 actor (Drafter/Manager/CCM/BOD/HRA), deployment architecture Phase 5, skill library, non-functional table - docs/database/schema-diagram.md MOI: full ERD 19 table mermaid + data flow diagram + vong doi 1 HD (create → 7 transition → gen ma → publish) + index strategy table + relationship cardinality + soft delete behavior + SQL queries (inbox/dashboard/gen ma) + migration history - docs/gotchas.md UPDATE: 17 → 26 pitfalls, them section "Claude Code harness quirks" (Edit File not read, DI build pass nhung runtime fail) + "Contract workflow" (ma HD gen 2 lan, BE-FE NEXT_PHASES sync, race condition) + "Permission matrix" (cache real-time, MenuKey typo) - docs/STATUS.md: Phase 4 MVP done, docs entry points section liet ke het, next Phase 5 Production - docs/HANDOFF.md: phase table them Phase 4 row, file tree update voi Reports, test points day du, git state commit 7 - docs/changelog/migration-todos.md: tick Phase 4 MVP items + them iteration 2 list - docs/changelog/sessions/2026-04-21-1430-phase4-report.md: session log voi thong so cumulative (BE 3100 LOC, 30 docs) - CLAUDE.md root: update Tai lieu quan trong section them rules.md, architecture.md, schema-diagram.md, .claude/skills (13 links now) Bug fix: - TS unused import ContractPhaseLabel trong DashboardPage - DI thieu register IContractExcelExporter — build pass but runtime would fail (added) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
250
docs/architecture.md
Normal file
250
docs/architecture.md
Normal file
@ -0,0 +1,250 @@
|
||||
# Architecture — SOLUTION_ERP
|
||||
|
||||
> Kiến trúc tổng thể + trách nhiệm từng layer + diagram luồng dữ liệu.
|
||||
|
||||
## 1. Layered overview
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ CLIENT TIER │
|
||||
│ ┌──────────────────┐ ┌──────────────────┐ │
|
||||
│ │ fe-admin :8082 │ │ fe-user :8080 │ │
|
||||
│ │ React 19 + Vite │ │ React 19 + Vite │ │
|
||||
│ │ Tailwind 4 │ │ Tailwind 4 │ │
|
||||
│ │ TanStack Query │ │ TanStack Query │ │
|
||||
│ └────────┬─────────┘ └────────┬─────────┘ │
|
||||
└───────────┼──────────────────────────┼───────────────────────┘
|
||||
│ Vite dev proxy /api │
|
||||
│ IIS URL Rewrite prod │
|
||||
▼ ▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ API LAYER (:5443) │
|
||||
│ SolutionErp.Api — ASP.NET Core 10 Web API │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ Controllers: Auth, Menus, Roles, Permissions, │ │
|
||||
│ │ Suppliers, Projects, Departments, │ │
|
||||
│ │ Forms, Contracts, Reports │ │
|
||||
│ │ Middleware: GlobalException, Serilog, CORS, JWT │ │
|
||||
│ │ Authorization: MenuPermissionHandler (policy-based) │ │
|
||||
│ │ Services: CurrentUserService, WebHostEnvLocator │ │
|
||||
│ │ wwwroot/templates/ (5 .docx/.xlsx) │ │
|
||||
│ └────────────────────┬───────────────────────────────────┘ │
|
||||
└───────────────────────┼──────────────────────────────────────┘
|
||||
│ MediatR ISender.Send(cmd)
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ APPLICATION LAYER │
|
||||
│ SolutionErp.Application │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
||||
│ │ Auth │ │ Master │ │ Permissions │ │
|
||||
│ │ (Login/Me) │ │ (CRUD 3 │ │ (Menu tree + │ │
|
||||
│ │ │ │ entity) │ │ matrix) │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
|
||||
│ ┌──────────────┐ ┌──────────────────┐ │
|
||||
│ │ Forms │ │ Contracts │ ┌──────────────┐ │
|
||||
│ │ (Render │ │ (Workflow 9 │ │ Reports │ │
|
||||
│ │ engine) │ │ phase, Inbox) │ │ (Dashboard + │ │
|
||||
│ └──────────────┘ └──────────────────┘ │ Excel exp) │ │
|
||||
│ └──────────────┘ │
|
||||
│ ┌──────────────────────────────────────────────────────┐ │
|
||||
│ │ Common: Exceptions, Behaviors (ValidationPipeline), │ │
|
||||
│ │ Interfaces (IDbContext, ICurrentUser, ...), │ │
|
||||
│ │ Models (PagedResult) │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
└───────┬──────────────────────────────────────────┬───────────┘
|
||||
│ depends on interface │ runs on
|
||||
▼ ▼
|
||||
┌──────────────────────┐ ┌───────────────────────────┐
|
||||
│ DOMAIN LAYER │ │ INFRASTRUCTURE LAYER │
|
||||
│ SolutionErp.Domain │ │ SolutionErp.Infrastructure│
|
||||
│ │ │ │
|
||||
│ Common/BaseEntity │ │ Persistence/ApplicationD │
|
||||
│ Contracts/ │ │ bContext + Migrations │
|
||||
│ Forms/ │ │ Identity/JwtTokenService │
|
||||
│ Identity/ │ │ Forms/Docx+XlsxRenderer │
|
||||
│ Master/ │ │ Services/ContractWorkflow│
|
||||
│ │ │ + ContractCodeGenerator│
|
||||
│ Enum + value object │ │ Reports/ExcelExporter │
|
||||
└──────────────────────┘ │ Services/DateTimeService │
|
||||
↑ └────────────┬──────────────┘
|
||||
│ references │
|
||||
└───────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────┐
|
||||
│ DATA TIER │
|
||||
│ SQL Server 2022 │
|
||||
│ (dbo schema, 19 bảng)│
|
||||
└───────────────────────┘
|
||||
```
|
||||
|
||||
## 2. Request lifecycle (1 POST/api/contracts)
|
||||
|
||||
```
|
||||
1. Browser → POST /api/contracts { type, supplierId, ... }
|
||||
2. Vite → proxy tới :5443
|
||||
3. JwtBearerMiddleware → validate token, set ClaimsPrincipal
|
||||
4. Routing → ContractsController.Create(cmd)
|
||||
5. MediatR.Send(CreateContractCommand)
|
||||
6. ValidationBehavior (pipeline) → FluentValidation run
|
||||
7. CreateContractCommandHandler
|
||||
├─ check Supplier/Project exists (IApplicationDbContext)
|
||||
├─ new Contract entity + set DrafterUserId (ICurrentUser)
|
||||
├─ set SlaDeadline (IDateTime + IContractWorkflowService.GetPhaseSla)
|
||||
├─ db.Contracts.Add(...)
|
||||
└─ SaveChangesAsync
|
||||
├─ AuditingInterceptor sets CreatedAt/CreatedBy
|
||||
└─ EF Core INSERT → SQL Server
|
||||
8. Return Guid id
|
||||
9. Controller → 201 Created + Location header
|
||||
10. Axios interceptor (FE) → TanStack Query invalidate + UI update
|
||||
```
|
||||
|
||||
## 3. Workflow state machine (Phase 3)
|
||||
|
||||
Xem full ở [`workflow-contract.md`](workflow-contract.md).
|
||||
|
||||
```
|
||||
DangChon → DangSoanThao → DangGopY → DangDamPhan → DangInKy →
|
||||
→ DangKiemTraCCM → DangTrinhKy → DangDongDau → DaPhatHanh
|
||||
|
||||
Alternates: → TuChoi (từ DangSoanThao)
|
||||
→ DangSoanThao (revise từ bất kỳ phase duyệt)
|
||||
|
||||
Bypass CĐT (BypassProcurementAndCCM=true):
|
||||
DangInKy → DangTrinhKy (skip CCM)
|
||||
```
|
||||
|
||||
**Code generator trigger:** khi `targetPhase = DangDongDau` + `MaHopDong IS NULL` → gen format RG-001 với transaction SERIALIZABLE.
|
||||
|
||||
## 4. Permission model
|
||||
|
||||
```
|
||||
User ──(AspNetUserRoles)── Role ──(Permissions)── MenuItem
|
||||
│
|
||||
├── CanRead
|
||||
├── CanCreate
|
||||
├── CanUpdate
|
||||
└── CanDelete
|
||||
```
|
||||
|
||||
**Resolution:**
|
||||
- Login → JWT chứa claims (sub, email, roles)
|
||||
- `/api/menus/me` → query Permissions theo roleIds, **union OR** CRUD flags, filter tree theo CanRead
|
||||
- FE cache menu trong `AuthContext` + localStorage
|
||||
- Mỗi API action: `[Authorize(Policy = "{MenuKey}.{Action}")]` → `MenuPermissionHandler` check
|
||||
|
||||
**Admin bypass:** role `Admin` luôn pass mọi policy (seed default full CRUD).
|
||||
|
||||
## 5. Data flow — "tạo HĐ và chạy hết workflow"
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor D as Drafter
|
||||
actor M as Manager (PD/PM)
|
||||
actor C as CCM
|
||||
actor B as BOD
|
||||
actor H as HRA
|
||||
|
||||
participant FE as fe-user
|
||||
participant API
|
||||
participant WF as WorkflowService
|
||||
participant CG as CodeGenerator
|
||||
participant DB
|
||||
|
||||
D->>FE: POST /contracts/new
|
||||
FE->>API: POST /api/contracts
|
||||
API->>DB: INSERT Contracts (Phase=DangSoanThao, SLA=+7d)
|
||||
API-->>FE: 201 {id}
|
||||
|
||||
D->>FE: Click "Submit → góp ý"
|
||||
FE->>API: POST /contracts/{id}/transitions {target:3}
|
||||
API->>WF: Transition(contract, 3, roles=[Drafter])
|
||||
WF->>WF: Check adjacency + role
|
||||
WF->>DB: INSERT ContractApproval + UPDATE Contract Phase=3
|
||||
API-->>FE: 204
|
||||
|
||||
M->>FE: Inbox → click HĐ → góp ý + "Chuyển tiếp"
|
||||
FE->>API: POST /transitions {target:4}
|
||||
API->>WF: Transition → Phase 4
|
||||
Note over WF: Chạy tương tự qua 5,6,7
|
||||
|
||||
B->>FE: Duyệt → target:8 DangDongDau
|
||||
FE->>API: POST /transitions {target:8}
|
||||
API->>WF: Transition
|
||||
WF->>CG: GenerateAsync(contract, project, supplier)
|
||||
CG->>DB: BEGIN TRAN SERIALIZABLE
|
||||
CG->>DB: SELECT/UPDATE ContractCodeSequences
|
||||
CG->>DB: COMMIT
|
||||
CG-->>WF: "FLOCK 01/HĐGK/SOL&PVL/03"
|
||||
WF->>DB: UPDATE Contract SET MaHopDong, Phase=8
|
||||
API-->>FE: 204
|
||||
|
||||
H->>FE: Click đóng dấu → target:9
|
||||
FE->>API: POST /transitions {target:9}
|
||||
API->>WF: Transition (role HrAdmin)
|
||||
WF->>DB: UPDATE Phase=9 (DaPhatHanh)
|
||||
API-->>FE: 204
|
||||
```
|
||||
|
||||
## 6. Deployment architecture (Phase 5 — planned)
|
||||
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ Internet / Corp LAN │
|
||||
└──────────────┬──────────────┘
|
||||
│
|
||||
┌──────────▼──────────┐
|
||||
│ IIS (Win Server) │
|
||||
│ URL Rewrite / ARR │
|
||||
└──────────┬──────────┘
|
||||
┌─────────────┼─────────────┐
|
||||
│ │ │
|
||||
┌──────▼──────┐ ┌───▼────┐ ┌──────▼──────┐
|
||||
│ fe-admin │ │ Api │ │ fe-user │
|
||||
│ static files│ │ Kestrel│ │ static files│
|
||||
│ (dist/) │ │ :5443 │ │ (dist/) │
|
||||
└─────────────┘ └───┬────┘ └─────────────┘
|
||||
│
|
||||
┌────────▼────────┐
|
||||
│ SQL Server │
|
||||
│ (same host OR │
|
||||
│ separate VM) │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
- IIS app pool riêng cho Api, Integrated Managed Pipeline, .NET CLR disabled (hosting .NET 10 OOP)
|
||||
- Static files 2 FE deploy vào `C:\inetpub\wwwroot\solution-erp-admin\` + `...user\`
|
||||
- HTTPS: Let's Encrypt qua win-acme (hoặc cert mua)
|
||||
- Backup SQL: daily full + 15min log → D:\Backups
|
||||
|
||||
## 7. Skill library (AI agent support)
|
||||
|
||||
`.claude/skills/` có 3 skill chuyên biệt:
|
||||
|
||||
| Skill | Dùng khi |
|
||||
|---|---|
|
||||
| [`contract-workflow`](../.claude/skills/contract-workflow/SKILL.md) | Debug chuyển phase, 403, mã HĐ, bypass CĐT |
|
||||
| [`form-engine`](../.claude/skills/form-engine/SKILL.md) | Render template, upload, placeholder không replace |
|
||||
| [`permission-matrix`](../.claude/skills/permission-matrix/SKILL.md) | Access denied, menu không hiện, gán role |
|
||||
|
||||
Claude auto-invoke theo description matching.
|
||||
|
||||
## 8. Non-functional
|
||||
|
||||
| Aspect | Current | Phase 5 target |
|
||||
|---|---|---|
|
||||
| Availability | dev-only | 99.5% (IIS restart, SQL HA optional) |
|
||||
| Latency | <200ms P95 local | <500ms P95 prod |
|
||||
| Concurrency | unrestricted | rate limit 100 req/min/IP |
|
||||
| Observability | Serilog console | + file rolling daily + Seq/ELK |
|
||||
| Security | JWT + HTTPS dev | + rate limit + audit log + CSP |
|
||||
|
||||
## 9. Liên quan
|
||||
|
||||
- [`rules.md`](rules.md) — coding conventions
|
||||
- [`database/database-guide.md`](database/database-guide.md) — DB schema chi tiết
|
||||
- [`flows/`](flows/) — per-feature sequence diagrams
|
||||
- [`workflow-contract.md`](workflow-contract.md) — state machine spec
|
||||
- [`forms-spec.md`](forms-spec.md) — 8 form catalog
|
||||
Reference in New Issue
Block a user