[CLAUDE] Skill: thêm 3 skill ops project-specific
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m47s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m47s
Khảo sát alirezarezvani/claude-skills repo — phần lớn skill đã có ở user-level (code-reviewer, sql-database-assistant, focused-fix, senior-frontend, mcp-builder...). Bulk import sẽ trùng + nhiều skill là doc-dump generic không có YAML when-to-use. Thay vào đó: viết 3 skill PROJECT-SPECIFIC encode kiến thức SOLUTION_ERP-only mà generic không thể biết: - dependency-audit-erp: dotnet list --vulnerable + npm audit cho fe-admin/fe-user, respect pin constraint MediatR 12.4.1 + Swashbuckle 6.9.0 + Node 20.x, dẫn chiếu gotchas, output template + CI integration TODO Phase 5.1 - ef-core-migration: 8 migration history + 3-file rule + Design TimeDbContextFactory + 6 pitfalls cụ thể (bao gồm cascade vs restrict cho WorkflowDefinitionId), workflow add entity mới end- to-end, prod apply via idempotent script - iis-deploy-runbook: 3 IIS site topology + win-acme cert + NSSM gitea-runner shared VIETREPORT + LibreOffice 25.8.6 headless, debug playbook 500/502/SignalR/login, deploy steps + manual emergency, rotate creds + backup commands, dẫn chiếu gotcha #25/26/28/29 Skills README cập nhật: 6 skill (3 domain + 3 ops). CLAUDE.md + docs/CLAUDE.md sync count. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
205
.claude/skills/ef-core-migration/SKILL.md
Normal file
205
.claude/skills/ef-core-migration/SKILL.md
Normal file
@ -0,0 +1,205 @@
|
||||
---
|
||||
name: ef-core-migration
|
||||
description: Tạo/sửa/revert EF Core 10 migration cho SOLUTION_ERP. Dùng khi thêm entity mới, thay đổi schema, rollback migration, debug DesignTimeDbContextFactory fail. Đã có 8 migration sẵn (Init → AddVersionedWorkflows). Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ.
|
||||
when-to-use:
|
||||
- "thêm migration"
|
||||
- "EF Core migration"
|
||||
- "dotnet ef migrations add"
|
||||
- "revert migration"
|
||||
- "schema DB update"
|
||||
- "DbContext change"
|
||||
- "snapshot lỗi"
|
||||
- "DesignTimeDbContextFactory"
|
||||
---
|
||||
|
||||
# EF Core Migration — SOLUTION_ERP
|
||||
|
||||
> **Context:** .NET 10 + EF Core 10 + SQL Server. DbContext: `ApplicationDbContext` ở `Infrastructure/Persistence/`. Startup: `SolutionErp.Api`.
|
||||
|
||||
## Migration history (8 migration hiện có)
|
||||
|
||||
| # | Name | Tables added / changed |
|
||||
|---|---|---|
|
||||
| 1 | `Init` | 7 Identity tables (AspNetUsers/Roles/UserRoles/...) |
|
||||
| 2 | `AddMasterData` | Suppliers, Projects, Departments |
|
||||
| 3 | `AddPermissions` | MenuItems, Permissions |
|
||||
| 4 | `AddForms` | ContractTemplates, ContractClauses |
|
||||
| 5 | `AddContractsWorkflow` | Contracts, ContractApprovals, ContractComments, ContractAttachments, ContractCodeSequences |
|
||||
| 6 | `AddNotifications` | Notifications |
|
||||
| 7 | `AddWorkflowTypeAssignments` | WorkflowTypeAssignments (legacy admin override) |
|
||||
| 8 | `AddVersionedWorkflows` | WorkflowDefinitions, WorkflowSteps, WorkflowStepApprovers + `Contracts.WorkflowDefinitionId` FK |
|
||||
|
||||
Total: **24 bảng** dbo + `__EFMigrationsHistory`. Xem `docs/database/schema-diagram.md` ERD đầy đủ.
|
||||
|
||||
## Commands (chạy từ root repo)
|
||||
|
||||
### Thêm migration mới
|
||||
|
||||
```powershell
|
||||
# Sau khi chỉnh Domain entity + EF config + DbContext DbSet
|
||||
dotnet ef migrations add <MigrationName> `
|
||||
--project src/Backend/SolutionErp.Infrastructure `
|
||||
--startup-project src/Backend/SolutionErp.Api `
|
||||
--output-dir Persistence/Migrations
|
||||
```
|
||||
|
||||
**Naming convention:** PascalCase, verb prefix:
|
||||
- `Add<Thing>` — thêm entity / bảng
|
||||
- `Update<Thing>` — thay đổi schema
|
||||
- `Remove<Thing>` — xóa column / table
|
||||
- `Rename<Thing>` — đổi tên
|
||||
|
||||
### Apply migration to DB
|
||||
|
||||
```powershell
|
||||
# Dev: LocalDB SolutionErp_Dev
|
||||
dotnet ef database update `
|
||||
--project src/Backend/SolutionErp.Infrastructure `
|
||||
--startup-project src/Backend/SolutionErp.Api
|
||||
|
||||
# Hoặc đơn giản: chạy API → DbInitializer tự Migrate
|
||||
dotnet run --project src/Backend/SolutionErp.Api
|
||||
```
|
||||
|
||||
### Revert 1 migration (rollback)
|
||||
|
||||
```powershell
|
||||
# Rollback về migration trước đó (ví dụ về sau AddWorkflowTypeAssignments)
|
||||
dotnet ef database update AddWorkflowTypeAssignments `
|
||||
--project src/Backend/SolutionErp.Infrastructure `
|
||||
--startup-project src/Backend/SolutionErp.Api
|
||||
|
||||
# Xóa file migration (3 file, xem dưới)
|
||||
dotnet ef migrations remove `
|
||||
--project src/Backend/SolutionErp.Infrastructure `
|
||||
--startup-project src/Backend/SolutionErp.Api
|
||||
```
|
||||
|
||||
### Gen SQL script (review trước khi apply prod)
|
||||
|
||||
```powershell
|
||||
# Script từ 1 migration → latest
|
||||
dotnet ef migrations script AddWorkflowTypeAssignments `
|
||||
--project src/Backend/SolutionErp.Infrastructure `
|
||||
--startup-project src/Backend/SolutionErp.Api `
|
||||
--output tmp/migration-7-to-8.sql
|
||||
|
||||
# Idempotent (check if exists trước mỗi operation)
|
||||
dotnet ef migrations script --idempotent `
|
||||
--project src/Backend/SolutionErp.Infrastructure `
|
||||
--startup-project src/Backend/SolutionErp.Api
|
||||
```
|
||||
|
||||
## 3-file rule (BẮT BUỘC commit đủ)
|
||||
|
||||
Mỗi `migrations add` sinh **3 file** — phải commit đủ:
|
||||
|
||||
```
|
||||
src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/
|
||||
├── {Timestamp}_{Name}.cs ← migration logic (Up/Down)
|
||||
├── {Timestamp}_{Name}.Designer.cs ← model snapshot tại thời điểm migration
|
||||
└── ApplicationDbContextModelSnapshot.cs ← current model state (được overwrite mỗi migration)
|
||||
```
|
||||
|
||||
**Gotcha #17:** Thiếu `ModelSnapshot.cs` → `migrations add` kế tiếp sẽ sinh duplicate columns. Thiếu `Designer.cs` → không revert được.
|
||||
|
||||
## Pitfalls thường gặp
|
||||
|
||||
### P1 — DesignTime DbContext resolve fail
|
||||
|
||||
**Triệu chứng:** `dotnet ef migrations add` → `Unable to resolve service for type 'DbContextOptions<ApplicationDbContext>'`.
|
||||
|
||||
**Nguyên nhân:** EF tooling chạy đứng ngoài runtime DI, cần factory riêng.
|
||||
|
||||
**Fix:** Đã có `src/Backend/SolutionErp.Infrastructure/Persistence/DesignTimeDbContextFactory.cs`. Nếu connection string thay đổi → update factory, không chỉ `appsettings.json`.
|
||||
|
||||
### P2 — Table rename / column rename gen ra DROP + CREATE
|
||||
|
||||
**Triệu chứng:** Migration sinh `DropColumn` + `AddColumn` thay vì `RenameColumn` → mất data.
|
||||
|
||||
**Fix:** Sửa migration thủ công sang `migrationBuilder.RenameColumn(...)`. Hoặc dùng `[Column("newname")]` attribute để EF tự detect rename.
|
||||
|
||||
### P3 — Query filter (soft delete) khi thêm FK
|
||||
|
||||
**Triệu chứng:** Warning `The entity type 'X' has a global query filter but referencing entity 'Y' doesn't. This may lead to inconsistent results`.
|
||||
|
||||
**Fix:** Entity reference cũng phải có query filter:
|
||||
```csharp
|
||||
builder.HasQueryFilter(x => !x.IsDeleted);
|
||||
```
|
||||
|
||||
Hoặc dùng `.IgnoreQueryFilters()` cho query cần bypass.
|
||||
|
||||
### P4 — FK cascade/restrict khác với expectation
|
||||
|
||||
**Triệu chứng:** Migration apply OK nhưng DELETE parent → cascade sang child (hoặc ngược lại restrict block).
|
||||
|
||||
**Fix:** Explicit config trong `IEntityTypeConfiguration<T>`:
|
||||
```csharp
|
||||
builder.HasOne(x => x.Contract)
|
||||
.WithMany(c => c.Approvals)
|
||||
.HasForeignKey(x => x.ContractId)
|
||||
.OnDelete(DeleteBehavior.Cascade); // hoặc Restrict, SetNull
|
||||
```
|
||||
|
||||
**Case study quan trọng:** `Contracts.WorkflowDefinitionId` → `WorkflowDefinitions.Id` **PHẢI dùng `Restrict`** để protect HĐ cũ khi admin archive version (xem `workflow-contract.md` invariants).
|
||||
|
||||
### P5 — Nullable reference type gen column NOT NULL
|
||||
|
||||
**Triệu chứng:** Property `public string? Description` → migration gen `NOT NULL`.
|
||||
|
||||
**Fix:** Check `builder.HasQueryFilter` chỗ config, hoặc explicit `builder.Property(x => x.Description).IsRequired(false)`.
|
||||
|
||||
### P6 — `AddVersionedWorkflows` duplicate seed
|
||||
|
||||
**Case study hiện tại:** Nếu thêm migration mới sau `AddVersionedWorkflows`, cẩn thận KHÔNG trigger `DbInitializer.SeedWorkflowDefinitionsAsync` 2 lần. Check `if (!db.WorkflowDefinitions.Any())` trong DbInitializer.
|
||||
|
||||
## Workflow khi thêm entity mới (example: add AuditLog)
|
||||
|
||||
```
|
||||
1. Domain/AuditLogs/AuditLog.cs — tạo entity (BaseEntity hoặc AuditableEntity)
|
||||
2. Infrastructure/Persistence/Configurations/AuditLogConfiguration.cs
|
||||
- ToTable("AuditLogs")
|
||||
- Unique index trên (EntityType, EntityId) nếu cần
|
||||
3. Infrastructure/Persistence/ApplicationDbContext.cs
|
||||
- public DbSet<AuditLog> AuditLogs => Set<AuditLog>();
|
||||
4. Application/Common/Interfaces/IApplicationDbContext.cs
|
||||
- DbSet<AuditLog> AuditLogs { get; }
|
||||
5. dotnet ef migrations add AddAuditLogs
|
||||
6. Review file .cs sinh ra → OK
|
||||
7. dotnet ef database update → LocalDB apply
|
||||
8. Test: dotnet run → check bảng được tạo
|
||||
9. Commit [CLAUDE] Domain+Infra: add AuditLog entity + migration
|
||||
10. ⚠️ UPDATE docs/database/schema-diagram.md (ERD + migration table)
|
||||
11. UPDATE docs/STATUS.md nếu là work lớn
|
||||
```
|
||||
|
||||
## Apply prod (VPS)
|
||||
|
||||
```powershell
|
||||
# Trên VPS, sau khi deploy code:
|
||||
# Option 1: auto migrate — DbInitializer.MigrateAsync() chạy khi API startup
|
||||
# Option 2: manual script
|
||||
dotnet ef migrations script <LastApplied> --idempotent --output migrate.sql
|
||||
# Review migrate.sql → chạy qua sqlcmd:
|
||||
sqlcmd -S .\SQLEXPRESS -d SolutionErp -U vrapp -P <pw> -i migrate.sql
|
||||
```
|
||||
|
||||
**Prod safety:**
|
||||
- Backup trước: `scripts/backup-sql.ps1`
|
||||
- Dry-run idempotent script local trước
|
||||
- Test rollback plan: script from-N-to-M-1 sẵn
|
||||
|
||||
## Code pointers
|
||||
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/ApplicationDbContext.cs` — 24 DbSet
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/DesignTimeDbContextFactory.cs` — EF tooling factory
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/DbInitializer.cs` — seed + warn + migrate runtime
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/Configurations/` — 24 IEntityTypeConfiguration
|
||||
- `src/Backend/SolutionErp.Application/Common/Interfaces/IApplicationDbContext.cs` — interface Application layer
|
||||
|
||||
## Related
|
||||
|
||||
- `docs/database/database-guide.md` — conventions + migration workflow chi tiết
|
||||
- `docs/database/schema-diagram.md` — ERD 24 bảng
|
||||
- `docs/gotchas.md` #7, #17 — migration pitfalls
|
||||
Reference in New Issue
Block a user