feat: PRD-002 Product CRUD #40

Merged
dmolinari merged 14 commits from feature/PRD-002 into main 2026-04-19 16:49:58 +00:00
Owner

Summary

PRD-002: Product CRUD — foundational product entity with complete CRUD operations, immutable domain, Application handlers with cross-aggregate validation, real Dapper persistence, API with 5 endpoints, and frontend feature with form reactive to ProductType flags.

Key deliverables:

  • Schema V018: dbo.Product with SYSTEM_VERSIONING (10y retention), temporal history, filtered unique index (MedioId, ProductTypeId, Nombre) WHERE IsActive=1, 4 performance-tuned indices
  • Entity layers: Product domain entity (immutable), IProductRepository interface, real ProductRepository + ProductQueryRepository Dapper implementations
  • Application: 5 command/query handlers (Create, Update, Deactivate, List, GetById), 2 validators (FluentValidation), cross-aggregate rule validation (flags coherence against ProductType), audit trail (producto.created, producto.updated, producto.deactivated)
  • API: ProductsController with 5 RESTful endpoints, ExceptionFilter handling 5 new error cases (404, 409 duplicate, 409 conflicts, 422 flags incoherent)
  • IProductQueryRepository activation: Real Dapper implementation replaces NullProductQueryRepository stub. Binding moved from Application to Infrastructure DI. Guard for DeactivateProductTypeCommand now active — attempting to deactivate a ProductType with active Products returns 409 Conflict (closes W1 from PRD-001).
  • Frontend: Full Products feature (ProductsPage, ProductForm, ProductFormDialog, DeactivateProductDialog) with hooks and API layer. Form renders conditionally based on ProductType flags (RequiresCategory, HasDuration). Inline error handling (409, 422) with field-specific messaging.
  • Permissions: New catalogo:productos:gestionar permiso assigned to admin role (permiso count: 26 → 27)

Test Plan

Test counts (final):

  • Application: 1015 tests (8b555e1..8c9a505: +22 new)
  • API: 284 tests (165abc8..a41a4ea: +17 new)
  • Frontend: 409 tests (08a4738..2b79b6f: +42 new)
  • Total: 1708 tests (baseline 1591 post-PRD-001, delta +117)

Critical test: ProductTypeDeactivationGuardTests (commit a41a4ea)

  • Verifies IProductQueryRepository real impl is active and guard works end-to-end
  • Scenario: Create ProductType → Create Product → DELETE ProductType → 409 ProductTypeEnUso

Warnings Resolved (from verify-report #473)

  • W1: ExceptionFilter mapped ProductTypeInactivo/RubroInactivo to 422 (spec: 409) — fixed in d262454 (now 409)
  • W2: ProductForm conditional rendering for RequiresCategory/HasDuration flags — implemented in 2b79b6f
  • W3, W4: ProductFormDialog and DeactivateProductDialog tests — added in 0f5455a
  • W5: ProductsPage pagination + filter tests — added in a7cfcdb
  • W6: V018 migration untracked in batch 1 — consolidated in d7fb310 (V018 + SqlTestFixture update)
  • S1: NullProductQueryRepository dead code — removed in b4f17d6
  • S2: SQL SELECT COUNT(1) vs SELECT TOP 1 1 — changed to EXISTS in b4f17d6

Follow-ups Created

  • [PRD-002 / Domain] Rubro deactivation guard — rechazar desactivar Rubro con Productos activos (scope deferred to post-archive issue creation, implementation in follow-up)

Artifacts

Engram artifacts:

  • sdd/prd-002-product-crud/explore (#466) — scope, business rules, schema proposal, FKs, validation strategy, edge cases
  • sdd/prd-002-product-crud/proposal (#467) — intent, scope, key decisions (D1–D10)
  • sdd/prd-002-product-crud/spec (#468) — 25 requirements (R1–R25), 65 scenarios
  • sdd/prd-002-product-crud/design (#469) — architectural overview, layer shapes, migration plan, DI activation
  • sdd/prd-002-product-crud/tasks (#471) — 10 batches, 68 tasks, strict TDD sequence
  • sdd/prd-002-product-crud/apply-progress (#472) — 9 batches complete, all tests green
  • sdd/prd-002-product-crud/verify-report (#473) — verification against 25 reqs, W1–W6 + S1–S2 closed
  • sdd/prd-002-product-crud/archive-report — this PR closes and archives the change

Next UDTs Unblocked

  • PRD-003 (ProductPrices históricos — tarifas por fecha)
  • PRD-004 (ProductBundle — relación M:N, validación ciclos)
  • PRD-005 (Settlement cross-company)
  • PRD-006 (Soft-delete universal)
  • PRD-008 (Seed 12 productos legacy — V019)
  • VTA-001 (Avisos — FK Product)
  • PRC-001 (WordCounter/Tasación — consulta Product.BasePrice)

Generated with SDD (Spec-Driven Development) workflow.

## Summary **PRD-002: Product CRUD** — foundational product entity with complete CRUD operations, immutable domain, Application handlers with cross-aggregate validation, real Dapper persistence, API with 5 endpoints, and frontend feature with form reactive to ProductType flags. Key deliverables: - **Schema V018**: `dbo.Product` with SYSTEM_VERSIONING (10y retention), temporal history, filtered unique index `(MedioId, ProductTypeId, Nombre) WHERE IsActive=1`, 4 performance-tuned indices - **Entity layers**: Product domain entity (immutable), IProductRepository interface, real ProductRepository + ProductQueryRepository Dapper implementations - **Application**: 5 command/query handlers (Create, Update, Deactivate, List, GetById), 2 validators (FluentValidation), cross-aggregate rule validation (flags coherence against ProductType), audit trail (`producto.created`, `producto.updated`, `producto.deactivated`) - **API**: ProductsController with 5 RESTful endpoints, ExceptionFilter handling 5 new error cases (404, 409 duplicate, 409 conflicts, 422 flags incoherent) - **IProductQueryRepository activation**: Real Dapper implementation replaces NullProductQueryRepository stub. Binding moved from Application to Infrastructure DI. Guard for `DeactivateProductTypeCommand` now active — attempting to deactivate a ProductType with active Products returns **409 Conflict** (closes **W1 from PRD-001**). - **Frontend**: Full Products feature (ProductsPage, ProductForm, ProductFormDialog, DeactivateProductDialog) with hooks and API layer. Form renders conditionally based on ProductType flags (RequiresCategory, HasDuration). Inline error handling (409, 422) with field-specific messaging. - **Permissions**: New `catalogo:productos:gestionar` permiso assigned to admin role (permiso count: 26 → 27) ### Test Plan **Test counts (final)**: - Application: 1015 tests (8b555e1..8c9a505: +22 new) - API: 284 tests (165abc8..a41a4ea: +17 new) - Frontend: 409 tests (08a4738..2b79b6f: +42 new) - **Total**: 1708 tests (baseline 1591 post-PRD-001, delta +117) **Critical test: ProductTypeDeactivationGuardTests** (commit a41a4ea) - Verifies IProductQueryRepository real impl is active and guard works end-to-end - Scenario: Create ProductType → Create Product → DELETE ProductType → **409 ProductTypeEnUso** ### Warnings Resolved (from verify-report #473) - **W1**: ExceptionFilter mapped ProductTypeInactivo/RubroInactivo to 422 (spec: 409) — **fixed in d262454** (now 409) - **W2**: ProductForm conditional rendering for RequiresCategory/HasDuration flags — **implemented in 2b79b6f** - **W3, W4**: ProductFormDialog and DeactivateProductDialog tests — **added in 0f5455a** - **W5**: ProductsPage pagination + filter tests — **added in a7cfcdb** - **W6**: V018 migration untracked in batch 1 — **consolidated in d7fb310** (V018 + SqlTestFixture update) - **S1**: NullProductQueryRepository dead code — **removed in b4f17d6** - **S2**: SQL SELECT COUNT(1) vs SELECT TOP 1 1 — **changed to EXISTS in b4f17d6** ### Follow-ups Created - **[PRD-002 / Domain] Rubro deactivation guard** — rechazar desactivar Rubro con Productos activos (scope deferred to post-archive issue creation, implementation in follow-up) ### Artifacts Engram artifacts: - `sdd/prd-002-product-crud/explore` (#466) — scope, business rules, schema proposal, FKs, validation strategy, edge cases - `sdd/prd-002-product-crud/proposal` (#467) — intent, scope, key decisions (D1–D10) - `sdd/prd-002-product-crud/spec` (#468) — 25 requirements (R1–R25), 65 scenarios - `sdd/prd-002-product-crud/design` (#469) — architectural overview, layer shapes, migration plan, DI activation - `sdd/prd-002-product-crud/tasks` (#471) — 10 batches, 68 tasks, strict TDD sequence - `sdd/prd-002-product-crud/apply-progress` (#472) — 9 batches complete, all tests green - `sdd/prd-002-product-crud/verify-report` (#473) — verification against 25 reqs, W1–W6 + S1–S2 closed - `sdd/prd-002-product-crud/archive-report` — this PR closes and archives the change ### Next UDTs Unblocked - **PRD-003** (ProductPrices históricos — tarifas por fecha) - **PRD-004** (ProductBundle — relación M:N, validación ciclos) - **PRD-005** (Settlement cross-company) - **PRD-006** (Soft-delete universal) - **PRD-008** (Seed 12 productos legacy — V019) - **VTA-001** (Avisos — FK Product) - **PRC-001** (WordCounter/Tasación — consulta Product.BasePrice) Generated with SDD (Spec-Driven Development) workflow.
dmolinari added 14 commits 2026-04-19 16:49:53 +00:00
Implements full frontend for PRD-002: 5 API fns, 5 hooks (useProducts,
useCreateProduct, useUpdateProduct, useDeactivateProduct), ProductForm,
ProductFormDialog, DeactivateProductDialog, ProductsPage with CanPerform
gating. Router entry at /admin/products and sidebar link added. 19 Vitest
tests GREEN (api, hooks, page).
dmolinari merged commit 1730b0623e into main 2026-04-19 16:49:58 +00:00
dmolinari deleted branch feature/PRD-002 2026-04-19 16:49:58 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dmolinari/SIG-CM2.0#40