id
title
type
status
priority
module
version
created_date
updated_date
estimated_sp
SAAS-019
Portfolio
Module
Specified
P2
portfolio
1.0.0
2026-01-24
2026-01-24
13
SAAS-019: Portfolio
Metadata
Codigo: SAAS-019
Modulo: Portfolio
Prioridad: P2
Estado: Especificado
Fase: 6 - Advanced Features
Story Points: 13
Descripcion
Catalogo de productos y servicios para plataformas SaaS. Permite definir ofertas, precios, categorias y variantes. Se integra con Sales para cotizaciones y con Billing para suscripciones basadas en productos.
Objetivos
Catalogo de productos/servicios configurable
Categorias y subcategorias jerarquicas
Precios con multiples monedas
Variantes de productos (tallas, colores, etc.)
Integracion con Sales y Billing
Alcance
Incluido
CRUD de productos/servicios
Categorias jerarquicas
Precios por moneda
Variantes basicas
Imagenes de productos
Productos activos/inactivos
Busqueda y filtros
Exportacion catalogo
Excluido
Inventario (erp-core)
Ordenes de compra (erp-core)
Proveedores (erp-core)
Configurador de productos complejo
Modelo de Datos
Schema: portfolio
-- Categorias
CREATE TABLE portfolio . categories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid (),
tenant_id UUID NOT NULL REFERENCES tenants . tenants ( id ),
name VARCHAR ( 100 ) NOT NULL ,
slug VARCHAR ( 100 ) NOT NULL ,
description TEXT ,
parent_id UUID REFERENCES portfolio . categories ( id ),
image_url VARCHAR ( 500 ),
position INTEGER DEFAULT 0 ,
is_active BOOLEAN DEFAULT true ,
created_at TIMESTAMPTZ DEFAULT NOW (),
updated_at TIMESTAMPTZ DEFAULT NOW (),
CONSTRAINT unique_category_slug UNIQUE ( tenant_id , slug )
);
-- Productos
CREATE TABLE portfolio . products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid (),
tenant_id UUID NOT NULL REFERENCES tenants . tenants ( id ),
-- Info basica
name VARCHAR ( 200 ) NOT NULL ,
slug VARCHAR ( 200 ) NOT NULL ,
description TEXT ,
short_description VARCHAR ( 500 ),
-- Clasificacion
type portfolio . product_type NOT NULL DEFAULT 'product' ,
category_id UUID REFERENCES portfolio . categories ( id ),
-- Codigo
sku VARCHAR ( 100 ),
barcode VARCHAR ( 100 ),
-- Precios
base_price DECIMAL ( 15 , 2 ) NOT NULL DEFAULT 0 ,
currency VARCHAR ( 3 ) DEFAULT 'USD' ,
tax_rate DECIMAL ( 5 , 2 ) DEFAULT 0 ,
-- Estado
status portfolio . product_status NOT NULL DEFAULT 'draft' ,
is_featured BOOLEAN DEFAULT false ,
-- Media
images JSONB DEFAULT '[]' ,
thumbnail_url VARCHAR ( 500 ),
-- Metadata
tags JSONB DEFAULT '[]' ,
attributes JSONB DEFAULT '{}' ,
meta_title VARCHAR ( 200 ),
meta_description VARCHAR ( 500 ),
-- Audit
created_at TIMESTAMPTZ DEFAULT NOW (),
updated_at TIMESTAMPTZ DEFAULT NOW (),
CONSTRAINT unique_product_slug UNIQUE ( tenant_id , slug ),
CONSTRAINT unique_product_sku UNIQUE ( tenant_id , sku )
);
-- Variantes
CREATE TABLE portfolio . variants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid (),
product_id UUID NOT NULL REFERENCES portfolio . products ( id ) ON DELETE CASCADE ,
tenant_id UUID NOT NULL REFERENCES tenants . tenants ( id ),
name VARCHAR ( 200 ) NOT NULL ,
sku VARCHAR ( 100 ),
-- Precio diferencial
price_adjustment DECIMAL ( 15 , 2 ) DEFAULT 0 ,
price_type portfolio . price_type DEFAULT 'adjustment' , -- 'adjustment' | 'fixed'
-- Atributos (color, talla, etc.)
attributes JSONB NOT NULL DEFAULT '{}' ,
-- Estado
is_active BOOLEAN DEFAULT true ,
created_at TIMESTAMPTZ DEFAULT NOW ()
);
-- Precios por moneda
CREATE TABLE portfolio . prices (
id UUID PRIMARY KEY DEFAULT gen_random_uuid (),
product_id UUID NOT NULL REFERENCES portfolio . products ( id ) ON DELETE CASCADE ,
variant_id UUID REFERENCES portfolio . variants ( id ) ON DELETE CASCADE ,
currency VARCHAR ( 3 ) NOT NULL ,
amount DECIMAL ( 15 , 2 ) NOT NULL ,
-- Precios especiales
compare_at_price DECIMAL ( 15 , 2 ), -- Precio tachado
cost_price DECIMAL ( 15 , 2 ), -- Costo
-- Vigencia
starts_at TIMESTAMPTZ ,
ends_at TIMESTAMPTZ ,
created_at TIMESTAMPTZ DEFAULT NOW (),
CONSTRAINT unique_price UNIQUE ( product_id , variant_id , currency )
);
-- Enums
CREATE TYPE portfolio . product_type AS ENUM (
'product' , 'service' , 'digital' , 'subscription'
);
CREATE TYPE portfolio . product_status AS ENUM (
'draft' , 'active' , 'inactive' , 'archived'
);
CREATE TYPE portfolio . price_type AS ENUM (
'adjustment' , 'fixed'
);
RLS Policies
ALTER TABLE portfolio . categories ENABLE ROW LEVEL SECURITY ;
ALTER TABLE portfolio . products ENABLE ROW LEVEL SECURITY ;
ALTER TABLE portfolio . variants ENABLE ROW LEVEL SECURITY ;
ALTER TABLE portfolio . prices ENABLE ROW LEVEL SECURITY ;
CREATE POLICY tenant_isolation ON portfolio . products
USING ( tenant_id = current_setting ( 'app.current_tenant_id' ):: UUID );
Endpoints API
Categories
Metodo
Endpoint
Descripcion
GET
/portfolio/categories
Listar categorias
POST
/portfolio/categories
Crear categoria
GET
/portfolio/categories/:id
Obtener categoria
PATCH
/portfolio/categories/:id
Actualizar categoria
DELETE
/portfolio/categories/:id
Eliminar categoria
GET
/portfolio/categories/tree
Arbol jerarquico
Products
Metodo
Endpoint
Descripcion
GET
/portfolio/products
Listar productos
POST
/portfolio/products
Crear producto
GET
/portfolio/products/:id
Obtener producto
PATCH
/portfolio/products/:id
Actualizar producto
DELETE
/portfolio/products/:id
Eliminar producto
POST
/portfolio/products/:id/duplicate
Duplicar producto
PATCH
/portfolio/products/:id/status
Cambiar estado
Variants
Metodo
Endpoint
Descripcion
GET
/portfolio/products/:id/variants
Listar variantes
POST
/portfolio/products/:id/variants
Crear variante
PATCH
/portfolio/variants/:id
Actualizar variante
DELETE
/portfolio/variants/:id
Eliminar variante
Prices
Metodo
Endpoint
Descripcion
GET
/portfolio/products/:id/prices
Listar precios
POST
/portfolio/products/:id/prices
Agregar precio
PATCH
/portfolio/prices/:id
Actualizar precio
DELETE
/portfolio/prices/:id
Eliminar precio
Frontend
Paginas
/portfolio - Dashboard catalogo
/portfolio/products - Lista de productos
/portfolio/products/new - Crear producto
/portfolio/products/:id - Editar producto
/portfolio/categories - Gestion categorias
Componentes
ProductsList - Tabla/grid de productos
ProductForm - Formulario producto completo
ProductCard - Tarjeta preview
VariantsManager - Gestion variantes
PricesManager - Gestion precios multi-moneda
CategoryTree - Arbol de categorias
CategoryForm - Formulario categoria
ImageUploader - Subida de imagenes
ProductSearch - Busqueda avanzada
Hooks
useProducts - CRUD productos
useCategories - CRUD categorias
useVariants - CRUD variantes
usePrices - CRUD precios
Dependencias
Modulos Requeridos
SAAS-001 Auth
SAAS-002 Tenants
SAAS-011 Storage (imagenes)
Modulos Opcionales
SAAS-018 Sales (productos en oportunidades)
SAAS-004 Billing (suscripciones)
Criterios de Aceptacion
CRUD productos con validaciones
Categorias jerarquicas funcionales
Variantes con atributos dinamicos
Precios multi-moneda
Subida de imagenes integrada
Busqueda y filtros avanzados
Tests unitarios (>70% coverage)
Estimacion
Componente
SP
DDL + Entities
2
Backend Services
3
Controllers + DTOs
2
Frontend Pages
3
Frontend Components
2
Tests
1
Total
13
Ultima actualizacion: 2026-01-24
Autor: Claude Opus 4.5