125 lines
5.5 KiB
JSON
125 lines
5.5 KiB
JSON
{
|
|
"task_id": "CODE-DEDUP-REPOSITORY-001",
|
|
"summary": "Extract repeated repository boilerplate (ID extraction, array sanitization, unwrap/normalization) into shared support utilities to eliminate ~290 lines of duplication across 6+ repository files.",
|
|
"assumptions": [
|
|
"MintyPHP DB layer returns nested arrays with table-name keys (e.g. $row['tenants']).",
|
|
"All repositories use the same unwrap, unwrapList, extractIds, and sanitizePositiveIds patterns.",
|
|
"A trait or static helper class is the right abstraction — no base repository class needed (repositories are thin)."
|
|
],
|
|
"scope": {
|
|
"in": [
|
|
"lib/Repository/Tenant/TenantRepository.php — unwrap, unwrapList, listIds extraction",
|
|
"lib/Repository/Access/RoleRepository.php — unwrap, unwrapList, listIds extraction",
|
|
"lib/Repository/Org/DepartmentRepository.php — unwrap, unwrapList, listIds extraction",
|
|
"lib/Repository/Access/PermissionRepository.php — ID extraction patterns",
|
|
"lib/Repository/Access/UserRoleRepository.php — ID sanitization",
|
|
"lib/Repository/Org/UserDepartmentRepository.php — ID sanitization",
|
|
"New file: lib/Repository/Support/RepositoryArrayHelper.php"
|
|
],
|
|
"out": [
|
|
"Repository method signatures (public API unchanged)",
|
|
"Repository SQL queries (not touched)",
|
|
"Service layer changes",
|
|
"Frontend changes"
|
|
]
|
|
},
|
|
"guardrails": {
|
|
"required_guard_ids": [
|
|
"GR-CORE-001",
|
|
"GR-LANG-001",
|
|
"GR-LANG-002",
|
|
"GR-TEST-001",
|
|
"GR-TEST-002"
|
|
],
|
|
"required_quality_gate_ids": [
|
|
"QG-001",
|
|
"QG-002",
|
|
"QG-003",
|
|
"QG-006"
|
|
]
|
|
},
|
|
"success_criteria": [
|
|
{
|
|
"id": "SC-001",
|
|
"criterion": "A single RepositoryArrayHelper class exists in lib/Repository/Support/ providing extractIds(), sanitizePositiveIds(), unwrap(), and unwrapList() as static methods."
|
|
},
|
|
{
|
|
"id": "SC-002",
|
|
"criterion": "All 6+ repository files use RepositoryArrayHelper instead of inline implementations. No duplicate unwrap/extractIds/sanitize logic remains."
|
|
},
|
|
{
|
|
"id": "SC-003",
|
|
"criterion": "Repository public method signatures and return values are identical before and after refactoring (pure internal refactor)."
|
|
},
|
|
{
|
|
"id": "SC-004",
|
|
"criterion": "PHPUnit, PHPStan, Architecture Contract, and CS checks pass green; zero new failures introduced by this task (pre-existing failures are out of scope)."
|
|
}
|
|
],
|
|
"implementation_steps": [
|
|
{
|
|
"id": "S1",
|
|
"title": "Create RepositoryArrayHelper",
|
|
"description": "Create lib/Repository/Support/RepositoryArrayHelper.php with static methods: extractIds(array $rows, string $tableKey): array, sanitizePositiveIds(array $ids): array, unwrap(?array $row, string $tableKey): ?array, unwrapList(mixed $rows, string $tableKey): array.",
|
|
"guard_refs": ["GR-CORE-001", "GR-LANG-001"]
|
|
},
|
|
{
|
|
"id": "S2",
|
|
"title": "Write unit tests for RepositoryArrayHelper",
|
|
"description": "Test all 4 methods with edge cases: empty arrays, null input, missing table keys, mixed types, duplicate IDs, negative IDs.",
|
|
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
|
|
},
|
|
{
|
|
"id": "S3",
|
|
"title": "Refactor TenantRepository",
|
|
"description": "Replace inline unwrap/unwrapList/extractIds with RepositoryArrayHelper calls. Verify no signature changes.",
|
|
"guard_refs": ["GR-CORE-001"]
|
|
},
|
|
{
|
|
"id": "S4",
|
|
"title": "Refactor RoleRepository and PermissionRepository",
|
|
"description": "Replace inline implementations with RepositoryArrayHelper calls.",
|
|
"guard_refs": ["GR-CORE-001"]
|
|
},
|
|
{
|
|
"id": "S5",
|
|
"title": "Refactor DepartmentRepository and UserDepartmentRepository",
|
|
"description": "Replace inline implementations with RepositoryArrayHelper calls.",
|
|
"guard_refs": ["GR-CORE-001"]
|
|
},
|
|
{
|
|
"id": "S6",
|
|
"title": "Refactor UserRoleRepository",
|
|
"description": "Replace inline ID sanitization with RepositoryArrayHelper::sanitizePositiveIds().",
|
|
"guard_refs": ["GR-CORE-001"]
|
|
},
|
|
{
|
|
"id": "S7",
|
|
"title": "Run all quality gates",
|
|
"description": "QG-001 PHPUnit, QG-002 PHPStan, QG-003 Architecture, QG-006 CS check.",
|
|
"guard_refs": ["GR-LANG-002"]
|
|
}
|
|
],
|
|
"tests": [
|
|
"tests/Repository/Support/RepositoryArrayHelperTest.php — new, covers all 4 static methods with edge cases",
|
|
"tests/Architecture/CoreStarterkitContractTest.php — must stay green",
|
|
"Existing service tests that call repository methods indirectly — must stay green"
|
|
],
|
|
"acceptance_checks": [
|
|
"SC-001: File lib/Repository/Support/RepositoryArrayHelper.php exists with 4 public static methods",
|
|
"SC-002: rg 'foreach.*\\$row.*\\[.*id.*\\]' lib/Repository/ returns only RepositoryArrayHelper, not inline implementations",
|
|
"SC-003: git diff shows no changes to public method signatures in repository files",
|
|
"SC-004: QG-001 + QG-002 + QG-003 + QG-006: zero new failures introduced by this task (pre-existing failures are out of scope)"
|
|
],
|
|
"risks": [
|
|
{
|
|
"risk": "Subtle behavioral difference in edge cases between inline and helper implementations",
|
|
"mitigation": "Write comprehensive helper tests first (TDD). Run full QG-001 after each repository file change."
|
|
},
|
|
{
|
|
"risk": "Table key naming inconsistency across repositories",
|
|
"mitigation": "Audit all unwrap calls first to confirm table key naming. The helper accepts the key as parameter, so naming differences are handled."
|
|
}
|
|
]
|
|
}
|