[CLAUDE] Docs: S124 adap-wave AI_INFRA + owner worker-tier-pin (14 agent opus+effort:max) + user-memory relocate R6 + H24 dogfood
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m26s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m26s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
114
.claude/auto-memory/feedback_declarative_kind_config_pattern.md
Normal file
114
.claude/auto-memory/feedback_declarative_kind_config_pattern.md
Normal file
@ -0,0 +1,114 @@
|
||||
# Pattern Declarative KIND_CONFIG Record — Single-page multi-kind CRUD reuse
|
||||
|
||||
> **Discovered:** S29 Plan CA (Master/Catalogs/CatalogsPage.tsx 321 LOC) — first proven instance.
|
||||
> **Reinforced:** S35 G-H2 FE Admin (Hrm/HrmConfigsPage.tsx ~470 LOC) — Pattern 2× cumulative cross-module.
|
||||
|
||||
## Pattern
|
||||
|
||||
Single-page handle **N kind** of catalog/config via URL `:kind` param + declarative `KIND_CONFIG: Record<Kind, ...>`. KHÔNG split N page riêng (clutter routes + duplicate boilerplate).
|
||||
|
||||
### Structure
|
||||
```tsx
|
||||
type Kind = 'kind-a' | 'kind-b' | ... // union literal (TS6 erasableSyntaxOnly)
|
||||
|
||||
type FieldDef = {
|
||||
key: string
|
||||
label: string
|
||||
type: 'text' | 'textarea' | 'checkbox' | 'number' | 'date' | 'time' | 'select' | 'multiselect-weekday' | ...
|
||||
required?: boolean
|
||||
placeholder?: string
|
||||
step?: number
|
||||
options?: Array<{value, label}>
|
||||
}
|
||||
|
||||
const KIND_CONFIG: Record<Kind, {
|
||||
label: string
|
||||
icon: React.ComponentType<{className?: string}>
|
||||
fields: FieldDef[]
|
||||
columns: string[]
|
||||
}> = {
|
||||
'kind-a': { label, icon, fields: [...], columns: [...] },
|
||||
'kind-b': { ... },
|
||||
}
|
||||
|
||||
export function CatalogPage() {
|
||||
const { kind } = useParams<{kind?: string}>()
|
||||
const config = KIND_CONFIG[kind ?? 'default']
|
||||
// Render sub-tab nav + table + Dialog form (declarative renderField per FieldDef.type)
|
||||
}
|
||||
```
|
||||
|
||||
## Decision
|
||||
|
||||
**Khi nào dùng Pattern Declarative KIND_CONFIG (vs split page):**
|
||||
- N kind ≤ 6, mỗi kind có fields shape DIFFERENT nhưng UX flow SAME (List + Create/Edit dialog + Delete)
|
||||
- KHÔNG có per-kind business logic phức tạp (workflow / approval flow / codeGen)
|
||||
- Mỗi kind chỉ khác fields list + columns
|
||||
- Total page LOC ~300-500 (acceptable single-file maintain)
|
||||
|
||||
**KHÔNG dùng khi:**
|
||||
- Per-kind business logic phức tạp → split per-page (vd Contract type 7 có 7 form khác + 9 phase workflow)
|
||||
- N kind > 6 → file > 1000 LOC khó scan
|
||||
- Fields shape differ rất nhiều (vd file upload field + signature picker mix vào)
|
||||
|
||||
## Example proven cumulative
|
||||
|
||||
### Plan CA Chunk B (S29) — Master/Catalogs
|
||||
- 4 kind: units / materials / services / work-items
|
||||
- File: `fe-admin/src/pages/master/CatalogsPage.tsx` 321 LOC + mirror fe-user
|
||||
- Field shape: code/name + variant per kind (defaultUnit/category/originCountry/etc.)
|
||||
- BE: `/api/catalogs/{kind}` × 4 verb mirror controller
|
||||
|
||||
### S35 G-H2 (this session) — Hrm/HrmConfigs
|
||||
- 4 kind: leave-types / holidays / shifts / ot-policies
|
||||
- File: `fe-admin/src/pages/hrm/HrmConfigsPage.tsx` ~470 LOC + mirror fe-user
|
||||
- Field shape: complex (multiselect-weekday cho ShiftPattern WorkDays + TimeOnly cho startTime/endTime + 3 multiplier OtPolicy)
|
||||
- BE: `/api/hrm-configs/{kind}` × 4 verb mirror controller
|
||||
- NEW FieldDef.type extend: `number/date/time/select/multiselect-weekday`
|
||||
|
||||
## renderField helper extend pattern
|
||||
|
||||
Mỗi kind có thể introduce NEW field type → extend `renderField(field, value, onChange)` switch:
|
||||
- `text/date/time` → `<Input type={field.type}>`
|
||||
- `number` → `<Input type="number" step={field.step}>`
|
||||
- `textarea` → `<Textarea>`
|
||||
- `checkbox` → `<input type="checkbox">`
|
||||
- `select` → `<select>` với `field.options`
|
||||
- `multiselect-weekday` (NEW S35) → 7 checkbox Mon-Sun + comma-join string
|
||||
|
||||
## Reusable cross-project
|
||||
|
||||
- VIPIX: Tags + Categories + Collections (3 catalog) — Pattern fit
|
||||
- NAMGROUP: Loại NV + Phòng ban + Vị trí (3 catalog đơn giản) — Pattern fit
|
||||
- ASHICO: 5-site config + 7-DB selector → có thể adapt
|
||||
- DH_Y_DUOC: Loại sáng kiến + Cấp duyệt (2 catalog) — Pattern fit
|
||||
- BVAAU: Loại bệnh nhân + Bảo hiểm (2-3 catalog) — Pattern fit
|
||||
|
||||
## Pattern relationship
|
||||
|
||||
| Pattern | Scope | Token cost | Notes |
|
||||
|---|---|---|---|
|
||||
| Declarative KIND_CONFIG | Single-page multi-kind CRUD | ~25K Implementer spawn | 1 page + KIND_CONFIG Record |
|
||||
| 12-bis | Cross-module mirror BE | ~25K Implementer spawn | BE mega 4 region |
|
||||
| 12-ter | Within-module N-satellite | ~22K spawn | 1 mega features + N region |
|
||||
| 16-bis | Cross-app FE 4-place mirror | ~15K Implementer spawn | types + page + Routes + Layout staticMap |
|
||||
|
||||
Declarative KIND_CONFIG + 12-bis + 16-bis = **Trinity pattern** cho master catalog feature S29 + S35 proven 2×.
|
||||
|
||||
## Anti-pattern
|
||||
|
||||
❌ KHÔNG split N page per kind — clutter routes + duplicate boilerplate State/Mutation/Dialog
|
||||
❌ KHÔNG hardcode per-kind switch trong render JSX — dùng `KIND_CONFIG` Record + `renderField` switch tách logic
|
||||
❌ KHÔNG quên FieldDef.type extend khi NEW kind có shape khác — vd time picker / multiselect
|
||||
|
||||
## Verify checklist
|
||||
|
||||
- [ ] 1 page với `:kind` URL param + `useParams` extract
|
||||
- [ ] `KIND_CONFIG: Record<Kind, {...}>` declarative N kind config
|
||||
- [ ] 1 useQuery list + 1 useMutation save (Create + Update branch via isEdit) + 1 useMutation remove
|
||||
- [ ] Sub-tab nav 4 kind (NavLink active state per kind)
|
||||
- [ ] Dialog modal CRUD generic (KHÔNG per-kind dialog)
|
||||
- [ ] `renderField()` helper switch case per FieldDef.type
|
||||
- [ ] BE URL `/api/{prefix}/{kind}` × 4 verb (List + Create + Update + Delete) mirror controller
|
||||
- [ ] Mirror SHA256 IDENTICAL × 2 app (Pattern 16-bis)
|
||||
- [ ] Layout.tsx staticMap entry N leaf (Pattern 16-bis 4-place)
|
||||
Reference in New Issue
Block a user