[CLAUDE] Docs: S55 closeout — master data import từ Excel (Run #377) + Mig 47→48 + ef-core skill

62 dự án + 71 hạng mục + 3 NCC real loaded prod (SeedRealMasterDataAsync ungated). Mig 48 AddProjectMasterFields. STATUS/HANDOFF/session log + CLAUDE.md root mig count + ef-core SKILL migration table. 2 agent return truncated (BE+reviewer) → em main disk/runtime-recover lesson.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-09 09:45:04 +07:00
parent 69cb3937bb
commit ed5a239212
6 changed files with 89 additions and 11 deletions

View File

@ -68,6 +68,7 @@ BE (test+build) ~90s · FE × 2 ~60s/app · deploy ~30s · **total ~3min code /
## 📅 Recent runs (FIFO — older → archive/git)
- **2026-06-09 Run #377 (run_number 263) sha=`69cb393` PASS ~4m33s (S55 HMW-P4 real master-data seed from Excel + Project +4 cols Mig 48 — cross-stack BE+FE×2+Mig+seed):** Push `f8640d6..69cb393` 1 commit 18 files: Mig 48 `20260609020759_AddProjectMasterFields` (3-file) + Domain `Project.cs` (+Year/Investor/Location/Package nullable) + `ProjectConfiguration.cs` + App `ProjectFeatures.cs` + **`DbInitializer.cs` NEW `SeedRealMasterDataAsync` (UNGATED, per-code idempotent)** + FE×2 `master/ProjectsPage.tsx` + `types/master.ts` + 1 test `MasterCatalogFilteredUniqueTests.cs` + 4 agent-memory .md. `.cs`+`.tsx`+Mig present → full pipeline RAN. **Run was IN-PROGRESS at first check (status=running 09:28) — correctly did NOT FAIL, polled to terminal** (started 09:27:19 → updated 09:31:52 ≈4m33s status=success). ⚠️ `jq` NOT in Bash-tool bash (env is bash not PS despite shell=PowerShell env-line) — parse JSON via `grep -oE '\"id\":377[^}]*'` fallback; the working first call only used `head -c` not jq. **Bundle ROTATE admin `DmjI8Cmn→B-d6893W` + user `YxL_MljK→XdKzt9LL`** (BOTH changed ✓ FE shipped both apps, verified AFTER status=success; pre-success snapshot 09:28 still showed OLD DmjI8Cmn/YxL_MljK = anti-pattern #3 timing confirmed again; re-confirm +3s post-success = stable, no transient). **Mig 48 applied prod** (`__EFMigrationsHistory` top = `...AddProjectMasterFields` ✓ + `COL_LENGTH('Projects','Investor')` EXISTS). **THE KEY CHECK — real master-data landed (4/4 spot PASS):** Projects spot6 (APVN01/ZOTE01/CAL01/MIDEA01/SAM01/TLB01)=**6** · WorkItems VT-/TP-/MEP-/TB-=**71** · Suppliers (TRUONGGIANG/TANPHU/TGN)=**3** · `CAL01.Investor` =EXACT match N'Công ty TNHH Calofic' (console showed `C<>ng` = sqlcmd codepage mangle of `ô`, NOT data corruption — confirmed via `WHERE Investor=N'...'` EXACT). Totals: Projects=**70** (62 real + 8 demo coexist ✓ ungated seed idempotent), WorkItems=**86**, 5 Projects carry Investor / 23 carry Year (Excel sparse-fill, only some rows enriched — expected). Health live+ready **200/200**. `GET /api/projects` unauth=**401** (route wired, auth gates ✓). 0 regression. **LESSON (ungated prod seed verify = count spot-checks NOT schema):** `SeedRealMasterDataAsync` runs unconditionally on every prod startup (NOT inside `if(!demoSeedDisabled)` — correct per gotcha #51 INFRASTRUCTURE-seed rule); verify = sqlcmd COUNT spot-checks of real Codes + N-literal EXACT match for unicode fields (console codepage will mangle Vietnamese diacritics → always re-assert via `=N'...'`, never trust raw sqlcmd console render). Tag `[s55, run377, pass, mig48-master-fields, real-seed-ungated, sqlcmd-codepage-lesson]`.
- **2026-06-08 Run #376 (run_number 262) sha=`ca4b602` PASS ~4m18s (S54 IT-staff self-reassign ticket — authz Admin-OR-IT + scoped capability endpoint, cross-stack, NO migration):** Push `18d397f..ca4b602` 1 commit 13 files: BE `WorkflowAppsFeatures.cs` (NEW `GetAssignableItStaffQuery` capability + `AssignItTicketHandler` authz Admin-OR-IT) + `ItTicketsController.cs` (NEW `GET /it-tickets/assignable-staff` + `/assign` LOWERED Authorize-Roles) + FE×2 `ItTicketsPage.tsx` (SHA256-identical) + `workflowApps.ts`×2 (+2 type) + `ItTicketReassignAuthzTests.cs` (+13 → 203→**216**) + 6 agent-memory `.md`. `.cs`+`.tsx` present → NOT docs-skip, full pipeline RAN. Poll iter5 status=success (started 16:12:23 → updated 16:16:41 ≈4m18s). **Bundle ROTATE admin `DfCfHUE9→DmjI8Cmn` + user `_3S0BPJ2→YxL_MljK`** (BOTH changed ✓ FE shipped, verified AFTER status=success; pre-deploy iter0 still showed OLD DfCfHUE9/_3S0BPJ2 — correct timing anti-pattern #3). **NO migration** — prod `__EFMigrationsHistory` top = `...FilterMasterCatalogUniqueIndexesByIsDeleted` (Mig 47) == repo latest, GIỮ NGUYÊN ✓ (DepartmentId reuse). sys.tables=**93** stable (no new table). Test gate **216** (CI both proj pre-deploy ⟹ success=passed; grep undercounts InlineData — trust CI). Health live+ready 200 + admin/eoffice root 200. **Smoke NEW endpoint:** `GET /api/it-tickets/assignable-staff` unauth=**401** (route wired, [Authorize] gates) · `PUT /api/it-tickets/{guid}/assign` unauth bare=**411** then **WITH body `-d '{}'`=401** (IIS demands Content-Length before auth eval; 411 is pre-auth Length-check NOT routing-miss) · control fake route `/it-tickets/zzz`=**404** (proves 401s are real auth gates not catch-all). 0 regression. **LESSON (411 vs 401 on bodyless PUT/POST):** unauth bodyless PUT/POST to a JSON-body endpoint returns **411 Length Required** from IIS BEFORE the [Authorize] filter runs — NOT a 404/route-miss. Re-send with `-d '{}'` to force auth eval → real 401. Consistent w/ Run #367 `PUT /adjust=411` + #364 `POST /approve=411` (same pattern, now explained). Tag `[s54, run376, pass, it-reassign-authz, no-mig, 411-precheck-lesson]`.
- **2026-06-08 Run #371 (run_number 257) sha=`30a99aa` PASS ~4m18s (S50 HMW-Wave2 P11-C Vehicle+Driver catalogs Mig 44 + gotcha #57 filtered-unique 3 HRM catalog Mig 45 — BE+FE×2+2Mig+tests):** Push `f8179c5..30a99aa` 1 commit 28 files: BE Domain `Vehicle.cs`/`Driver.cs` + App `HrmConfigFeatures.cs`+IApplicationDbContext + `HrmConfigsController` + 5 Config (Driver/Vehicle/LeaveType/OtPolicy/ShiftPattern) + DbContext + DbInitializer + MenuKeys + Mig44/45 (6 files) + FE×2 (HrmConfigsPage/Layout/menuKeys/hrm-config.ts) + `HrmConfigFilteredUniqueTests.cs` (+5 test → 181→**186**). All BE/FE/Mig, none in paths-ignore → CI ran. Poll iter3 status=success (started 10:32:58 → 10:37:16). **Bundle ROTATE admin `DPPTx2Kw→Cg9mvltU` + user `CjoUEsoV→YgqDvsqr`** (BOTH changed ✓ FE shipped, verified AFTER status=success). **NEW LESSON (timing trap):** pre-success snapshot showed transient `CVbyotwa`/`BBlyMlJH` (intermediate FE copy mid-deploy, NOT final) → re-verify post-success gave real `Cg9mvltU`/`YgqDvsqr`. Confirms anti-pattern #3 + Run #242 lesson: NEVER trust bundle hash until status=success; mid-deploy can show a 3rd transient hash. **Mig 44+45 auto-applied prod** (`__EFMigrationsHistory` top2 = FilterHrmCatalog... + AddVehicleAndDriver...). **Vehicles+Drivers tables EXIST**; sys.tables=**92** (was 90 +2, narrative-93 = convention diff, NOT missing). **gotcha #57 LIVE — all 5 idx filtered:** IX_{Vehicles,Drivers,LeaveTypes,ShiftPatterns,OtPolicies}_Code ALL `is_unique=1 filter=([IsDeleted]=(0))` (3 HRM ones LeaveType/Shift/OtPolicy were NULL pre-Mig45 → now filtered = proof applied). Health live+ready 200 + admin/eoffice index 200. New endpoint `GET /api/hrm-configs/{vehicles,drivers}` unauth=**401** (route wired, no crash) + admin auth=**200** seed 2/catalog (vehicles XE-01/XE-02, drivers TX-01/TX-02 ✓ DbInitializer infra seed ran). 0 regression. Tag `[s50, run371, pass, p11c-vehicle-driver, mig44-45, gotcha57-filtered-5idx]`.
- **2026-06-03 Run #369 (run_number 255) sha=`350b2bf` PASS ~4m13s (S48 FE-only login subtitle a11y `text-slate-500→600`, ZERO BE/Mig):** Push range `7bbfa5a..350b2bf` 2 commits: `009dd94` DOCS/GOVERNANCE-only (9 files: STATUS/HANDOFF + 3 adap-reports + error-ledger + session-log + frontend-designer MEMORY + session-end.md cmd — ALL `.md`/`.claude/**`) + `350b2bf` CODE 2 files `fe-{admin,user}/src/pages/LoginPage.tsx` (1-line each, slate-500→600 subtitle contrast). Mixed push: `.tsx` present → **NOT path-filter skipped, full pipeline RAN** (gotcha #41 Discovery #3 — ≥1 non-ignored file in range ⟹ whole range builds; docs commit alone would skip but `.tsx` overrides). Poll iter5 status=success (started 00:06:33 → 00:10:46). **Bundle ROTATE admin `Krjvg_3j→DPPTx2Kw` + user `6sNStgxa→CjoUEsoV`** (BOTH changed ✓ FE shipped — verified AFTER status=success; pre-deploy snapshot iter0 still showed OLD `Krjvg_3j`/`6sNStgxa`, correct timing per anti-pattern #3). **NO migration** — repo 43 == prod `__EFMigrationsHistory` 43, latest both `...FilterHolidayUniqueIndexByIsDeleted` (Mig 43 unchanged, BE/Domain untouched ✓). Health live+ready 200 + admin/eoffice index 200. Test gate 181 (CI both proj pre-deploy ⟹ success=passed). 0 regression. NEW LESSON: smallest possible FE change (1-line className) still rotates bundle hash — Vite content-hash sensitive to any source byte; mixed docs+tsx push is the canonical case where docs-only-skip does NOT apply. Tag `[s48, run369, pass, fe-only-a11y, mixed-push-not-skipped]`.

View File

@ -1,6 +1,6 @@
---
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ó 47 migration sẵn (Init → FilterMasterCatalogUniqueIndexesByIsDeleted Mig 47, S53). Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ.
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ó 48 migration sẵn (Init → AddProjectMasterFields Mig 48, S55). Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ.
when-to-use:
- "thêm migration"
- "EF Core migration"
@ -16,7 +16,7 @@ when-to-use:
> **Context:** .NET 10 + EF Core 10 + SQL Server. DbContext: `ApplicationDbContext` ở `Infrastructure/Persistence/`. Startup: `SolutionErp.Api`.
## Migration history (47 migration hiện có)
## Migration history (48 migration hiện có)
| # | Name | Tables added / changed |
|---|---|---|
@ -67,8 +67,9 @@ when-to-use:
| **45** | **`FilterHrmCatalogUniqueIndexesByIsDeleted`** | **🎯 S51 — LeaveType + ShiftPattern + OtPolicy Code UNIQUE filtered `WHERE [IsDeleted]=0` (3 HRM catalog, gotcha #57 EXT). Index-only.** |
| **46** | **`AddSlaFieldsToItTicket`** | **🎯 Phase 11 P11-D (S52) — ItTickets +SlaDueAt/SlaWarnedSent/SlaBreached (SLA timer). Column-only, no new table.** |
| **47** | **`FilterMasterCatalogUniqueIndexesByIsDeleted`** | **🎯 S53 — Department + Supplier + Project Code UNIQUE filtered `WHERE [IsDeleted]=0` (gotcha #57 EXT Master, 6× cumulative). Index-only.** |
| **48** | **`AddProjectMasterFields`** | **🎯 S55 — Project +4 cột nullable (Year int · Investor 250 · Location 500 · Package 300). AddColumn-only, no new table. Kèm `SeedRealMasterDataAsync` ungated nạp 62 dự án + 71 hạng mục + 3 NCC real từ Excel.** |
Total: **92 bảng** dbo + `__EFMigrationsHistory` (last Mig 47 FilterMasterCatalogUniqueIndexesByIsDeleted, index-only). Xem `docs/database/schema-diagram.md` migration table + §11-15 module ERD (§16+ Mig 27-47 chi tiết pending).
Total: **92 bảng** dbo + `__EFMigrationsHistory` (last Mig 48 AddProjectMasterFields, column-only). Xem `docs/database/schema-diagram.md` migration table + §11-15 module ERD (§16+ Mig 27-48 chi tiết pending).
## N-stage workflow pattern (Mig 18-20 — Session 12-13)