You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extraer la gestión de almacén de ResponseGrid a un producto open-source independiente — un WMS genérico (pensado para almacenes de Protección Civil, pero válido para cualquier sector) — y hacer que ResponseGrid lo reutilice como librería interna, en lugar de mantener la misma lógica dos veces.
Son dos software totalmente separados (distinta BD, servidor, auth y organizaciones; sin datos compartidos). El único punto de unión es código reutilizado vía paquetes.
🧭 Estado actual y próximos pasos (handoff para agentes)
Hecho:Fase 1 ✅ · Fase 2 ✅ (núcleo de dominio del WMS nuevo, dominio puro) · Fase 0 ✅ (taxonomía data-driven #380 + migración de consumidores a slug #382/#395) · Fase 0.5 persistencia ✅ (warehouse-postgres, schema wms. + repos + consumidor de validación, #383/#392).
Fase 3 (app de referencia standalone) se desarrolla directamente en OTRO repositorio, fuera de este monorepo — no se implementa aquí ni se trackea en esta épica.
Cada incremento = rama nueva desde main (git fetch origin main && git checkout -B origin/main), PR con Closes #NN, squash + auto-merge en verde. Reclamar la issue (in-progress) antes de empezar (protocolo en AGENTS.md).
@globalemergency/warehouse-core es dominio puro: ESLint no-restricted-imports prohíbe @nestjs/*, drizzle-orm, pg y apps/*. Tenencia opaca vía ScopeId.
Tests del paquete: se co-ubican como src/**/*.test.ts, compilan con tsc -p tsconfig.test.json a dist-test/ (git-ignored) y corren con node --test — porque el type-stripping puro no soporta enum/parameter-properties. Los gatea el step CI «Run tests — warehouse-core» (pnpm --filter '@globalemergency/warehouse-core' test). .prettierrc propio del paquete (comillas simples). Los int-tests de warehouse-postgres necesitan Postgres → job Test con servicio.
Núcleo de dominio del WMS completo (dominio puro): ubicaciones + existencia + kardex + FEFO + recuentos (#388) + reservas (#390) + caducidad (#393), con persistencia Postgres (#383). Queda min/max (reorder)(en pausa: se está pensando algo más grande) y el recuento a nivel de bin como refinamiento futuro; lo esencial está.
Fase 3 — App de referencia standalone — fuera de este repo
WMS OSS desplegable con auth propia. Se desarrolla directamente en otro repositorio (fuera de este monorepo); no se trackea aquí.
La lógica de almacén (existente) vive una sola vez en el paquete. (Fase 1 completa: kernel/catalog/persistencia-línea/containers/logistics ✓)
El paquete es agnóstico de emergencia/Prote/identity y no importa de apps/api. (todo el dominio extraído opera contra ScopeId; HTTP/auth/ports de estado en el host)
Objetivo
Extraer la gestión de almacén de ResponseGrid a un producto open-source independiente — un WMS genérico (pensado para almacenes de Protección Civil, pero válido para cualquier sector) — y hacer que ResponseGrid lo reutilice como librería interna, en lugar de mantener la misma lógica dos veces.
Son dos software totalmente separados (distinta BD, servidor, auth y organizaciones; sin datos compartidos). El único punto de unión es código reutilizado vía paquetes.
🧭 Estado actual y próximos pasos (handoff para agentes)
Hecho: Fase 1 ✅ · Fase 2 ✅ (núcleo de dominio del WMS nuevo, dominio puro) · Fase 0 ✅ (taxonomía data-driven #380 + migración de consumidores a slug #382/#395) · Fase 0.5 persistencia ✅ (
warehouse-postgres, schemawms.+ repos + consumidor de validación, #383/#392).Fase 3 (app de referencia standalone) se desarrolla directamente en OTRO repositorio, fuera de este monorepo — no se implementa aquí ni se trackea en esta épica.
Próximos pasos (issues abiertas, claimables):
packages/warehouse-*a repo OSS público + publish. Depende de WMS OSS: decisiones transversales de producto (nombre, licencia, alcance v1, integración desacoplada) #385.Orden sugerido: #385 → #386.
Convenciones para continuar (importante):
main(git fetch origin main && git checkout -B origin/main), PR conCloses #NN, squash + auto-merge en verde. Reclamar la issue (in-progress) antes de empezar (protocolo en AGENTS.md).@globalemergency/warehouse-corees dominio puro: ESLintno-restricted-importsprohíbe@nestjs/*,drizzle-orm,pgyapps/*. Tenencia opaca víaScopeId.src/**/*.test.ts, compilan contsc -p tsconfig.test.jsonadist-test/(git-ignored) y corren connode --test— porque el type-stripping puro no soportaenum/parameter-properties. Los gatea el step CI «Run tests — warehouse-core» (pnpm --filter '@globalemergency/warehouse-core' test)..prettierrcpropio del paquete (comillas simples). Los int-tests dewarehouse-postgresnecesitan Postgres → jobTestcon servicio.ScopeId/emergency_iden feat(warehouse-core): extrae containers (Container) al paquete usando ScopeId #366/Extraer el módulo logistics (TransportCapacity + Shipment) a @globalemergency/warehouse-core #367.Decisiones ya cerradas
@globalemergency/warehouse-core(puro) +@globalemergency/warehouse-postgres(Drizzle) +@globalemergency/warehouse-nest(glue DI, opcional). Sin HTTP ni auth (los pone cada host).warehouse-corecon módulos internos (kernel/catalog/inventory/containers/logistics) vía subpath exports.actorIdopaco.ScopeIdopaco (WMS → Organización/Prote; ResponseGrid → Emergencia/Centro).@globalemergency/*. Topología final: polyrepo; paso 1 = in-monorepo (workspace:*).Estado de partida (extraer vs construir)
Lo existente cubre ~40%. Se construye (~60%):
Warehouse/Zone/Bin,StockItem,StockMovement(kardex), salidas/consumo, FEFO/caducidad activa, UoM + decimales, min/max, recuentos, concurrencia optimista, idempotencia.Issues hijas
✅ Entregado
kernel(SupplyLine,Category,CategoryDefinition). Mergeado + desplegado.catalog(Supply, resolvers, ports de catálogo). Mergeado + desplegado.@globalemergency/warehouse-postgres(supplyLineColumns+ mappers;drizzle-ormpeerDependency). Mergeado.ScopeId(id opaco de tenencia) en el kernel. Mergeado.containers(Containerpalet/caja/lote + port) genericizado aScopeId; frontera 1:1 en el host (API y columna DB sin cambios). Mergeado.logistics(TransportCapacity,Shipment/transfer, matching,ShipmentDelivered+ ports) sobreScopeId; frontera 1:1 en el host. Mergeado. → Fase 1 completa.inventory(Warehouse+Zone) sobreScopeId; arranca la Fase 2 (WMS core nuevo). Tests propios del paquete (node --testsobre JS compilado) gateados en CI. Mergeado.Bin(ubicación física; root propio que referencia warehouse+zone por id) eninventory. → backbone de ubicaciones completo. Mergeado.StockItem(existencia: producto × lote × bin × estado) + VOsQuantity(decimal + UoM) yLot(con caducidad para FEFO);versionpara concurrencia optimista. → el corazón del WMS. Mergeado.StockMovement(kardex: asiento inmutable de doble pata) +applyStockMovement(mover = decrementar uno/incrementar otro); idempotencia de entradas (idempotencyKey), port append-only. → libro mayor + salidas/consumo/traslados. Mergeado.allocateFefo(servicio de asignación por caducidad, first-expired-first-out; plan de reparto puro + shortfall). → Fase 2 completa: núcleo de dominio del WMS terminado. Mergeado.CategorySlug(VO),CategoryRegistry(jerarquía/prefijos data-driven),CORE_CATEGORY_SLUGS. Sin tocar consumidores. Mergeado. (Follow-up completado en Fase 0 (follow-up de #380): migrar SupplyLine + consumidores de Category enum a CategorySlug/registry #382.)SupplyLine+ consumidores deCategorya slug validado —SupplyLine.categorypasa astringvalidado conCategorySlug; el validador HTTPCategorySlugPropertysustituye a@IsEnum(Category);gen:apiabre el contrato público astring;Category/CORE_CATEGORY_SLUGSquedan como semilla core. Web sin cambios (ya data-driven). Comportamiento 1:1. Mergeado (feat(supplies): abre Category de enum cerrado a slug validado (data-driven) — Fase 0 #395). → Fase 0 completa.warehouse-postgres(schemawms., repos Drizzle de los 4 ports, migraciones namespaced, consumidor de validación standalone). Mergeado (feat(warehouse-postgres): persistencia del inventario WMS (schema wms.) — Fase 0.5 #392). → el WMS ya tiene dominio + almacenamiento.reconcileCount(recuentos — concilia conteo físico ↔ sistema y produce elStockMovementde ajuste; plan/ejecución). Dominio puro. Mergeado.reserveStock/releaseReservation(transferavailable ↔ reserveddel mismo grano; el stock no sale del bin). Compañero de FEFO para el ciclo asignación→picking. Dominio puro. Mergeado.findExpired/expiringWithin/expiryStatusOf/nextToExpire(visibilidad proactiva de la caducidad; compañero de FEFO). Dominio puro. Mergeado.🔜 Abierto (claimable)
Fase 0 — Genericización in-situ
ScopeIdsobreEmergencyIdcomo clave de partición opaca — feat(warehouse-core): añade ScopeId, el id opaco de tenencia del kernel #365 (id genérico en el kernel; mapeoEmergencyId→ScopeIden la frontera del host).Categoryde enum a slug data-driven (taxonomía configurable) — base en Fase 0: base data-driven de la taxonomía — CategorySlug + CategoryRegistry #380 (CategorySlug/CategoryRegistry/CORE_CATEGORY_SLUGS) + migración de consumidores completada (SupplyLine.category→ slug validado) en Fase 0 (follow-up de #380): migrar SupplyLine + consumidores de Category enum a CategorySlug/registry #382/feat(supplies): abre Category de enum cerrado a slug validado (data-driven) — Fase 0 #395.Fase 0.5 — Paquete precursor in-monorepo ✅
warehouse-core+warehouse-postgres(workspace:*, build dual, subpaths) — feat(warehouse-core): extrae el kernel de material a @globalemergency/warehouse-core #356/feat(warehouse-postgres): estrena el paquete de persistencia con supply-line-columns #364.apps/api → @globalemergency/warehouse-*— feat(warehouse-core): extrae el kernel de material a @globalemergency/warehouse-core #356/feat(warehouse-postgres): estrena el paquete de persistencia con supply-line-columns #364.wms.— Fase 0.5: persistencia del inventario en warehouse-postgres (schema wms. + repos + migraciones + consumidor de validación) #383/feat(warehouse-postgres): persistencia del inventario WMS (schema wms.) — Fase 0.5 #392.Fase 1 — Mover lo puro extraíble al paquete ✅
kernel: value objects de material — feat(warehouse-core): extrae el kernel de material a @globalemergency/warehouse-core #356.catalog:Supply, resolvers, ports — feat(warehouse-core): extrae el módulo catalog (Supply + resolvers) al paquete #360.supplyLineColumns) →warehouse-postgres— feat(warehouse-postgres): estrena el paquete de persistencia con supply-line-columns #364.containers:Container(palet/caja/lote) sobreScopeId— feat(warehouse-core): extrae containers (Container) al paquete usando ScopeId #366.logistics:TransportCapacity,Shipment/transfer sobreScopeId— Extraer el módulo logistics (TransportCapacity + Shipment) a @globalemergency/warehouse-core #367.Fase 2 — Construir el núcleo WMS nuevo (en el paquete) ✅
Warehouse/Zone/Bin✓ (WMS core (Fase 2): módulo inventory — Warehouse + Zone #370 Warehouse+Zone, WMS core (Fase 2): agregado Bin (ubicación física) #372 Bin)StockItem(producto × lote × ubicación × estado) ✓ (WMS core (Fase 2): StockItem — existencia (producto × lote × bin × estado) #374; +Quantity/Lot)StockMovement— kardex ✓ (WMS core (Fase 2): StockMovement — kardex (asiento unificado de doble pata) #376; asiento unificado de doble pata +applyStockMovement)Quantity)allocateFefo+ WMS core (Fase 2): gestión de caducidad — findExpired / expiringWithin / expiryStatusOf #393 gestión de caducidad)StockItem.versionWMS core (Fase 2): StockItem — existencia (producto × lote × bin × estado) #374 +idempotencyKeyWMS core (Fase 2): StockMovement — kardex (asiento unificado de doble pata) #376)reconcileCount)reserveStock/releaseReservation)Núcleo de dominio del WMS completo (dominio puro): ubicaciones + existencia + kardex + FEFO + recuentos (#388) + reservas (#390) + caducidad (#393), con persistencia Postgres (#383). Queda min/max (reorder) (en pausa: se está pensando algo más grande) y el recuento a nivel de bin como refinamiento futuro; lo esencial está.
Fase 3 — App de referencia standalone — fuera de este repo
Fase 4 — Extracción a repo OSS — #386
packages/warehouse-*al repo público;workspace:*→ versión publicada; CI/publish (depende de WMS OSS: decisiones transversales de producto (nombre, licencia, alcance v1, integración desacoplada) #385)Transversales (decisiones abiertas) — #385
Definición de Done
Criterios base: cada sub-issue con gate CI verde y PR con
Closes #NN.Criterios específicos:
warehouse-core+-postgresexisten como paquetes, consumidos víaworkspace:*, con dependencia unidireccional ESLint — feat(warehouse-core): extrae el kernel de material a @globalemergency/warehouse-core #356/feat(warehouse-core): extrae el módulo catalog (Supply + resolvers) al paquete #360/feat(warehouse-postgres): estrena el paquete de persistencia con supply-line-columns #364/feat(warehouse-core): extrae containers (Container) al paquete usando ScopeId #366/Extraer el módulo logistics (TransportCapacity + Shipment) a @globalemergency/warehouse-core #367.apps/api. (todo el dominio extraído opera contraScopeId; HTTP/auth/ports de estado en el host)wms.(Fase 0.5: persistencia del inventario en warehouse-postgres (schema wms. + repos + migraciones + consumidor de validación) #383/feat(warehouse-postgres): persistencia del inventario WMS (schema wms.) — Fase 0.5 #392)packages/warehouse-*a repo OSS con licencia. (Fase 4: extracción de packages/warehouse-* a repo OSS público (publish + consumo por versión) #386; la app de referencia standalone se aborda en otro repo)Esta épica es el punto de entrada; el detalle técnico de cada pieza va en su sub-issue.