[CLAUDE] Docs+Memory: S35 wrap — FE forms + G-H2 BE CRUD + FE Admin deploy prod end-to-end

Cumulative S35 3 commit + 3 CI Run #242/#243/#244 ALL PASS:
- `c3cd343` FE inline forms 5 satellite × 2 app cookie-cutter (+1758 LOC)
- `909655c` G-H2 BE CRUD HrmConfig 16 endpoint (+576 LOC NEW)
- `021674a` G-H2 FE Admin HrmConfigsPage declarative (+1388 LOC)

## Updates this commit (docs CI skip per gotcha #41)
- docs/STATUS.md S35 wrap header (cumulative 3 chunk + Multi-agent ROI ~250K)
- docs/HANDOFF.md S35 brief + S36 backlog 6 option
- docs/gotchas.md +#53 sub-agent truncation/stall pattern S35 × 3 occurrence + Quick reference 28
- docs/changelog/sessions/2026-05-28-s35-fe-inline-forms-g-h2.md NEW session log
- 4 sub-agent MEMORY auto-updated entry (Implementer + CICD + Reviewer + Investigator S35 spawns)

## Patterns reinforced cumulative S35
- Pattern 12-ter (within-module N-satellite) 6× cumulative
- Pattern 12-bis (cross-module catalog mega) 3× cumulative
- Pattern 16-bis (4-place mirror cross-app) 6× — staticMap 4th place mandatory (gotcha #50)
- Smart Friend 9× cumulative clean (S22+S25+S29×2+S33×2+S35×3)
- NEW: Declarative KIND_CONFIG Record pattern (single-page multi-kind CRUD reuse)

## Smart Friend Implementer 3 catch S35 (anti-pattern prevention)
1. Chunk 2 MaxLength validator vs EF config mismatch → aligned EF source-of-truth
2. Chunk 2 HRM entities NO HasQueryFilter → explicit .Where(!IsDeleted) 8 site
3. Chunk 3 em main spec gap Layout staticMap miss → Implementer enforced Pattern 16-bis 4-place

## State chốt S35
- 35 mig unchanged · 71 tables · ~185 endpoints (+16 HRM Configs)
- 43 FE pages (+1 HrmConfigsPage) · 130 test PASS unchanged
- 53 gotcha (+1 #53) · 27 memory user-level · 6 skills · 4 sub-agents

## Multi-agent ROI S35 ~250K
- Implementer 3 spawn ~80K (3 cookie-cutter chunk + Smart Friend × 3 catch)
- Investigator 1 spawn ~8K (G-H2 BE CRUD pre-flight + NamGroup MISS verdict)
- Reviewer 3 spawn ~60K (Smart Friend 9× clean, 2 truncated + 1 tight brief PASS)
- CICD 4 spawn ~70K (warm-up + 3 deploy verify, 1 stalled em main fallback)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-28 10:23:55 +07:00
parent 021674a66a
commit 8afdc1e826
8 changed files with 382 additions and 3 deletions

View File

@ -154,6 +154,8 @@ Flag commit nếu thấy `<PackageReference Include="MediatR" Version="14...` ho
## 📅 Recent activity (last 10 FIFO)
- **2026-05-28 (S35 Plan G-H2 Task 3 BE CRUD 16 endpoint pre-commit — PASS, Smart Friend 8× CLEAN):** 2 NEW file BE-only `HrmConfigFeatures.cs` 439 LOC + `HrmConfigsController.cs` 137 LOC. Independent verify: build clean 0 warning 0 error, tests **130/130 PASS** (58 Domain + 72 Infra) baseline preserved. **Cat 1 Wire BE**: 0 mock/alert/TODO marker. 8 ConflictException throws (4 Create UNIQUE Code/composite + 4 Update Code/composite-change guard). Holiday Update line 196-198 correctly checks composite `(Year, Date)` BOTH fields trên condition `entity.Year != req.Year || entity.Date != req.Date` (not just one). Delete handler `db.X.Remove(entity)` → AuditingInterceptor.cs:56-62 auto-convert State Deleted → Modified + IsDeleted=true + DeletedAt + DeletedBy (verified file read). **Cat 2 URL routing**: 16 endpoint kebab-case exact match spec: `leave-types`/`holidays`/`shifts`/`ot-policies` (file line 19/49/79/109 verified). **Cat 3 Anti-fiddle**: chỉ 2 NEW file BE (git status confirm), 0 touch FE/Domain/EF Config/Migration/DbInitializer/test. **Cat 4 Authorization**: class-level `[Authorize]` line 15 + 12 per-action `[Authorize(Roles = "Admin")]` (4 sub-resource × 3 write verb POST/PUT/DELETE) — exact mirror CatalogsController precedent line 12-46. **Cat 5 Validator**: 8 AbstractValidator class (4 Create + 4 Update). Smart Friend fix #1 verified — MaxLength MATCH EF source-of-truth: LeaveType.Code=50 (config line 14) ✓, ShiftPattern.Code=20 (config line 14) ✓, OtPolicy.Code=50 (config line 15) ✓, all Name=200/Description=500 ✓, ShiftPattern.WorkDays=100 (config line 16) ✓. Special validators: LeaveType.DaysPerYear≥0, Holiday.Year ∈ [2000,2100], Shift.StartTime≠EndTime + BreakMinutes≥0 + WorkDays NotEmpty, OtPolicy 3 Multiplier≥1.0 + 3 MaxHours>0. **Cat 6 Cookie-cutter 12-bis 3×**: 4 region structure identical (DTO + List + Create cmd/validator/handler + Update cmd/validator/handler + Delete cmd/handler). Naming consistent ListXQuery/CreateXCommand pattern. Smart Friend fix #2 verified — 4 HRM entities NO HasQueryFilter (grep Configurations confirm 9 file HasQueryFilter NONE are HRM) → 4 List handler correctly add `.Where(!IsDeleted)` line 37/134/232/337 + 8 Create/Update Conflict check `&& !x.IsDeleted` predicate explicit. **MediatR + FluentValidation auto-scan** Application assembly (DependencyInjection.cs:14-19) — no manual DI registration needed. **Smart Friend 8× cumulative CLEAN**: (1) S22 #44, (2) S25 #48, (3) S29 password, (4) S29 ApplicableType, (5) S33 BW, (6) S33 Plan B Phase 2, (7) S35 FE forms (em main earlier), (8) S35 Plan G-H2 NOW. KHÔNG lower bar — actual catches 0 CRITICAL/MAJOR. **2 MINOR observed (defer Phase 1.5)**: (a) ListHolidaysQuery KHÔNG có `bool? IsActive` filter (chỉ Q + Year) — khác 3 query sibling có IsActive filter — inconsistent UX nhưng có thể intentional (holidays admin thường list all). (b) OtPolicy claim "1 default IsActive=true unique" (entity comment line 7) nhưng handler Create/Update KHÔNG enforce "chỉ 1 active" — admin có thể tạo nhiều IsActive=true cùng lúc. Future G-P1 attendance reference `IsActive=true` sẽ ambiguous nếu có 2+ active. Defer fix khi G-P1 implement (em main spec rõ defer phase 1.5). **Verdict: PASS proceed commit**. Token cost ~9K.
- **2026-05-26 (S33 Plan B G-H1 Phase 2 Task 4+5+6 pre-commit — PASS, Smart Friend 6× CLEAN):** Em main spawn em adversarial review 17 file uncommitted (3 BE new + 6 FE new + 6 FE mod + 2 Task 6 mod). **Independent verify SHA256 mirror 3 file PASS IDENTICAL**: `types/employee.ts` ccfc70666568, `EmployeesListPage.tsx` dc859c897c5c, `EmployeeCreatePage.tsx` c796f25d01ac — admin == user exact. **Cat 1 Wire BE**: 5 endpoint `GET /employees` (paged) + `GET /{id}` + `POST` (CreatedAtAction) + `PUT /{id}` (NoContent + ID match guard) + `DELETE /{id}` (soft NoContent) — tất cả real `mediator.Send`, 0 mock marker. Validator Create+Update đầy đủ (Phone MaxLen 20 + EmailAddress conditional When + decimal `.GreaterThanOrEqualTo(0)` lương/phép). Handler Create: load User (FindByIdAsync) → check existing EmployeeProfile UNIQUE (soft-deleted aware: throw ConflictException with distinct message) → atomic MaNhanVien codeGen SERIALIZABLE → entity save. Handler Get: Include 5 satellite + LEFT JOIN User/Department + projection. Handler List: filter Status + DepartmentId + Search (EmployeeCode/FullName Contains) + paging. **Cat 2 Schema**: Mig `AddEmployeeProfiles` timestamp 20260526110207 (= Mig 34 numeric by sort) — `EmployeeProfiles` + 5 satellite + `EmployeeCodeSequences` (7 table mới). UNIQUE indexes verified `IX_EmployeeProfiles_UserId` (line 309-313) + `IX_EmployeeProfiles_EmployeeCode` (line 293-297). FK Cascade Users. 6 Province/District/Ward cột plain Guid? defer FK G-H2 đúng comment. `EmployeeProfileConfiguration.cs` line 22-32 mirror Mig: UNIQUE + Cascade. MenuKeys.cs `All[]` line 108-114 đã có Hrm + HrmHoSo (line 112) — Admin auto-grant qua SeedAdminPermissionsAsync iterates All[]. DbInitializer.cs line 1484-1485 seed Hrm Order=28 + HrmHoSo Order=1 dưới Hrm parent. 28 không xung đột với Budgets=27. SeedDemoEmployeeProfilesAsync line 1945 NOT gated DemoSeed (placed OUTSIDE gate block) — đúng infrastructure pattern gotcha #51 lesson. **Cat 3 Security**: `[Authorize]` class-level present EmployeesController line 20 — no per-action policy yet (em main defer Phase 1.5). Input validation Create + Update Validator class đầy đủ. **Cat 4 Code quality**: TS6 erasableSyntaxOnly compliant — 10 enum dùng const-object pattern + `typeof X[keyof typeof X]`. Named exports (no default trừ App). Bundle size 1.43MB admin / 1.35MB user comparable baseline. ContactRound icon verified exist 5 places trong lucide-react bundle. DependencyInjection.cs line 39 registered `AddScoped<IEmployeeCodeGenerator, EmployeeCodeGenerator>`. **Cat 5 Test**: defer Phase 1.5 per em main spec UAT mode. Baseline 120/120 PASS preserved. **Smart Friend 6× cumulative CLEAN**: (1) S22 #44, (2) S25 #48, (3) S29 Plan CA password ≥12, (4) S29 Plan B ApplicableType, (5) S33 Plan C BW, (6) S33 Plan B Phase 2 NOW. KHÔNG lower bar — actual catches 0 MAJOR/CRITICAL. **3 MINOR observed (defer Phase 1.5)**: (a) Race condition EmployeeCode UNIQUE dưới SERIALIZABLE OK risk THẤP (per-year reset, mirror PE/HD pattern proven). (b) UpdateCommand 3 bool field IsCommunistParty/IsYouthUnion/IsTradeUnion không nullable → admin update partial sẽ accidentally reset (FE phải re-send all 3 every PUT — minor UX issue). (c) Delete handler `DateTime.UtcNow` direct không inject IDateTimeProvider — consistent existing PE/Contract Delete pattern, accept. **Special check verdicts**: gotcha #51 infrastructure seed gate compliance ✓ (em main cite gotcha #51 explicit comment line 1942-1944). gotcha #50 Layout staticMap mirror ✓ (Hrm_HoSo:/employees cả fe-admin line 57 + fe-user line 79). menuKeys.ts FE drift: pre-existing fe-admin minimal (16 key) vs fe-user (24 key) — em main Task 5 chỉ add Hrm 2 key cả 2 file, KHÔNG break Plan AA + Budget. Drift là pre-existing FE state intentional, không phải regression Plan B Phase 2. **Verdict**: PASS proceed commit. Token cost ~30K. Tag: `[adversarial-pass, hrm-mig34, smart-friend-6x-clean, phase-10]`.
- **2026-05-26 (S33 Plan C B-Wrap test bundle pre-commit — PASS, INDEPENDENT VERIFY 9/9 tests):** Em main spawn em adversarial Plan C B-Wrap Contract V2 test bundle review. 4 file mới: TestCurrentUser (31 LOC stub), ContractWorkflowServiceApproveV2Tests (BW1-4+7, 5 [Fact]), CreateContractCommandApplicableTypeTests (BW5, 1 [Fact]), ContractV2SchemaPersistenceTests (BW6 split 3 [Fact]). Total 9 [Fact]. **Independent verify ran `dotnet test --filter` → 9/9 PASS local trong 4.7s** (em main claim 120/120 baseline tăng từ 111 — verified). Spec mapping verify Cat 1: BW1 ContextNote `"Hoàn tất Cấp 1, sang Cấp 2 cùng Bước 1"` ✓ match service line 360, BW2 mã HĐ `"FLOCK01/HĐTP/SOL&BTBM/01"` ✓ match ContractCodeGenerator HĐTP format line 21, BW3 ContextNote `"Approver skip thẳng tới Bước 3 Cấp 2"` ✓ match service line 348 (lastStepIdx=2, lastLevelMaxOrder=2, prefix `[Approver skip thẳng tới Bước 3 Cấp 2 (NV cuối) — bỏ qua các Bước/Cấp trung gian]`), BW4 ForbiddenException `"Bước 1...Cấp 1: bạn không có"` ✓ match service line 263-264, BW5 ConflictException `"ApplicableType=Contract"` ✓ match handler line 84-85 (test correctly handles spec→actual exception type discrepancy: spec says ValidationException, actual ConflictException — em main inline comment line 84 docs the discrepancy), BW7 ConflictException `"skipToFinal chỉ hỗ trợ HĐ V2"` ✓ match service line 105-106. Schema verify Cat 2: Mig `AddContractLevelOpinions` (timestamp 20260522052240) actual position 33 by filename sort confirmed via Glob (33 mig + 33 designer + 1 snapshot in /Persistence/Migrations folder), spec ref "Mig 33" matches. UNIQUE composite `(ContractId, ApprovalWorkflowLevelId)` confirmed `ContractLevelOpinionConfiguration.cs:34`. FK Cascade Contract + FK Restrict Level confirmed line 27+32 + migration FK line 41+47. Test quality Cat 5: assertions specific (`Should().Be(2)` for levelOrder, `Should().Contain(...)` for substring match, `Should().ThrowAsync<X>()` with WithMessage wildcard), each [Fact] sets up fresh `IdentityFixture` + `using` disposal pattern (BW1-4+7 verbose using-block, BW6 `using var fix` shorthand — minor style inconsistency but functional same). Smart Friend independence note: **5 lần cumulative Smart Friend catches — em main + Implementer làm TỐT lần này, KHÔNG có catch MAJOR**. (1) S22 #44, (2) S25 #48, (3) S29 ApplicableType, (4) S29 DemoSeed, (5) S33 BW = clean. Implementer + em main spec mapping accurate, exact string match between assertions and service strings. **Minor (3, defer):** (a) `CreateService` helper method `ContractWorkflowServiceApproveV2Tests.cs:27-44` unused dead code — 5 [Fact] manually recreate inline (cleaner but DRY violation). Cleanup recommend Plan C-Hotfix or next test bundle. (b) `TestCurrentUser.Roles` constructor params `string[] roles` allows null → defensive `roles ?? Array.Empty<string>()` line 27 OK but C# warning shadow. (c) BW6 split 3 [Fact] cleanly separated DUPLICATE + UPSERT + Cascade per spec — 9 tests OK not over-engineer (each invariant tested isolated). **Defer noted**: ApproveV2Async still ~150 LOC, BW1-4+7 cover happy + terminal + skip + outsider + V1 fallback — Plan B-Wrap roadmap mentions BW Bonus future test: OR-of-N multi-NV (3 NV cùng Cấp 1, only 1 needs approve), idempotent UPSERT (Cấp 1 approve → reject → approve lại same row Comment update), Mig 32 seed idempotent guard. Not blocker for current bundle commit. Token cost spawn ~22K. Verdict: **PASS proceed commit** (9 [Fact] all pass independent verify, spec match service exact, schema 3 invariant tested, 0 critical/major, 3 minor cosmetic). Recommendation: commit 4 file as proposed, baseline tăng 111→120. Tag: `[adversarial-pass, test-bundle, contract-v2, smart-friend-5x-clean]`.