@quadcore-lib/products-server
v0.1.0
Published
CRUD de productos para e-commerce, sobre NestJS + TypeORM. Lectura pública (storefront), escritura `admin`. Precio numérico, stock, imágenes, SKU único y soft-delete.
Readme
@quadcore-lib/products-server
CRUD de productos para e-commerce, sobre NestJS + TypeORM. Lectura pública (storefront), escritura admin. Precio numérico, stock, imágenes, SKU único y soft-delete.
Instalación
npm install @quadcore-lib/products-server @quadcore-lib/auth-server @quadcore-lib/core-serverUso
import { QuadcoreProductsModule } from '@quadcore-lib/products-server';
@Module({ imports: [/* TypeOrm + Auth */ QuadcoreProductsModule.forRoot()] })
export class AppModule {}Endpoints
| Método | Ruta | Acceso | Descripción |
|---|---|---|---|
| GET | /products | público | Listado paginado. Query: page, pageSize, search, categoryId, isActive, includeDeleted. |
| GET | /products/:id | público | Un producto. |
| POST | /products | admin | Crear. |
| PATCH | /products/:id | admin | Actualizar. |
| DELETE | /products/:id | admin | Soft-delete. |
| POST | /products/:id/restore | admin | Restaurar. |
| PATCH | /products/:id/stock | admin | Ajustar stock. Body AdjustStockDto: exactamente uno de delta (suma/resta relativa) o set (valor absoluto); allowNegative? (default false) permite dejar el stock resultante en negativo. Si el resultado es negativo y allowNegative no está en true, responde 409 Conflict. Sin delta ni set → 400 Bad Request. |
Entidad ProductEntity (tabla products)
id, name, slug (único), description?, sku? (único), price (numeric→number), currency, stock, images? (string[]), categoryId? (referencia suave a categoría), isActive, timestamps + deletedAt (soft-delete).
Campos adicionales:
compareAtPrice?(numeric→number, null): precio "antes" para mostrar descuento, no afecta lógica de cobro.isFeatured(boolean, defaultfalse): flag para destacar el producto en storefront.attributes?(JSON libre, null): atributos por vertical sin columnas fijas, ej.{ region, year, rating }para vino. No tipado por el backend.categoryIds?(string[], null): M2M suave con categorías, además delcategoryIdlegacy (que se mantiene por compatibilidad).
categoryIdes una referencia por id sin FK dura:products-serverno depende decategories-server. El filtrado?categoryId=funciona igual; si querés una relación TypeORM real, extendé la entidad en tu proyecto.categoryIdssigue el mismo criterio (sin FK dura) para soportar múltiples categorías por producto.
Stock: dos mecanismos distintos
PATCH /products/:id/stock(admin, HTTP) →ProductsService.adjustStock(id, dto): corrección manual puntual desde el panel admin. Transaccional con lock pesimista de fila (SELECT ... FOR UPDATE), soportadeltaosetabsoluto, bloquea negativo salvoallowNegative.decrementStock(id, quantity)/restoreStock(id, quantity)(sin HTTP, programático):UPDATEs atómicos de una sola sentencia (WHERE stock >= quantityen el decremento, sinfindOne+save, sin lock explícito — el propioUPDATEes la sección crítica).decrementStockdevuelveboolean(falsesi no había stock suficiente). Es la primitiva que usa@quadcore-lib/orders-server(TypeOrmProductResolver) al crear/cancelar órdenes en el flujo de checkout. InyectáProductsServicesi necesitás ajustar stock desde tu propio código fuera de HTTP.
No mezclar los dos flujos sobre el mismo producto sin pensar la concurrencia entre ellos: adjustStock toma lock de fila dentro de una transacción; decrementStock/restoreStock son UPDATEs sueltos fuera de esa transacción, así que no se serializan entre sí más allá de lo que ya garantiza cada sentencia individual.
Migraciones
Este paquete trae sus migraciones de TypeORM en dist/src/migrations/*.js (se compilan junto al resto). Ver la guía completa (setup del DataSource, cómo combinarlas con las de otros paquetes, synchronize en dev vs. prod) en el README de @quadcore-lib/core-server, sección "Migraciones de DB".
