feat: PRD-001 ProductType (flags + multimedia) #38

Merged
dmolinari merged 10 commits from feature/PRD-001 into main 2026-04-19 15:18:53 +00:00
Owner

Summary

  • V017 Migration: dbo.ProductType tabla temporal con SYSTEM_VERSIONING, shadow table _History. Permiso catalogo:tipos:gestionar creado.
  • Domain Entity: ProductType inmutable con flags (HasDuration, RequiresText, RequiresCategory, IsBundle) y límites multimedia (AllowImages, MaxImages, MaxImageSizeMB, MaxImageWidth, MaxImageHeight). AllowImages=false normaliza multimedia a NULL.
  • CRUD Completo: CreateProductTypeCommandHandler, UpdateProductTypeCommandHandler, DeactivateProductTypeCommandHandler + handlers query (GetById, List).
  • Validadores: Zod frontend + FluentValidation backend. MaxImages > 0 o NULL (sin límite).
  • Frontend CRUD: ProductTypesPage con dialogs para create/edit/deactivate. ProductTypeForm con lógica condicional: multimedia disabled si AllowImages=false.
  • Audit Completo: Temporal table + AuditLogger entries (producto_tipo.created/updated/deactivated). Obsidian audit doc actualizado (línea 337 + 376).
  • Permiso: catalogo:tipos:gestionar (26 total permisos post PRD-001).
  • Patrón: IProductQueryRepository.IsInUseAsync stub (NullProductQueryRepository) — seguir pattern CAT-002.
  • Controller Pattern: IValidator inyectado directo en handler (no pipeline) — seguir FiscalController pattern.

Test Plan

All Green: 1591 tests (+141 vs baseline 1450)

  • Application.Tests: 935/935 — domain entity, handlers, validators, repository stub
  • Api.Tests: 266/266 — controller, auth, exception filter (4 cases: 409 NombreDuplicado, 409 EnUso, 400 validation, 201/200)
  • Vitest (frontend): 390/390 (+27 vs pre-W3 363)
    • ProductTypeForm.test.tsx (8 tests)
    • ProductTypeFormDialog.test.tsx (6 tests)
    • DeactivateProductTypeDialog.test.tsx (4 tests)
    • ProductTypesPage.test.tsx (9 tests)

Warnings Tracked

  • W1 (Inherited #36): e2e 409 InUse gap — blocked by RSA singleton in TestWebApplicationFactory. TODO comment added. Coverage: DeactivateProductTypeCommandHandlerTests (unit) + ExceptionFilter unit tests.
  • W2 (Acceptable): Audit e2e no asserta dbo.AuditEvents DB table (consistent with CAT-001 pattern). Mitigation: handler unit tests + Obsidian audit doc updated.
  • W_OPENEDIT (WARNING): ProductTypesPage.openEdit() stubs multimedia fields as null. Risk: if a type has multimedia limits, editing overwrites with null silently. Practical risk LOW pre-PRD-008 (no real data). Fix in followup #37.

Commits Delivered

# Commit Message
1 de70152 feat(bd): V017 crea dbo.ProductType con SYSTEM_VERSIONING + permiso catalogo:tipos:gestionar
2 132d17c feat(domain): ProductType entity + domain exceptions
3 3c9e852 feat(application): IProductTypeRepository + IProductQueryRepository stub + queries
4 5c8f19b feat(application): CRUD handlers + validators + DI
5 936d1dc feat(infrastructure): ProductTypeRepository Dapper + DI wiring
6 1707898 feat(api): ProductTypesController + ExceptionFilter 4 casos
7 3db4ded feat(frontend): feature product-types completa
8 9cb1e84 feat(frontend): ProductTypeForm + Dialog + DeactivateDialog con TDD
9 230405e feat(frontend): wire dialogs en ProductTypesPage
10 d6ec618 docs(tests): TODO W1 PRD-002 + audit doc completo

Files Delta

73 files changed, 5116 insertions(+), 14 deletions(-)

Artifacts

Engram topic keys (SDD flow):

  • sdd/prd-001-product-type-flags-multimedia/explore
  • sdd/prd-001-product-type-flags-multimedia/proposal
  • sdd/prd-001-product-type-flags-multimedia/spec
  • sdd/prd-001-product-type-flags-multimedia/design
  • sdd/prd-001-product-type-flags-multimedia/design-part2
  • sdd/prd-001-product-type-flags-multimedia/tasks
  • sdd/prd-001-product-type-flags-multimedia/apply-progress
  • sdd/prd-001-product-type-flags-multimedia/verify-report (re-verified post W3)

Next

  • Follow-up #37: ProductTypesPage.openEdit() — fetch full ProductTypeDetail before populating form (multimedia null-stub fix)
  • PRD-002: Product CRUD (starts once PRD-001 merges, kicks off auto in SDD mode)
## Summary - **V017 Migration**: dbo.ProductType tabla temporal con SYSTEM_VERSIONING, shadow table _History. Permiso `catalogo:tipos:gestionar` creado. - **Domain Entity**: ProductType inmutable con flags (HasDuration, RequiresText, RequiresCategory, IsBundle) y límites multimedia (AllowImages, MaxImages, MaxImageSizeMB, MaxImageWidth, MaxImageHeight). AllowImages=false normaliza multimedia a NULL. - **CRUD Completo**: CreateProductTypeCommandHandler, UpdateProductTypeCommandHandler, DeactivateProductTypeCommandHandler + handlers query (GetById, List). - **Validadores**: Zod frontend + FluentValidation backend. MaxImages > 0 o NULL (sin límite). - **Frontend CRUD**: ProductTypesPage con dialogs para create/edit/deactivate. ProductTypeForm con lógica condicional: multimedia disabled si AllowImages=false. - **Audit Completo**: Temporal table + AuditLogger entries (producto_tipo.created/updated/deactivated). Obsidian audit doc actualizado (línea 337 + 376). - **Permiso**: `catalogo:tipos:gestionar` (26 total permisos post PRD-001). - **Patrón**: IProductQueryRepository.IsInUseAsync stub (NullProductQueryRepository) — seguir pattern CAT-002. - **Controller Pattern**: IValidator<TCommand> inyectado directo en handler (no pipeline) — seguir FiscalController pattern. ## Test Plan **All Green: 1591 tests (+141 vs baseline 1450)** - **Application.Tests**: 935/935 ✅ — domain entity, handlers, validators, repository stub - **Api.Tests**: 266/266 ✅ — controller, auth, exception filter (4 cases: 409 NombreDuplicado, 409 EnUso, 400 validation, 201/200) - **Vitest (frontend)**: 390/390 ✅ (+27 vs pre-W3 363) - ProductTypeForm.test.tsx (8 tests) - ProductTypeFormDialog.test.tsx (6 tests) - DeactivateProductTypeDialog.test.tsx (4 tests) - ProductTypesPage.test.tsx (9 tests) ## Warnings Tracked - **W1 (Inherited #36)**: e2e 409 InUse gap — blocked by RSA singleton in TestWebApplicationFactory. TODO comment added. Coverage: DeactivateProductTypeCommandHandlerTests (unit) + ExceptionFilter unit tests. - **W2 (Acceptable)**: Audit e2e no asserta dbo.AuditEvents DB table (consistent with CAT-001 pattern). Mitigation: handler unit tests + Obsidian audit doc updated. - **W_OPENEDIT (WARNING)**: ProductTypesPage.openEdit() stubs multimedia fields as null. Risk: if a type has multimedia limits, editing overwrites with null silently. Practical risk LOW pre-PRD-008 (no real data). Fix in followup #37. ## Commits Delivered | # | Commit | Message | |---|--------|---------| | 1 | de70152 | feat(bd): V017 crea dbo.ProductType con SYSTEM_VERSIONING + permiso catalogo:tipos:gestionar | | 2 | 132d17c | feat(domain): ProductType entity + domain exceptions | | 3 | 3c9e852 | feat(application): IProductTypeRepository + IProductQueryRepository stub + queries | | 4 | 5c8f19b | feat(application): CRUD handlers + validators + DI | | 5 | 936d1dc | feat(infrastructure): ProductTypeRepository Dapper + DI wiring | | 6 | 1707898 | feat(api): ProductTypesController + ExceptionFilter 4 casos | | 7 | 3db4ded | feat(frontend): feature product-types completa | | 8 | 9cb1e84 | feat(frontend): ProductTypeForm + Dialog + DeactivateDialog con TDD | | 9 | 230405e | feat(frontend): wire dialogs en ProductTypesPage | | 10 | d6ec618 | docs(tests): TODO W1 PRD-002 + audit doc completo | ## Files Delta 73 files changed, 5116 insertions(+), 14 deletions(-) ## Artifacts Engram topic keys (SDD flow): - sdd/prd-001-product-type-flags-multimedia/explore - sdd/prd-001-product-type-flags-multimedia/proposal - sdd/prd-001-product-type-flags-multimedia/spec - sdd/prd-001-product-type-flags-multimedia/design - sdd/prd-001-product-type-flags-multimedia/design-part2 - sdd/prd-001-product-type-flags-multimedia/tasks - sdd/prd-001-product-type-flags-multimedia/apply-progress - sdd/prd-001-product-type-flags-multimedia/verify-report (re-verified post W3) ## Next - **Follow-up #37**: ProductTypesPage.openEdit() — fetch full ProductTypeDetail before populating form (multimedia null-stub fix) - **PRD-002**: Product CRUD (starts once PRD-001 merges, kicks off auto in SDD mode)
dmolinari added 10 commits 2026-04-19 15:18:47 +00:00
Create/Update/Deactivate handlers con TransactionScope + audit; validators FluentValidation;
DI wiring NullProductQueryRepository + 5 handlers; SqlTestFixture V017 + permiso count 25→26.
CRUD + paginado con filtros sobre dbo.ProductType; history temporal verificada en tests.
11 integration tests nuevos, suite total 935 GREEN.
CRUD endpoints con validación FluentValidation inline; 4 nuevas excepciones mapeadas
en ExceptionFilter; conteos de permisos 25→26 actualizados; 12 e2e tests nuevos.
types, api, hooks, ProductTypesPage, router /admin/product-types,
sidebar Tipos de Producto; 11 vitest tests nuevos — suite total 363 GREEN.
Implementa los 3 componentes de UI faltantes con enfoque Red→Green:
- ProductTypeForm: zod schema con transforms para multimedia numérica,
  lógica condicional (multimedia deshabilitada cuando allowImages=false),
  normalización en submit.
- ProductTypeFormDialog: mode create/edit, inline error 409, aria-describedby (NFR8).
- DeactivateProductTypeDialog: AlertDialog confirmar soft-delete, inline error 409 EnUso.

18 tests nuevos (8 form + 6 dialog + 4 deactivate). Total: 381.
Conecta ProductTypeFormDialog (create/edit) y DeactivateProductTypeDialog
en ProductTypesPage: botón "Nuevo Tipo", acción Editar por fila, acción
Desactivar por fila, empty state CTA "Crear primer tipo".

9 tests nuevos de page integration. Total: 390.
Agrega comentario TODO antes del bloque DELETE explicando el gap e2e
para 409 IsInUse (bloqueado por RSA singleton, issue #36, PRD-002).
Auditoría.md ya tenía las entradas producto_tipo.* desde apply anterior.
dmolinari merged commit 0462970ea1 into main 2026-04-19 15:18:53 +00:00
dmolinari deleted branch feature/PRD-001 2026-04-19 15:18:53 +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#38