Files
solution-erp/docs/changelog/migration-todos.md
pqhuy1987 702411fcc8 [CLAUDE] Phase1: foundation - BE Clean Arch + Identity + JWT + 2 FE React + login E2E
Backend (.NET 10):
- Domain: BaseEntity/AuditableEntity, ContractType/Phase/ApprovalDecision enums, User/Role (Identity<Guid>), AppRoles (12 const)
- Application: IApplicationDbContext/ICurrentUser/IDateTime/IJwtTokenService, custom exceptions, ValidationBehavior (MediatR pipeline), Auth CQRS (Login/Refresh/Me), DependencyInjection
- Infrastructure: ApplicationDbContext (IdentityDbContext), AuditingInterceptor (auto audit + soft delete), DbInitializer (seed 12 role + admin), DesignTimeDbContextFactory, JwtTokenService, DateTimeService, DI
- Api: CurrentUserService, GlobalExceptionMiddleware (ProblemDetails), AuthController, Program.cs rewrite (Serilog + JWT + CORS + Swagger), appsettings + launchSettings (port 5443)
- Migration Init applied to SolutionErp_Dev LocalDB

Frontend (React 19 + Vite 8 + Tailwind 4):
- fe-admin (:8082 blue) + fe-user (:8080 emerald) - shared structure, khac menu + brand color
- Tailwind 4 via @tailwindcss/vite plugin, theme brand colors
- AuthContext (localStorage token), ProtectedRoute, Layout (sidebar + header)
- UI kit: Button/Input/Label (CVA + Tailwind)
- LoginPage voi toast error, DashboardPage/InboxPage placeholder
- Axios interceptor: auto Bearer + 401 redirect
- TanStack Query client, React Router 7, Sonner toast

Package downgrades (do .NET 10 / TS 6 compat):
- MediatR 14 -> 12.4.1 (v14 breaking changes)
- Swashbuckle 10 -> 6.9.0 (v10 khong tuong thich OpenApi 2)
- Removed Microsoft.AspNetCore.OpenApi (conflict voi Swashbuckle)

E2E verified: POST /api/auth/login qua Vite proxy ca 2 FE -> JWT + user info

Credentials seed: admin@solutionerp.local / Admin@123456

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 10:59:44 +07:00

160 lines
9.3 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.

# Migration To-dos — Atomic Roadmap
> Mỗi item là 1 task atomic (~2-8h work). Tick `[x]` khi xong. Link session log nếu có.
## Phase 0 — Draft Scaffold (T1)
- [x] Tạo cấu trúc thư mục `SOLUTION_ERP/`
- [x] Scaffold .NET 10 solution `SolutionErp.slnx`
- [x] Scaffold 4 project: `SolutionErp.{Domain, Application, Infrastructure, Api}`
- [x] Wire Clean Arch references (Api → App/Infra, Infra → App, App → Domain)
- [x] Install NuGet base: MediatR, FluentValidation, AutoMapper, EF Core SqlServer, Identity, JWT, Swagger, Serilog
- [x] Scaffold 2 React + Vite apps `fe-admin` + `fe-user` với TS template
- [x] Config vite.config.ts: port, strictPort, proxy `/api`, alias `@`
- [x] Pin Node `>=20` trong package.json + `.nvmrc` cho CI
- [x] Parse 8 form → `docs/forms-spec.md`
- [x] Parse quy trình → `docs/workflow-contract.md`
- [x] Viết `docs/{CLAUDE,STATUS,PROJECT-MAP}.md`
- [x] Viết `.gitignore`, `README.md`, `global.json`, `docker-compose.yml`
- [x] Tạo placeholder skill folders: `contract-workflow`, `form-engine`, `permission-matrix`
- [x] `git init` + commit đầu (`25dad7f`)
- [ ] Push Gitea remote (chờ URL từ user)
## Phase 1 — Alpha Core (T2-4)
### Foundation (đã xong Session 2)
- [x] `Domain/Common/BaseEntity.cs` (Id Guid, CreatedAt, UpdatedAt, CreatedBy, UpdatedBy)
- [x] `Domain/Common/AuditableEntity.cs` (IsDeleted, DeletedAt, DeletedBy)
- [x] `Domain/Contracts/` Enums: `ContractType`, `ContractPhase` (9 state), `ApprovalDecision`
- [x] `Domain/Identity/User.cs` (IdentityUser<Guid> + FullName + RefreshToken + IsActive)
- [x] `Domain/Identity/Role.cs` (IdentityRole<Guid> + Description)
- [x] `Domain/Identity/AppRoles.cs` — 12 role constants
- [x] `Application/Common/Interfaces/`: IApplicationDbContext, ICurrentUser, IDateTime, IJwtTokenService
- [x] `Application/Common/Exceptions/*`
- [x] `Application/Common/Behaviors/ValidationBehavior.cs`
- [x] `Application/DependencyInjection.cs` — MediatR + FluentValidation
- [x] `Infrastructure/Persistence/ApplicationDbContext.cs : IdentityDbContext`
- [x] `Infrastructure/Persistence/Interceptors/AuditingInterceptor.cs`
- [x] `Infrastructure/Persistence/DbInitializer.cs` — seed 12 role + admin
- [x] `Infrastructure/Persistence/DesignTimeDbContextFactory.cs`
- [x] `Infrastructure/Identity/{JwtSettings, JwtTokenService}.cs`
- [x] `Infrastructure/Services/DateTimeService.cs`
- [x] `Infrastructure/DependencyInjection.cs`
- [x] `Api/Services/CurrentUserService.cs`
- [x] `Api/Middleware/GlobalExceptionMiddleware.cs`
- [x] `Api/Controllers/AuthController.cs` (login, refresh, me, logout)
- [x] `Api/Program.cs` (Serilog, JWT, CORS, Swagger, middleware)
- [x] `Api/appsettings.{json, Development.json}` + `launchSettings.json` (port 5443)
- [x] Migration 1 `Init` + apply to `SolutionErp_Dev` LocalDB
- [x] FE: Vite config (Tailwind 4 + proxy + alias)
- [x] FE: `src/{index.css, lib/api.ts, lib/cn.ts, types/auth.ts}` cho 2 app
- [x] FE: `src/contexts/AuthContext.tsx`, `components/{ProtectedRoute, Layout}.tsx`
- [x] FE: `components/ui/{Button, Input, Label}.tsx`
- [x] FE: `pages/LoginPage.tsx`, `pages/DashboardPage.tsx` (admin) + `pages/InboxPage.tsx` (user)
- [x] FE: `App.tsx` với Router + AuthProvider + Toaster
- [x] FE: `main.tsx` với QueryClient (TanStack Query)
- [x] E2E verified: login qua Vite proxy cả 2 app → JWT + user info
### Phase 1 đợt 2 — CRUD master + Permission Matrix (sắp tới)
- [ ] `Domain/Entities/Supplier` (Code, Name, TaxCode, Phone, Email, Address, Type enum: NCC/NTP/TĐ/ĐVDV)
- [ ] `Domain/Entities/Project` (Code, Name, StartDate, EndDate, ManagerUserId)
- [ ] `Domain/Entities/Department` (Code, Name, ManagerUserId)
- [ ] EF `IEntityTypeConfiguration<T>` cho mỗi entity
- [ ] CQRS CRUD: Create/Update/Delete/GetById/List (với paging) cho 3 entity
- [ ] `Api/Controllers/{SuppliersController, ProjectsController, DepartmentsController}`
- [ ] Migration 2: `AddMasterData`
- [ ] `Domain/Entities/MenuItem` (Key PascalCase, Label, ParentKey, Order, Icon)
- [ ] `Domain/Entities/Permission` (RoleId, MenuKey, CanRead/Create/Update/Delete)
- [ ] Seed default menu tree + permission admin có full access
- [ ] `Application/Permissions/Queries/GetMyMenuTreeQuery` — resolve per-user, cache
- [ ] `Api/Controllers/{MenusController, RolesController, PermissionsController}`
- [ ] Migration 3: `AddPermissions`
- [ ] `Domain/Entities/Contract` skeleton (Id, Type, SupplierId, ProjectId, Phase=DangChon, DraftData JSON)
- [ ] Contract CRUD draft only (không workflow Phase 3)
- [ ] FE: `<PermissionGuard menuKey="Suppliers" action="Update">` + `usePermission()` hook
- [ ] FE Admin: 3 trang CRUD Supplier/Project/Department với table + modal + search/sort
- [ ] FE Admin: Permission Matrix grid page (role × menu × CRUD checkbox)
- [ ] FE User: trang "HĐ của tôi" list + filter
- [ ] Route guard theo role admin-only
- [ ] Update `SolutionErp.slnx` nếu thêm project mới
### Exit criteria Phase 1
- [ ] Admin login → tạo NCC/Project → tạo role "Nhân viên CCM" → gán permission menu "Contracts.Read"
- [ ] User CCM login → thấy menu Contracts, không thấy menu Admin
- [ ] Tạo Contract draft → list hiển thị, không bị 403 sai
## Phase 2 — Form Engine (T5-6)
- [ ] Khảo sát: OpenXml vs Aspose.Words — chọn 1 (Aspose có license phí; OpenXml free nhưng verbose)
- [ ] Convert 3 file `.doc``.docx` (COM automation PowerShell hoặc LibreOffice headless)
- [ ] Parse chi tiết field của 5 template HĐ — mỗi form thành JSON spec
- [ ] `Domain/Entities/ContractTemplate` (Id, FormCode, Name, TemplateFile path, FieldSpec JSON)
- [ ] `Application/Forms/Services/IFormRenderer` — input: template + data dict → output: byte[] (.docx)
- [ ] Implement `DocxRenderer` (OpenXml-based replace placeholder)
- [ ] Implement `XlsxRenderer` cho FO-002.07 (dùng EPPlus/ClosedXML)
- [ ] `Api/Controllers/FormsController` — GET /templates, POST /render
- [ ] FE user: form builder — chọn template → dynamic form → preview → export
- [ ] FE admin: upload template mới, edit field mapping
- [ ] Lưu `ContractClause` (FO-002.04) dạng rich text, admin edit qua TipTap/TinyMCE
- [ ] Import/export template (để backup)
- [ ] Test: 1 HĐ Giao khoán filled → export .docx mở bằng Word y hệt mẫu
## Phase 3 — Workflow State Machine (T7-9)
- [ ] `Domain/Entities/ContractApproval` + `ContractComment` + `ContractAttachment`
- [ ] `Domain/Entities/Contract` update: thêm `Phase`, `SlaDeadline`, `BypassProcurementAndCCM`
- [ ] `Domain/Services/IContractWorkflowService.TransitionAsync(...)` — state guard + role guard + side effects
- [ ] `Infrastructure/Services/ContractCodeGenerator` (implement RG-001) với locking cho seq
- [ ] `Infrastructure/HostedServices/SlaExpiryJob` — check mỗi 15min, auto-approve quá hạn
- [ ] `Infrastructure/Services/NotificationService` — email (MailKit) + in-app (SignalR optional)
- [ ] MediatR behavior: `AuditBehavior` — log mọi command
- [ ] API: `POST /api/contracts/{id}/transitions` body: `{targetPhase, comment}`
- [ ] FE user Inbox: list "HĐ chờ tôi xử lý" (query by current phase + user role)
- [ ] FE Contract detail page: timeline 9 phase, approval panel, comment thread
- [ ] Upload attachment (scan có chữ ký đối tác)
- [ ] Notification UI: badge count, dropdown, click → detail
- [ ] E2E test: happy path end-to-end 1 HĐ qua 9 phase
- [ ] E2E test: reject → quay về DangSoanThao
- [ ] E2E test: SLA expired → auto-approve + log
## Phase 4 — Reporting + Polish (T10-11)
- [ ] Dashboard admin: số HĐ theo phase, top NCC, top dự án, tổng giá trị theo tháng
- [ ] Excel export theo bộ lọc (dùng EPPlus)
- [ ] Report: HĐ quá hạn SLA bao nhiêu lần theo phase/role
- [ ] UX polish: skeleton loader, empty state, error boundary có recovery button
- [ ] Accessibility: keyboard nav, focus trap modal, aria labels
- [ ] Dark mode (optional, nếu rảnh)
- [ ] Performance: index DB cho query hot (SupplierId, ProjectId, Phase)
- [ ] Tài liệu user guide: quy trình tạo HĐ + duyệt
- [ ] UAT với 5-10 HĐ dữ liệu thật từ bộ phận Cung ứng
## Phase 5 — Production (T12-13)
- [ ] `docs/guides/cicd.md` — CI/CD runbook
- [ ] Gitea Actions workflow `.gitea/workflows/deploy.yml` — build .NET + 2 FE, deploy IIS qua SSH/WinRM
- [ ] Pin Node 20.x trong workflow, test CI sớm (không để surprise cuối dự án)
- [ ] `scripts/deploy-iis.ps1` — stop app pool, xcopy, start app pool
- [ ] Windows Server setup: IIS + URL Rewrite + ARR (reverse proxy FE → IIS)
- [ ] SQL Server prod: backup plan daily + weekly full
- [ ] HTTPS certificate (Let's Encrypt qua win-acme hoặc mua cert)
- [ ] `appsettings.Production.json` + user secrets
- [ ] Security audit: owasp top 10 check
- [ ] Rate limiting middleware (AspNetCoreRateLimit hoặc built-in)
- [ ] Health check endpoint `/health` cho IIS probe
- [ ] Error tracking: Serilog → file rolling daily, retention 30 ngày
- [ ] Runbook: restart app, rollback migration, restore backup
- [ ] UAT production 1 tuần với 2-3 user thật
- [ ] Go-live checklist: backup, rollback plan, on-call contact
## Post-launch (Phase 6+ — future)
- [ ] E-signature integration (VNPT CA hoặc FPT CA)
- [ ] Tích hợp Bravo / SAP ERP import NCC
- [ ] Mobile app (React Native?) cho BOD duyệt ngoài giờ
- [ ] AI: gợi ý điền form dựa HĐ cũ, OCR scan HĐ đối tác
- [ ] Multi-tenant nếu có công ty thứ 2