Files
solution-erp/docs/HANDOFF.md
pqhuy1987 f3fb3fd565 [CLAUDE] Phase5 prep: production infra + deploy scripts + 4 guides + FE refresh token
Backend production infra:
- Packages: Serilog.Sinks.File, HealthChecks.EntityFrameworkCore (RateLimiting built-in .NET 10)
- appsettings.Production.json MOI: placeholder __SET_VIA_SECRETS__, AllowedOrigins, Serilog File sink rolling daily retention 30d, RateLimit config
- appsettings.json + Development.json: them Serilog WriteTo Console
- Program.cs REWRITE:
  - Serilog ReadFrom.Configuration (prod file / dev console)
  - Rate limiter: policy auth-login 5/min/IP (AuthController.Login) + GlobalLimiter 300/min/IP
  - Health checks: /health/live liveness (empty predicate) + /health/ready DB probe (AddDbContextCheck)
  - HSTS production 1 year
  - CORS origins from config AllowedOrigins (default dev 2 localhost)
- AuthController.Login gắn [EnableRateLimiting("auth-login")]

Deploy scripts:
- scripts/deploy-iis.ps1: stop pool → backup current → clean+extract artifact → start pool → health check loop 30s timeout → rollback instruction if fail
- scripts/backup-sql.ps1: BACKUP DATABASE voi INIT+COMPRESSION+CHECKSUM + retention 30d auto cleanup
- .gitea/workflows/deploy.yml MOI: 4 job build BE (Windows) + build 2 FE (Ubuntu, pin .nvmrc 20) + deploy-iis qua WinRM PSSession (secrets IIS_HOST/USER/PASSWORD/JWT_SECRET/DB_CONNECTION)

Docs guides MOI (4 file):
- deployment-iis.md: prereqs (IIS features, Hosting Bundle, SQL, WinRM) + setup lan dau (app pool, 3 site, HTTPS win-acme, user-secrets) + deploy hang ngay (CI/CD + manual) + rollback + monitoring + troubleshooting + SPA web.config sample
- cicd.md: pipeline overview 4 job, secrets setup, runner Windows+Ubuntu, branch strategy, build optimizations, common CI/CD issues
- security-checklist.md: OWASP top 10 2021 mapping voi status + pre go-live checklist + incident response
- runbook.md: daily ops (health/logs), restart/rollback, DB backup/restore/migration revert, user management (reset password, unlock, disable), monitoring (CPU/disk/connection pool), deployment checklist, common gotcha

Frontend refresh token (ca 2 app fe-admin + fe-user):
- lib/api.ts REWRITE: them REFRESH_KEY, axios response interceptor 401 → POST /auth/refresh → retry request goc. Queue pattern cho nhieu request song song chi 1 refresh call chay. Skip retry /auth/login + /auth/refresh tranh infinite loop. _retry flag tren original config.
- contexts/AuthContext.tsx: luu+xoa REFRESH_KEY trong login/logout

E2E verified:
- GET /health/live → 200 Healthy
- GET /health/ready → 200 Healthy (DB probe)
- Rate limit flood 7 POST /auth/login → #1-5 HTTP 400 (cred sai) + #6-7 HTTP 429 Too Many Requests 
- TS check fe-admin + fe-user → pass
- dotnet build → 0 errors

Docs updates:
- docs/STATUS.md: Phase 5 prep done, next Phase 5 deploy production + Phase 5.1 security hardening, cumulative stats 8 commits
- docs/HANDOFF.md: phase table them Phase 5 prep row, file tree update voi guides + scripts + workflows, git state commit 8
- docs/changelog/migration-todos.md: tick Phase 5 prep items (12 items done) + Phase 5 deploy items remaining + Phase 5.1 security hardening list
- docs/changelog/sessions/2026-04-21-1530-phase5-prep.md: session log chi tiet

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

203 lines
9.4 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.

# HANDOFF — Brief 5 phút cho session tiếp theo
**Last updated:** 2026-04-21 15:30 (cuối Phase 5 Prep)
## Ở đâu rồi?
| Phase | Trạng thái |
|---|---|
| 0 Draft | ✅ Done |
| 1 Alpha Core foundation | ✅ Done |
| 1 Alpha Core đợt 2 (CRUD + Permission) | ✅ Done |
| 2 Form Engine MVP | ✅ Done |
| 2 Form Engine iteration 2 | 📝 Optional |
| 3 Workflow MVP (9 phase + code gen) | ✅ Done |
| 3 Workflow iteration 2 (SLA + notify + attachment) | 📝 Optional |
| 4 Report MVP (Dashboard + Excel) | ✅ Done |
| 4 Report iteration 2 | 📝 Optional |
| **5 Prep (infra + scripts + guides + refresh token)** | ✅ Done |
| 5 Deploy production (cần Gitea URL) | 📋 Next |
| 5.1 Security hardening (headers, lockout, IDOR) | 📋 Queue |
## Run nhanh
```powershell
# Terminal 1 — API (auto seed 8 template lần đầu)
dotnet run --project src\Backend\SolutionErp.Api
# Terminal 2 — Admin FE
cd fe-admin && npm run dev # → http://localhost:8082
# Terminal 3 — User FE
cd fe-user && npm run dev # → http://localhost:8080
```
Login: `admin@solutionerp.local` / `Admin@123456`
Điểm cần test ngay (Phase 4 MVP):
- **Admin `/dashboard`** → 5 KPI card + By Phase bar + Monthly chart + Top NCC/dự án
- **Admin `/reports`** → filter phase/date → Export Excel .xlsx 10 cột có formula SUM
- **fe-user `/contracts/new`** → tạo HĐ draft (Phase 2 DangSoanThao, SLA +7d)
- **fe-user `/inbox`** → xem HĐ chờ role mình xử lý
- **`/contracts/{id}`** → click "Duyệt → tiếp" chạy state machine. Phase 8 gen `MaHopDong` RG-001
- **`/forms`** → render template .docx
- **`/system/permissions`** → ma trận Role × MenuKey
- **`/master/suppliers|projects|departments`** → CRUD
## Cần làm kế tiếp (ưu tiên)
### A. Phase 5 — Production (tuần 12-13, item lớn nhất còn lại)
**Đọc trước:** `docs/changelog/migration-todos.md` section Phase 5.
- [ ] `.gitea/workflows/deploy.yml` CI/CD build + deploy IIS
- [ ] `scripts/deploy-iis.ps1` stop app pool → xcopy → start
- [ ] Windows Server IIS + URL Rewrite + ARR (reverse proxy FE → .NET)
- [ ] HTTPS cert via win-acme hoặc mua
- [ ] `appsettings.Production.json` + user secrets + JWT secret rotation
- [ ] Rate limiting middleware (auth endpoint 5 req/min/IP)
- [ ] Security audit OWASP top 10
- [ ] Health check endpoint `/health`
- [ ] Serilog → file rolling daily retention 30d
- [ ] SQL backup: daily full + 15min log
- [ ] Runbook: restart, rollback migration, restore backup
- [ ] UAT production 1 tuần với 2-3 user thật
- [ ] Go-live checklist
### B. Polish iterations (optional — khi rảnh)
**Phase 2 iter 2:** convert 3 .doc qua Word COM `DisplayAlerts=0` hoặc LibreOffice, field spec JSON + form builder FE dynamic, `{{#loop}}` block support, PDF convert, FE upload template multipart.
**Phase 3 iter 2:** `SlaExpiryJob` BackgroundService auto-approve, email (MailKit) + in-app (SignalR) notify, upload attachment endpoint + FE multipart (`wwwroot/uploads/contracts/{id}/`), RowVersion concurrency, render HĐ docx khi tạo (merge TemplateId + DraftData + ContractClause).
**Phase 4 iter 2:** SLA overdue report by role/phase, PDF HĐ export (LibreOffice), dashboard user-specific (role tôi).
### C. Phase 2 iteration 2 (form engine polish)
- Convert 3 file `.doc` qua Word COM `DisplayAlerts=0` + timeout, hoặc LibreOffice
- Field spec JSON per template + dynamic form builder FE
- `{{#loop}}...{{/loop}}` block support cho table lặp
- PDF convert via LibreOffice headless
- Admin upload template UI (multipart)
### D. Quick wins (không block phase)
- FE Users management + Roles CRUD (test permission với non-admin user thật)
- Filter Inbox theo phase FE
- Refresh token auto (FE axios interceptor retry 401)
## Lưu ý kỹ thuật quan trọng
**Đọc [`gotchas.md`](gotchas.md) trước khi:**
- Thêm package mới → check compat với .NET 10 (MediatR 14 fail → dùng 12)
- Debug 404 API → kiểm Program.cs có persist không (Dropbox issue)
- Expression tree error → tách switch ra ngoài LINQ
- TS enum error → dùng const-object pattern (`erasableSyntaxOnly`)
- Word COM stuck → kill + fallback LibreOffice
- Migration lỗi → check 3 file đầy đủ (Designer + Migration + Snapshot)
## File đang active
```
SOLUTION_ERP/
├── src/Backend/ (Clean Arch, 4 project, .NET 10)
│ ├── SolutionErp.Domain/
│ │ ├── Common/ BaseEntity, AuditableEntity
│ │ ├── Contracts/ ContractType, ContractPhase, ApprovalDecision + **Contract, ContractApproval, ContractComment, ContractAttachment, ContractCodeSequence** ← Phase 3
│ │ ├── Forms/ ContractTemplate, ContractClause ← Phase 2
│ │ ├── Identity/ User, Role, MenuItem, Permission, AppRoles, MenuKeys
│ │ └── Master/ Supplier, Project, Department, SupplierType
│ ├── SolutionErp.Application/
│ │ ├── Auth/ Login, Refresh, Me
│ │ ├── Common/ Exceptions, Behaviors, Interfaces, Models
│ │ ├── Contracts/ ContractFeatures (8 CQRS), IContractWorkflowService, IContractCodeGenerator, DTOs ← Phase 3
│ │ ├── Forms/ FormFeatures (List/Get/Render) ← Phase 2
│ │ ├── Master/ Suppliers, Projects, Departments CQRS
│ │ ├── Permissions/ GetMyMenuTree, matrix upsert
│ │ └── Reports/ **DashboardStats, ExportContractsToExcel, IContractExcelExporter** ← Phase 4
│ ├── SolutionErp.Infrastructure/
│ │ ├── Forms/ DocxRenderer, XlsxRenderer, FormRenderer ← Phase 2
│ │ ├── Identity/ JwtSettings, JwtTokenService
│ │ ├── Persistence/ DbContext, DbInitializer, Interceptors, Migrations (**5**)
│ │ ├── Reports/ **ContractExcelExporter** ← Phase 4
│ │ └── Services/ DateTimeService, ContractWorkflowService, ContractCodeGenerator ← Phase 3
│ └── SolutionErp.Api/
│ ├── Authorization/ MenuPermissionHandler + Requirement
│ ├── Controllers/ Auth, Suppliers, Projects, Departments, Menus, Roles, Permissions, Forms, Contracts, **Reports** (10 controller)
│ ├── Middleware/ GlobalExceptionMiddleware
│ ├── Services/ CurrentUserService, WebHostEnvironmentLocator
│ └── wwwroot/templates/ 5 file .docx/.xlsx ← Phase 2
├── fe-admin/ (11 page)
│ └── src/pages/
│ ├── LoginPage
│ ├── DashboardPage ← Phase 4 rewrite (KPI cards + BarChart)
│ ├── master/SuppliersPage, ProjectsPage, DepartmentsPage
│ ├── system/PermissionsPage
│ ├── forms/FormsPage ← Phase 2
│ ├── contracts/ContractsListPage, ContractDetailPage ← Phase 3
│ └── ReportsPage ← Phase 4
├── fe-user/ (5 page)
│ └── src/pages/
│ ├── LoginPage
│ ├── InboxPage ← Phase 3
│ └── contracts/ContractCreatePage, ContractDetailPage, MyContractsPage ← Phase 3
├── docs/ (35 file)
│ ├── STATUS.md, HANDOFF.md, rules.md, architecture.md
│ ├── CLAUDE.md, PROJECT-MAP.md
│ ├── workflow-contract.md, forms-spec.md
│ ├── database/{database-guide, schema-diagram}.md
│ ├── flows/ (7 file — README + 6 flow)
│ ├── guides/ (4 file) — deployment-iis, cicd, security-checklist, runbook ← Phase 5 prep
│ ├── changelog/migration-todos.md + sessions/ (7 session log)
│ └── gotchas.md
├── scripts/ (5 file PS + py)
│ ├── parse_forms.py, parse_workflow.py (Phase 0)
│ ├── convert-doc-to-docx.ps1 (Phase 2)
│ └── deploy-iis.ps1, backup-sql.ps1 ← Phase 5 prep
├── .gitea/workflows/deploy.yml ← Phase 5 prep CI/CD template
└── .claude/skills/ (3 skill — all full spec)
```
## Git state
```
(sẽ là commit 8) — Phase 5 Prep (infra + scripts + guides + refresh token)
fe7ad8e — Phase 4 Report MVP + docs consolidation
7e957a7 — Phase 3 Workflow MVP
5113e4c — Phase 2 Form Engine MVP
54d6c9b — Phase 1.2 CRUD + Permission
49a5f57 — Docs database-guide + flows
702411f — Phase 1 foundation
25dad7f — Phase 0 scaffold
Branch: main
Remote: chưa (Gitea URL CẦN NGAY để Phase 5 go-live)
```
## Credentials + URLs
```
admin@solutionerp.local / Admin@123456
```
- API: http://localhost:5443 (swagger `/swagger`)
- Admin FE: http://localhost:8082
- User FE: http://localhost:8080
- SQL LocalDB: `(localdb)\MSSQLLocalDB` / Database=`SolutionErp_Dev`
## Đánh giá nhanh
**Tốt:**
- Build pass 100% cả BE + FE
- E2E test full 9-phase workflow end-to-end — mã HĐ gen đúng format RG-001
- Docs đầy đủ: 26 file, session log mỗi chunk, gotchas tích lũy 17 pitfall
- Cả 2 FE đều có Contract detail page + timeline + comment thread + state machine action
**Rủi ro còn:**
- SLA chỉ set deadline — không có job auto-approve (Phase 3.2)
- Không có notification (email + in-app) — user phải F5 inbox
- Form render chỉ MVP — loop table + PDF chưa có
- Permission matrix chưa test thực với non-admin user
- 3 file .doc chưa convert (carryover Phase 2)
- Không có upload attachment endpoint (chỉ có entity + DTO)