[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:
300
docs/rules.md
Normal file
300
docs/rules.md
Normal file
@ -0,0 +1,300 @@
|
||||
# Rules — Coding Conventions SOLUTION_ERP
|
||||
|
||||
> Nguồn duy nhất cho rules. Bất cứ commit nào vi phạm cần justify trong message.
|
||||
|
||||
## 1. Ngôn ngữ
|
||||
|
||||
| Thành phần | Ngôn ngữ |
|
||||
|---|---|
|
||||
| UI FE | **100% tiếng Việt** |
|
||||
| Code (.cs/.ts) | **English** (tên biến/hàm/class) |
|
||||
| Comment code | Tiếng Anh hoặc Việt — miễn rõ |
|
||||
| Tên DB table + column | **English PascalCase** (Contracts, SupplierId) |
|
||||
| Business label | Tiếng Việt (vd `"Đang soạn thảo"` cho phase 2) |
|
||||
| Commit message | English hoặc Việt — preferred English |
|
||||
| Doc MD (docs/) | **Tiếng Việt** (audience là người Việt) |
|
||||
|
||||
## 2. Backend — .NET 10
|
||||
|
||||
### 2.1 Clean Architecture dependency rule
|
||||
|
||||
```
|
||||
Api → Application ← Domain
|
||||
↑
|
||||
Infrastructure ──┘
|
||||
```
|
||||
|
||||
- **Domain:** pure, chỉ dùng `Microsoft.Extensions.Identity.Stores` (cần cho IdentityUser) — không depend ASP.NET Core framework
|
||||
- **Application:** depend Domain; CQRS handlers + interfaces + DTOs + validators
|
||||
- **Infrastructure:** depend Application + Domain; impl interfaces (EF, JWT, rendering, services)
|
||||
- **Api:** depend Application + Infrastructure; Controllers + middleware + composition root
|
||||
|
||||
### 2.2 CQRS + MediatR pattern
|
||||
|
||||
- 1 feature = 1 file `{Verb}{Entity}Command.cs` / `{Verb}{Entity}Query.cs`
|
||||
- File chứa: Command record + Validator + Handler (cùng 1 file cho compact)
|
||||
- Dài thì tách: `{Feature}/Commands/{Create}/...`
|
||||
|
||||
**Command naming:**
|
||||
```
|
||||
Create{Entity}Command // tạo mới
|
||||
Update{Entity}Command // update full
|
||||
Patch{Entity}FieldCommand // update 1 field
|
||||
Delete{Entity}Command // soft delete (default)
|
||||
{Action}{Entity}Command // action domain-specific (vd TransitionContract)
|
||||
```
|
||||
|
||||
**Query naming:**
|
||||
```
|
||||
Get{Entity}Query // single by Id
|
||||
List{Entity}sQuery // list với paging
|
||||
{Entity}{Purpose}Query // custom query (vd GetMyInboxQuery)
|
||||
```
|
||||
|
||||
### 2.3 Validation
|
||||
|
||||
- FluentValidation (KHÔNG dùng DataAnnotation)
|
||||
- Validator = class trong cùng file command: `{Command}Validator : AbstractValidator<{Command}>`
|
||||
- Pipeline: `ValidationBehavior` auto-chạy trước Handler — throw `ValidationException` → 400 ProblemDetails
|
||||
|
||||
### 2.4 Error handling
|
||||
|
||||
- KHÔNG try-catch ở Controller
|
||||
- Throw domain exception: `NotFoundException`, `ForbiddenException`, `UnauthorizedException`, `ConflictException`, `ValidationException`
|
||||
- `GlobalExceptionMiddleware` map exception → HTTP status + ProblemDetails JSON
|
||||
- Logging: Serilog structured, không `Console.WriteLine`
|
||||
|
||||
### 2.5 Async/await
|
||||
|
||||
- Tất cả I/O (DB, HTTP, file) PHẢI async
|
||||
- Truyền `CancellationToken` mọi async call
|
||||
- Tên method async: suffix `Async` (trừ ASP.NET action signature)
|
||||
|
||||
### 2.6 Entity rules
|
||||
|
||||
- Mọi entity mới extend `BaseEntity` (Id Guid + audit) hoặc `AuditableEntity` (+ soft delete)
|
||||
- PK: `Id` type `Guid`, default `Guid.NewGuid()` trong constructor
|
||||
- FK: `{Entity}Id` type `Guid`
|
||||
- Enum: `HasConversion<int>()` trong EF config
|
||||
- String: luôn `HasMaxLength(n)` trong EF config — không để `nvarchar(max)` trừ khi là JSON/rich text
|
||||
- Money: `decimal` + `HasPrecision(18, 2)`
|
||||
- DateTime: luôn UTC, lấy từ `IDateTime.UtcNow` (không `DateTime.Now`)
|
||||
- Query filter soft delete: `HasQueryFilter(x => !x.IsDeleted)` cho AuditableEntity
|
||||
|
||||
### 2.7 DI registration
|
||||
|
||||
- Singleton: stateless services (DateTimeService, FormRenderer)
|
||||
- Scoped: per-request services (JwtTokenService, ContractWorkflowService, DbContext)
|
||||
- Transient: lightweight utility (hiếm dùng)
|
||||
|
||||
### 2.8 Package version pinning
|
||||
|
||||
- **KHÔNG dùng `*` hoặc `latest`** — luôn pin version cụ thể
|
||||
- Check compatibility với .NET 10 trước khi add. Gotchas đã biết:
|
||||
- MediatR 14 → lỗi IMediator DI, **pin 12.4.1**
|
||||
- Swashbuckle 10 → conflict OpenApi 2, **pin 6.9.0**
|
||||
- Xem [`gotchas.md`](gotchas.md) cho full list
|
||||
|
||||
## 3. Frontend — React 19 + Vite 8 + TS 6
|
||||
|
||||
### 3.1 Named export, không default export
|
||||
|
||||
```tsx
|
||||
// ✅
|
||||
export function SuppliersPage() { }
|
||||
export const MyConstant = 1
|
||||
|
||||
// ❌
|
||||
export default function SuppliersPage() { }
|
||||
|
||||
// Exception: App.tsx dùng default export (Vite convention)
|
||||
```
|
||||
|
||||
### 3.2 erasableSyntaxOnly (Vite 8)
|
||||
|
||||
KHÔNG dùng `enum` — dùng const-object pattern:
|
||||
|
||||
```ts
|
||||
// ❌
|
||||
export enum SupplierType { NhaCungCap = 1 }
|
||||
|
||||
// ✅
|
||||
export const SupplierType = { NhaCungCap: 1, NhaThauPhu: 2 } as const
|
||||
export type SupplierType = typeof SupplierType[keyof typeof SupplierType]
|
||||
```
|
||||
|
||||
### 3.3 Path alias
|
||||
|
||||
- Dùng `@/` cho absolute import: `import { api } from '@/lib/api'`
|
||||
- Config ở `vite.config.ts` + `tsconfig.app.json` (chỉ `paths`, không `baseUrl`)
|
||||
|
||||
### 3.4 Data fetching
|
||||
|
||||
- **TanStack Query** cho mọi API call (KHÔNG useState + useEffect thủ công)
|
||||
- `useQuery` cho GET, `useMutation` cho POST/PUT/DELETE
|
||||
- `invalidateQueries` sau mutation thành công
|
||||
|
||||
### 3.5 API calls
|
||||
|
||||
- Qua `api` instance (`src/lib/api.ts`) — đã wire axios interceptor JWT + 401 redirect
|
||||
- Base URL: `/api` (Vite proxy → `:5443`)
|
||||
|
||||
### 3.6 Permission guard
|
||||
|
||||
```tsx
|
||||
<PermissionGuard menuKey="Contracts" action="Update">
|
||||
<Button>Sửa</Button>
|
||||
</PermissionGuard>
|
||||
|
||||
// Hook
|
||||
const { can } = usePermission()
|
||||
if (!can('Contracts', 'Update')) return null
|
||||
```
|
||||
|
||||
Nhớ: FE guard chỉ là UX. BE policy `[Authorize(Policy = "Contracts.Update")]` là source of truth.
|
||||
|
||||
### 3.7 Component naming
|
||||
|
||||
- PascalCase cho file: `SuppliersPage.tsx`, `DataTable.tsx`
|
||||
- kebab-case cho utility: `api.ts`, `cn.ts`
|
||||
- React component = PascalCase
|
||||
- Hook: prefix `use`, ví dụ `usePermission`
|
||||
|
||||
### 3.8 Toast + error
|
||||
|
||||
- Dùng `sonner` (đã wire `<Toaster>` ở App)
|
||||
- `toast.success('...')`, `toast.error(getErrorMessage(err))`
|
||||
- Error helper: `src/lib/apiError.ts` extract từ ProblemDetails
|
||||
|
||||
### 3.9 Duplicate giữa 2 FE
|
||||
|
||||
**CÓ CHỦ ĐÍCH.** Mỗi app (`fe-admin` + `fe-user`) là standalone — copy shared code giữa 2 app thay vì extract ra package chung. Lý do: 2 app có UX rất khác (admin mission-critical, user workflow-heavy), evolution độc lập.
|
||||
|
||||
Khi share code: `cp` file từ app này sang app kia. Đồng bộ tay khi có breaking change.
|
||||
|
||||
## 4. Database
|
||||
|
||||
### 4.1 Convention
|
||||
|
||||
| Item | Rule |
|
||||
|---|---|
|
||||
| Schema | 1 schema duy nhất: `dbo` |
|
||||
| Table | PascalCase tiếng Anh, plural: `Contracts`, `Suppliers` |
|
||||
| Column | PascalCase: `FullName`, `CreatedAt` |
|
||||
| PK | `Id` — `uniqueidentifier` |
|
||||
| FK | `{Entity}Id` — `uniqueidentifier` |
|
||||
| Index | `IX_{Table}_{Col}` |
|
||||
| Unique | `UX_{Table}_{Col}` |
|
||||
|
||||
Full: xem [`database/database-guide.md`](database/database-guide.md).
|
||||
|
||||
### 4.2 Migration
|
||||
|
||||
- Một commit = 1 migration (trừ khi nhiều change nhỏ trong cùng feature)
|
||||
- Naming PascalCase: `AddMasterData`, `AddContractsWorkflow`
|
||||
- Commit đủ 3 file: `{Name}.cs`, `{Name}.Designer.cs`, `ApplicationDbContextModelSnapshot.cs`
|
||||
|
||||
## 5. Git & commits
|
||||
|
||||
### 5.1 Branch
|
||||
|
||||
- `main` — deploy branch
|
||||
- Feature branch (nếu nhiều người): `feature/phase{N}-{feature}`
|
||||
|
||||
### 5.2 Commit format
|
||||
|
||||
```
|
||||
[CLAUDE] <scope>: <imperative message>
|
||||
|
||||
<body optional — chi tiết what + why>
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
**Scope:** `Contract` · `Form` · `Workflow` · `Supplier` · `Auth` · `Admin` · `Api` · `App` · `Domain` · `Infra` · `FE-Admin` · `FE-User` · `Docs` · `CICD` · `Scripts` · `Report` · `Dashboard`
|
||||
|
||||
### 5.3 Một commit nên
|
||||
|
||||
- Build pass (BE + FE)
|
||||
- Không leave WIP nửa chừng (trừ khi commit message nói rõ)
|
||||
- Test E2E với endpoint mới (curl trong session log)
|
||||
|
||||
### 5.4 Không commit
|
||||
|
||||
- `.env`, `appsettings.*.Local.json`
|
||||
- `node_modules/`, `bin/`, `obj/`
|
||||
- `wwwroot/uploads/` (user files)
|
||||
- `SolutionErp_Design` database (tạm cho EF CLI)
|
||||
|
||||
## 6. Docs
|
||||
|
||||
### 6.1 Khi nào viết session log
|
||||
|
||||
- Session có commit thay đổi code → PHẢI tạo `docs/changelog/sessions/YYYY-MM-DD-HHMM-{topic}.md`
|
||||
- Session chỉ Q&A, không đụng file → không cần
|
||||
|
||||
### 6.2 Session log format
|
||||
|
||||
```markdown
|
||||
# Session YYYY-MM-DD HH:MM — <topic>
|
||||
|
||||
**Dev:** Claude / Copilot / <name>
|
||||
**Duration:** ~Nh
|
||||
**Base commit:** <sha>
|
||||
|
||||
## Làm được
|
||||
|
||||
### Chunk X — <name>
|
||||
- bullet list deliverable
|
||||
|
||||
## E2E verified
|
||||
|
||||
<curl output hoặc screenshot>
|
||||
|
||||
## Bug gặp + fix
|
||||
|
||||
| Bug | Fix |
|
||||
|
||||
## Docs updates
|
||||
|
||||
## Handoff
|
||||
|
||||
## Thông số cumulative
|
||||
```
|
||||
|
||||
### 6.3 Update khi thêm feature
|
||||
|
||||
- Thêm entity → update [`database/database-guide.md`](database/database-guide.md) schema section
|
||||
- Thêm endpoint → update [`flows/`](flows/) relevant flow
|
||||
- Thêm bug fix lặp lại → update [`gotchas.md`](gotchas.md)
|
||||
- Thêm pattern → update skill tương ứng ở `.claude/skills/`
|
||||
- Phase đổi → update [`STATUS.md`](STATUS.md) + [`HANDOFF.md`](HANDOFF.md) + [`changelog/migration-todos.md`](changelog/migration-todos.md)
|
||||
|
||||
## 7. Testing (hiện chưa có test tự động)
|
||||
|
||||
**Phase 1-4 — manual test:**
|
||||
- E2E qua curl/Postman trong mỗi session log
|
||||
- Build + TS check mỗi commit
|
||||
|
||||
**Phase 5 — tự động (chưa làm):**
|
||||
- Unit test: xUnit cho BE, Vitest cho FE
|
||||
- Integration test: TestContainer SQL Server cho BE
|
||||
- E2E test: Playwright cho FE
|
||||
|
||||
## 8. Security baseline
|
||||
|
||||
- HTTPS everywhere prod
|
||||
- JWT Secret trong user-secrets / env var (không commit appsettings)
|
||||
- Password hash: PBKDF2 (Identity default)
|
||||
- CORS whitelist chỉ 2 FE origin
|
||||
- SQL injection: EF Core parameterized (không raw SQL trừ khi phải)
|
||||
- Audit log: mọi ghi phải log qua `ContractApproval` hoặc `AuditLog` (future)
|
||||
- Rate limit: `/api/auth/login` 5 req/min/IP (chưa implement — Phase 5)
|
||||
|
||||
## 9. Liên quan
|
||||
|
||||
- [`CLAUDE.md`](../CLAUDE.md) — entry point cho AI agent
|
||||
- [`architecture.md`](architecture.md) — kiến trúc chi tiết (layered, CQRS, state machine)
|
||||
- [`gotchas.md`](gotchas.md) — pitfalls đã gặp
|
||||
- [`database/database-guide.md`](database/database-guide.md) — DB conventions
|
||||
- [`flows/`](flows/) — sequence diagram per feature
|
||||
Reference in New Issue
Block a user