61e9ce5b3b053b17ef497f928efdf9dd55b21352
13 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 61e9ce5b3b |
[CLAUDE] Domain+App+Api+Tests+FE-Admin+FE-User: S34 Plan 3 Phase 1.5 batch 4 item
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m48s
Phase 1.5 backlog G-H1 EmployeeProfile hardening batch (Items 6+2+1+4 of 6). Item 6 — menuKeys FE drift sync × 2 app: - fe-admin add: Catalogs + 4 Catalog leaves + Workflows + Budgets + Bg_List/Create/Pending (10 key) - fe-user add: Budgets + Bg_List/Create/Pending + ApprovalWorkflowsV2 + 2 AwV2 leaf + MenuVisibility + Workflows (8 key) - Cả 2 file giờ identical mirror BE MenuKeys.cs (28 key cumulative) Item 2 — UpdateEmployeeProfileCommand bool→bool? safe partial update: - 3 field IsCommunistParty/IsYouthUnion/IsTradeUnion → bool? - Handler: HasValue check, null = giữ giá trị cũ (Reviewer minor #(b) S33 fixed) - FE không bắt buộc gửi 3 field every PUT — tránh accidental reset Item 1 — EmployeesController per-action policy (gotcha #44 mitigation): - Class-level [Authorize(Policy = "Hrm_HoSo.Read")] — non-admin thiếu Read → 403 - POST [Authorize(Policy = "Hrm_HoSo.Create")] - PUT [Authorize(Policy = "Hrm_HoSo.Update")] - DELETE [Authorize(Policy = "Hrm_HoSo.Delete")] Item 4 — Test bundle Phase 1.5 (+10 [Fact], baseline 120 → 130/130 PASS): - EmployeeCodeGeneratorTests (3 [Fact]) — atomic SERIALIZABLE NV/YYYY/NNNN + first call + sequential increment + year boundary preserve old year - CreateEmployeeProfileCommandTests (4 [Fact]) — Create handler edge case + first profile + duplicate UserId Conflict + soft-deleted Conflict-restore + UserNotFound NotFoundException - ListEmployeesQueryTests (3 [Fact]) — filter + paging logic + status filter + departmentId filter + search by EmployeeCode partial Implementer Case 3 test gen caught spec mismatch (allow new after soft-delete vs throws Conflict-restore) — chose CODE source of truth + renamed test documenting discriminator message branch. Em main verify behavior correct (admin UX khôi phục thay vì tạo mới — explicit flow defer Phase 1.5+). Verify: - dotnet build PASS (2 warn DocxRenderer baseline, 0 error) - dotnet test 130/130 PASS (58 Domain + 72 Infra = +10) - 4 endpoint /api/employees policy wired (gotcha #44 active mitigation) - 4 MEMORY agent updated post-spawn (CICD Run #238 + Implementer test bundle) Deferred Phase 1.5 next batch: - Item 3 Satellite CRUD endpoints (WorkHistory/Education/FamilyRelation/Skill/ Document) + FE inline edit forms — heavy ~2-3h - Item 5 UAT smoke non-admin role verify silent 403 catch — defer post-deploy Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| ea440da990 |
[CLAUDE] Domain+App+Api+Infra+FE-Admin+FE-User: S34 Plan 2 G-O1 Danh bạ nội bộ
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m46s
Phase 10.2 Văn phòng số — Internal Directory (1 endpoint reuse Users + EmployeeProfiles + Departments, FE card grid avatar/dept/email/phone/Ext). BE Task 1+2 (em main solo): - Application/Office/DirectoryFeatures.cs — GetDirectoryQuery + DirectoryItemDto 12 field LEFT JOIN Users.IsActive + Departments + EmployeeProfiles - Api/Controllers/DirectoryController.cs — GET /api/directory?search=&departmentId= class-level [Authorize] (mọi authenticated NV tra cứu danh bạ nội bộ) - MenuKeys.cs +Off+OffDanhBa const + All[] update - DbInitializer.SeedMenuTreeAsync Off Order=29 + OffDanhBa Order=1 dưới Off FE Task 3 (Implementer Case 2 Pattern 16-bis 4-place mirror cross-app — 5×): - types/directory.ts SHA256 7349d9f64e78 × 2 app IDENTICAL - pages/office/InternalDirectoryPage.tsx SHA256 2aa7e0eed2c8 × 2 app IDENTICAL Card grid responsive 1/2/3/4 col + filter dept dropdown + search input Avatar 14×14 initials gradient PALETTE 6 màu (Pattern 14 Tailwind JIT) EmployeeCode badge + Department emerald badge + email mailto + phone tel Internal phone Ext: amber badge + empty/loading state Vietnamese 100% - App.tsx route /directory × 2 app - lib/menuKeys.ts Off+OffDanhBa const × 2 app - components/Layout.tsx resolvePath staticMap Off_DanhBa:/directory × 2 app (gotcha #50 — 5 places mirror crossapp DON'T MISS) Verify: - dotnet build PASS (2 warn DocxRenderer existing, 0 error) - dotnet test 120/120 PASS (58 Domain + 62 Infra baseline preserve) - npm build × 2 app PASS 0 TS err (fe-admin 1436KB / fe-user 1350KB) Implementer MEMORY Pattern 16-bis reinforced 5× cumulative (S29 Plan CA HF1 + S29 Plan B Chunk D + S33 Plan B G-H1 Task 5 + S34 Plan G-O1 Task 3). Endpoint smoke pending CICD post-deploy Stage 4 (Run #XXX expected ~3m30s). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 9616ae219c |
[CLAUDE] FE-Admin+FE-User: Plan B G-H1 Task 5 — EmployeesPage 2-panel + EmployeeCreatePage cookie-cutter mirror
Phase 10.1 G-H1 Phase 2 Task 5 — FE 2 app cookie-cutter mirror PE pattern.
Phase 1 ULTRA-MINIMAL scope (Implementer afdc812 scaffold):
- 2-panel ListPage (filter left + list+detail right, KHÔNG 3-panel vì Hrm
no workflow)
- 6-section inline collapsible detail (Cơ bản/Công tác/Đào tạo/Thân nhân/
Kỹ năng/Hồ sơ) — NO separate DetailTabs component file
- CreatePage Header form minimal (UserId picker + Status + DateOfBirth +
Gender + Phone + HireDate + Nationality)
- Display read-only Phase 1 satellite (no inline edit — defer Phase 1.5)
## Files (6 new + 6 modified × 2 app = 12)
### NEW (3 × 2 app, SHA256 IDENTICAL cross-app mirror)
| File | LOC | SHA256 prefix |
|------|----:|---|
| `fe-{admin,user}/src/types/employee.ts` | 283 | CCFC70666568 |
| `fe-{admin,user}/src/pages/hrm/EmployeesListPage.tsx` | 417 | DC859C897C5C |
| `fe-{admin,user}/src/pages/hrm/EmployeeCreatePage.tsx` | 178 | C796F25D01AC |
10 const-object enum mirror BE Domain.Hrm.Enums + DTOs:
- EmployeeStatus/Gender/MaritalStatus/EmployeeType/DegreeLevel/
EducationMode/GradeLevel/FamilyRelationKind/SkillKind/EmployeeDocumentType
- EmployeeListItem + EmployeeDetail + 5 satellite DTO type
### MODIFIED (3 × 2 app)
- `fe-{admin,user}/src/lib/menuKeys.ts` — +Hrm + HrmHoSo const
- `fe-{admin,user}/src/components/Layout.tsx` — +Hrm_HoSo:'/employees' staticMap
(LESSON Plan CA Hotfix 1 gotcha #50: page route mới phải thêm staticMap
entry cùng commit, else silent sidebar drop)
- `fe-{admin,user}/src/App.tsx` — +2 route /employees + /employees/new
## Pattern reinforcement
- **Pattern 16-bis 4-place mirror cross-app** reinforced 4× cumulative (S29
Plan CA HF1 + S29 Plan B Chunk D + S33 Task 5 admin + S33 Task 5 user).
Comment header trong Layout.tsx ghi explicit Plan CA Hotfix 1 #50 lesson.
- **Pattern 12-bis cross-module entity FE port PE → Hrm** reinforced 4× (Plan
B Chunk C Mig 33 + G-H1 Task 4 BE + Task 5 FE types mirror PE types/page
structure mirror PE 2-panel scope-down 3→2 panel).
## Reviewer ae752c0 verdict: PASS (commit
|
|||
| 059bfcbe38 |
[CLAUDE] FE-Admin+Domain: Chunk C — MenuVisibilityPage + menu key + seed
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
Session 20 turn 7 Chunk C. FE Admin page quản lý Ẩn/Hiện + Đổi tên menu
cho fe-user (eOffice). Admin sidebar fe-admin LUÔN dùng Tên gốc — page này
KHÔNG đụng admin navigation (user Q2=b).
Domain MenuKeys.cs:
+const MenuVisibility = "MenuVisibility"
All[] thêm MenuVisibility (giữa Permissions + Workflows)
DbInitializer SeedMenuTreeAsync:
+leaf (MenuVisibility, "Menu eOffice", System, 94, "Eye")
Workflows shift Order 94 → 95
Idempotent — chỉ INSERT nếu chưa có trong DB
Manual seed Mig 27 LocalDB Dev: INSERT MenuItems + Permissions cho Admin role
FE Admin:
- types/menu.ts: MenuItem/MenuNode +isVisible bool +displayLabel string|null
- lib/menuKeys.ts: +MenuVisibility const
- components/Layout.tsx resolver +MenuVisibility → /system/menu-visibility
- App.tsx +Route + import MenuVisibilityPage
NEW pages/system/MenuVisibilityPage.tsx (~210 LOC):
- PageHeader + 4 StatCard (Tổng / Hiển thị / Đã ẩn / Đã đổi tên)
- Search input (key | label | displayLabel)
- Table: Key (mono + parentKey ↳) | Tên gốc | Input "Tên hiển thị" inline
(placeholder "Mặc định: ...") | Toggle Hiển thị/Ẩn (emerald/amber) |
Lưu (khi dirty) / Khôi phục (khi đã custom)
- PATCH /menus/{key} body { isVisible, displayLabel } — trim whitespace,
empty string → null
- onSuccess: invalidate ['menus', 'all'] + ['my-menu'] + clear draft entry
- "Khôi phục mặc định" button: PATCH isVisible=true, displayLabel=null
- Footer hint: nhắc admin sidebar luôn dùng Tên gốc, đổi tên áp eOffice
Verify:
- npm run build × fe-admin pass
Pending Chunk D: FE Layout fe-user filter !isVisible + render displayLabel
Pending Chunk E: Docs S20 turn 7
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 937eb2449c |
[CLAUDE] Workflow V2: clone leaf Designer + sample seed cho DuyetNccPhuongAn (B)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m16s
Mở rộng V2 schema cho type B mirror type A đã chốt S17. Phần lớn đã chung qua ApplicableType discriminator — chỉ thêm menu key + sample seed. Changes: - MenuKeys.cs: +const ApprovalWorkflowDuyetNccPhuongAnV2 (AwV2_DuyetNccPhuongAn) + add vào All array - DbInitializer.SeedMenusAsync: +leaf "Duyệt NCC và Giải pháp (Mới)" dưới root ApprovalWorkflowsV2 - DbInitializer +SeedSampleApprovalWorkflowsV2Async: seed QT-DN-PA-V2-001 v01 (1 Bước Phòng CCM × 1 Cấp NV test) Idempotent — skip nếu admin đã tạo bất kỳ workflow B nào hoặc thiếu test user - fe-admin/lib/menuKeys.ts: +AwV2_DuyetNccPhuongAn KHÔNG đụng: - Migration (V2 schema chung qua ApplicableType — Mig 22-24 đã hỗ trợ B) - Service ApproveV2Async (không hardcode type) - Designer page ApprovalWorkflowsV2Page (TYPE_CODE_TO_INT đã có B=2) - Layout/App.tsx (regex AwV2_(.+) match dynamic) - Permission default (admin bypass + role khác không cần Designer access) Verify: dotnet build pass · 81 test pass · npm build fe-admin pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 2781c7ea09 |
[CLAUDE] FE-Admin: Designer Quy trình duyệt mới V2 (Chunk C)
Page mới `/system/approval-workflows-v2/:typeCode` mirror Designer cũ
nhưng theo schema Mig 22:
Bước (Phòng) > N Cấp (mỗi cấp = 1 NV cụ thể qua Select duy nhất)
Files:
- fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx (new — 480 LOC)
- Overview cards (Active version + History list per ApplicableType)
- DefinitionCard read-only render Bước → Cấp với approver name + email
- Designer dialog: Mã/Tên/Mô tả + reorder Step/Level (chevron up/down)
+ Add/Remove Step + Add/Remove Level + Select Phòng + Select NV duyệt
- Validate: mỗi Step phải có ≥1 Level, mỗi Level phải có approverUserId
- Auto-assign code QT-DN-V2-001 / QT-DN-PA-V2-001 / QT-HD-V2-001
- fe-admin/src/lib/menuKeys.ts (+2 const sync với BE MenuKeys)
- fe-admin/src/components/Layout.tsx (resolver: ApprovalWorkflowsV2 root +
AwV2_<TypeCode> leaf → /system/approval-workflows-v2/<code>)
- fe-admin/src/App.tsx (import + 2 route)
Verify: npm build fe-admin OK, 1924 modules transformed, 0 TS error.
Next: Chunk D — STATUS + HANDOFF + CLAUDE.md update + final commit.
|
|||
| 66c1a5c170 |
[CLAUDE] Rebrand: 3 domain huypham.vn → solutions.com.vn + migrate script
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m52s
User request: anh trỏ 3 subdomain mới về VPS IP 103.124.94.38:
- api.huypham.vn → api.solutions.com.vn
- admin.huypham.vn → admin.solutions.com.vn
- user.huypham.vn → eoffice.solutions.com.vn
Verified DNS: cả 3 resolve 103.124.94.38 ✓
Update 17 file repo:
FE (4): fe-admin/.env.production + fe-user/.env.production
(VITE_API_BASE_URL → https://api.solutions.com.vn)
fe-admin/src/lib/{api,realtime}.ts + fe-user equivalents (comment)
BE (1): appsettings.Production.json.example — CORS AllowedOrigins
CI/CD (1): .gitea/workflows/deploy.yml — smoke test URL
Scripts (3): setup-iis-sites (DomainApi/Admin/User), setup-ssl (3 host),
deploy-all (verify curls)
Docs (5): STATUS, HANDOFF, PROJECT-MAP, vps-setup, gotchas
Skill (1): iis-deploy-runbook — 3 site table + description
Email admin@huypham.vn giữ nguyên (Let's Encrypt contact — không phải
domain serve).
Thêm scripts/migrate-domains.ps1 — 1-shot VPS migration:
1. Pre-flight: resolve DNS 3 domain → verify IP VPS khớp
2. Add HTTP binding mới cho 3 IIS site (giữ binding cũ làm fallback)
3. Run win-acme xin 3 cert Let's Encrypt qua HTTP-01 challenge
(auto add HTTPS binding + http→https redirect)
4. Verify /health/live + /health/ready + 2 FE endpoint
5. (Optional -RemoveOld) xóa binding huypham.vn sau verify OK
Rollback: nếu fail, binding cũ vẫn active → site serve qua huypham.vn.
Anh chạy trên VPS:
cd C:\solution-erp\scripts ; .\migrate-domains.ps1
# Sau 1-2 ngày verify stable:
.\migrate-domains.ps1 -RemoveOld -SkipCert
|
|||
| a737196b21 |
[CLAUDE] FE-Admin+FE-User: PurchaseEvaluation pages (3-panel list + tabs detail)
Types + pages + components cho module Duyệt NCC ở cả 2 FE (copy-share). Pages: - PurchaseEvaluationsListPage: 3-panel lg:grid-cols-[340px_1fr_360px] * Panel 1: list filter theo type/phase/search + pendingMe inbox mode * Panel 2: PeDetailTabs (Thông tin/NCC/Hạng mục/Duyệt/Lịch sử) * Panel 3: PeWorkflowPanel với timeline + nextPhase buttons * Mobile fallback fullpage /purchase-evaluations/:id - PurchaseEvaluationCreatePage: form create/edit header (Type / Tên gói thầu / Dự án / Địa điểm / Mô tả / PaymentTerms JSON). Suppliers+Details+Quotes thêm sau khi save ở Detail tabs. Components: - PeDetailTabs: 5 tab + dialogs (AddSupplier/EditSupplier/DetailDialog/ QuoteDialog) + matrix N NCC × M hạng mục clickable cells + select winner - PeWorkflowPanel: policy timeline từ BE workflow.activePhases + transition confirmation dialog với comment Routes (cả 2 app): - /purchase-evaluations (+ ?type=1|2&pendingMe=1&id=...) - /purchase-evaluations/new (+ ?type / ?id để edit) - /purchase-evaluations/:id (mobile fullpage) Menu resolver: - Pe_<Code>_List → /purchase-evaluations?type=N - Pe_<Code>_Create → /purchase-evaluations/new?type=N - Pe_<Code>_Pending → /purchase-evaluations?type=N&pendingMe=1 - PeWf_<Code> (fe-admin only) → /system/pe-workflows/<code> Skip MVP: PE Workflow admin designer UI, PE Attachments. TS build pass cả 2 app. |
|||
| ea9ab5e352 |
[CLAUDE] App+Infra+Api+FE: SignalR realtime notifications E2E
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m43s
Clean-arch split: - Application: IRealtimeNotifier (PushToUserAsync, abstraction) - Api: NotificationHub (/hubs/notifications, [Authorize]) + SignalRNotifier impl với IHubContext<NotificationHub>, uses Clients.User(userId) (default provider resolves NameIdentifier="sub") - Infrastructure: NotificationPushInterceptor — SaveChangesInterceptor capture Notification entities state=Added trong SavingChanges, push qua IRealtimeNotifier trong SavedChanges sau khi commit thành công. Zero caller changes — handlers chỉ cần db.Add(Notification). Attached vào ApplicationDbContext cùng với AuditingInterceptor. Auth: - JWT config thêm OnMessageReceived event: read ?access_token= từ query string khi path = /hubs/* (WebSockets không set headers). - SignalRNotifier singleton (stateless, chỉ delegate IHubContext). FE (both apps): - @microsoft/signalr 8.0.7 vào package.json. - lib/realtime.ts: singleton connection với lazy start + automatic reconnect [0,2s,5s,10s,15s] + accessTokenFactory lấy từ localStorage. - NotificationBell: useEffect subscribe 'notification-created' khi isAuthenticated. On push: invalidate query + toast.message. Fallback polling giảm từ 30s → 60s (realtime cover gap). - AuthContext.logout: dynamic import stopConnection() — avoid leaking auth'd socket across users. Result: ERP-grade feel. Contract transition → Drafter nhận toast ngay trong vòng 100-300ms (same-origin WebSocket), không cần F5 hay polling. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| b1a4571c86 |
[CLAUDE] VPS setup scripts + SSL + runner + FE prod config + master runbook
Scripts moi (PowerShell admin trên VPS Windows Server):
- setup-sql-db.ps1: tao DB SolutionErp + grant db_owner cho vrapp (user shared voi VIETREPORT). Idempotent.
- setup-iis-sites.ps1: app pool SolutionErp-Api (NoManagedCode + AlwaysRunning + no idle) + 3 site (SolutionErp-Api/Admin/User) voi host header, C:\inetpub\solution-erp\{api,fe-admin,fe-user,logs,uploads}. Placeholder index.html + SPA web.config voi URL rewrite fallback + security headers. Firewall rule. ACL grant AppPool identity Modify. Naming prefix SolutionErp-* tranh conflict VIETREPORT.
- setup-ssl.ps1: download win-acme v2.2.9 → issue cert Let's Encrypt 3 domain (api/admin/user.huypham.vn) qua HTTP-01 challenge + auto install IIS binding + HTTP→HTTPS redirect + scheduled task 90d renew.
- setup-gitea-runner.ps1: download act_runner.exe → register voi Gitea git.baocaogiaoduc.vn, install Windows service, labels windows-latest,self-hosted,windows,x64 (cho phep share voi VIETREPORT).
FE production config:
- fe-admin/.env.production + fe-user/.env.production: VITE_API_BASE_URL=https://api.huypham.vn
- fe-admin/src/lib/api.ts + fe-user/src/lib/api.ts: BASE_URL = (import.meta.env.VITE_API_BASE_URL ?? '') + '/api'
- Dev: empty prefix → /api qua Vite proxy :5443
- Prod: https://api.huypham.vn/api (cross-origin CORS da config AllowedOrigins)
Docs:
- docs/guides/vps-setup.md MOI (master runbook): prereq, 4 script chay theo thu tu, set 5 Gitea secrets, first deploy, appsettings.Production.json pattern (file hoac user-secrets), smoke test 3 curl, post go-live checklist (doi admin password, rotate secrets chat-exposed, backup schedule, disable Swagger prod, monitor logs), table co-existence VIETREPORT
- CLAUDE.md root: add vps-setup.md reference
Gitea repo da setup (extern):
- https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp (private)
- Secrets set via API: IIS_HOST=103.124.94.38, IIS_USER=Administrator, DB_CONNECTION (voi vrapp password), JWT_SECRET placeholder
- CON THIEU: IIS_PASSWORD (Windows admin — user cung cap), JWT_SECRET real value (64-char tu vps-jwt-key.txt — user update qua Gitea UI)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 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>
|
|||
| 54d6c9ba52 |
[CLAUDE] Phase1.2: CRUD Master + Permission Matrix + FE admin pages
Backend:
- Domain/Master: Supplier (+ SupplierType 5 loai), Project, Department (AuditableEntity)
- Domain/Identity: MenuItem, Permission, MenuKeys const (12 menu)
- EF Configurations voi unique Code + query filter IsDeleted
- DbSets + IApplicationDbContext interface update
- Application: PagedResult + PagedRequest generic
- Application/Master CQRS CRUD 3 entity (Create/Update/Delete/Get/List voi paging search sort)
- Application/Permissions: GetMyMenuTree (union OR role, filter tree), ListMenuItems, ListPermissionsByRole, UpsertPermission (guard admin khong tu giam quyen), ListRoles
- Api/Authorization: MenuPermissionRequirement + Handler (Admin bypass, query DB)
- Program.cs: register 48 policy {menu}.{action} tu MenuKeys x Actions
- Api/Controllers: Suppliers, Projects, Departments, Menus, Roles, Permissions
- DbInitializer: seed 12 menu + admin full CRUD permissions
- Migration AddMasterData + AddPermissions
Frontend (fe-admin):
- Types: menuKeys.ts const, menu.ts (MenuNode/Role/Permission), master.ts (Supplier/Project/Department + SupplierType const-object)
- AuthContext: load menu from /menus/me, cache localStorage, refreshMenu()
- usePermission hook + PermissionGuard component (wrap button)
- UI kit them: Dialog (modal overlay), Textarea, Select
- Generic: DataTable (column config, sortable, loading, empty) + Pagination
- PageHeader component
- apiError helper extract message tu ProblemDetails
- Layout rewrite: render menu dong tu AuthContext.menu (MenuGroup collapsible + NavLink + lucide icon map)
- Pages: master/Suppliers, master/Projects, master/Departments (CRUD + search + sort + paging + Dialog form)
- Page system/Permissions: ma tran Role x MenuKey x CRUD checkbox (tick tu dong PUT upsert)
- App.tsx them 4 route moi
Bug fix:
- MenuPermissionHandler: EF expression tree khong support switch expression -> tach switch ra ngoai AnyAsync
- TS erasableSyntaxOnly khong cho enum -> SupplierType const-object pattern (typeof[keyof])
E2E verified via Vite proxy:
- GET /menus/me -> 6 root + 6 child nodes (12 menus)
- GET /roles -> 12 roles
- POST/GET/PUT/DELETE /suppliers -> full CRUD, soft delete OK
- tsc -b fe-admin pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 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> |