Claude-skill-registry Business Forge Engineer
Especialista en Business Forge: gestión de assets post-magia, Fusion Engine y generación de visuales.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/business-forge-engineer-adriangmrraa-multiagents-platform" ~/.claude/skills/majiayu000-claude-skill-registry-business-forge-engineer && rm -rf "$T"
manifest:
skills/data/business-forge-engineer-adriangmrraa-multiagents-platform/SKILL.mdsource content
Business Forge Engineer - Platform AI Solutions
1. Concepto: The Business Forge
Filosofía
El Business Forge es el estudio post-magia donde los usuarios refinan y utilizan los assets generados por el proceso de "Hacer Magia".
Capacidades
- Canvas: Visualizar assets generados (branding, scripts, ROI, visuals)
- Smart Catalog: Browser de productos brutos de Tienda Nube
- Fusion Engine: Generación de imágenes publicitarias on-demand
- Reality vs Dream Mode: Overlay de producto real sobre fondo IA
Arquitectura
Frontend (BusinessForge.tsx) ↓ Tab System (Canvas | Smart Catalog) ↓ Canvas → GET /admin/assets (filtrado por type) ↓ Smart Catalog → GET /admin/products ↓ Fusion Engine → POST /admin/generate-image ↓ Google Imagen 3 → Visual Asset
2. Frontend: Tab System
BusinessForge Component
const BusinessForge: React.FC = () => { const [activeTab, setActiveTab] = useState<'canvas' | 'catalog'>('canvas'); const [assets, setAssets] = useState<Asset[]>([]); const [products, setProducts] = useState<Product[]>([]); useEffect(() => { if (activeTab === 'canvas') { loadAssets(); } else { loadProducts(); } }, [activeTab]); const loadAssets = async () => { const data = await useApi<Asset[]>({ method: 'GET', url: '/admin/assets' }); setAssets(data); }; const loadProducts = async () => { const data = await useApi<Product[]>({ method: 'GET', url: '/admin/products' }); setProducts(data); }; return ( <div className="forge-container"> {/* Tab Navigation */} <div className="tabs"> <button className={activeTab === 'canvas' ? 'active' : ''} onClick={() => setActiveTab('canvas')} > 🎨 Canvas </button> <button className={activeTab === 'catalog' ? 'active' : ''} onClick={() => setActiveTab('catalog')} > 📦 Smart Catalog </button> </div> {/* Content */} <div className="forge-content"> {activeTab === 'canvas' ? ( <CanvasView assets={assets} /> ) : ( <CatalogView products={products} /> )} </div> </div> ); };
3. Canvas View (Assets Generados)
Filtrado por Tipo
const CanvasView: React.FC<{ assets: Asset[] }> = ({ assets }) => { const [filter, setFilter] = useState<AssetType>('all'); const filteredAssets = filter === 'all' ? assets : assets.filter(a => a.type === filter); return ( <div className="canvas-view"> {/* Filtros */} <div className="filters"> <button onClick={() => setFilter('all')}>All</button> <button onClick={() => setFilter('branding')}>🧬 Branding</button> <button onClick={() => setFilter('scripts')}>📝 Scripts</button> <button onClick={() => setFilter('roi')}>💰 ROI</button> <button onClick={() => setFilter('visuals')}>🎨 Visuals</button> </div> {/* Asset Grid */} <div className="asset-grid"> {filteredAssets.map(asset => ( <AssetCard key={asset.id} asset={asset} /> ))} </div> </div> ); };
Asset Card (Polymorphic Renderer)
const AssetCard: React.FC<{ asset: Asset }> = ({ asset }) => { const renderContent = () => { switch (asset.type) { case 'branding': return <BrandingAsset content={asset.content} />; case 'scripts': return <ScriptsAsset content={asset.content} />; case 'roi': return <ROIAsset content={asset.content} />; case 'visuals': return <VisualsAsset content={asset.content} />; default: return <JSONView data={asset.content} />; } }; return ( <div className="asset-card"> <div className="asset-header"> <h3>{asset.type}</h3> <span className="timestamp"> {new Date(asset.created_at).toLocaleDateString()} </span> </div> <div className="asset-body"> {renderContent()} </div> </div> ); };
Branding Asset
const BrandingAsset: React.FC<{ content: BrandingContent }> = ({ content }) => { return ( <div className="branding-asset"> <div className="section"> <h4>MISIÓN</h4> <p>{content.mission}</p> </div> <div className="section"> <h4>VISIÓN</h4> <p>{content.vision}</p> </div> <div className="section"> <h4>VOZ DE MARCA</h4> <p>{content.voice}</p> </div> <div className="section"> <h4>VALORES</h4> <ul> {content.values.map((v, i) => ( <li key={i}>{v}</li> ))} </ul> </div> <div className="color-palette"> <h4>PALETA DE COLORES</h4> <div className="colors"> {content.color_palette.map((color, i) => ( <div key={i} className="color-swatch" style={{ backgroundColor: color }} title={color} /> ))} </div> </div> </div> ); };
Visuals Asset (Social Posts)
const VisualsAsset: React.FC<{ content: VisualsContent }> = ({ content }) => { return ( <div className="visuals-grid"> {content.social_posts.map((post, i) => ( <FusionItem key={i} post={post} /> ))} </div> ); };
4. Fusion Engine (Generación On-Demand)
FusionItem Component
interface FusionPost { product_id: string; product_name: string; image_url: string; // URL de la imagen generada por IA base_image?: string; // URL original del producto (para overlay) prompt_used: string; } const FusionItem: React.FC<{ post: FusionPost }> = ({ post }) => { const [viewMode, setViewMode] = useState<'dream' | 'reality'>('dream'); return ( <div className="fusion-item"> <div className="image-container"> {viewMode === 'dream' ? ( // Imagen pura de IA (puede alucinar detalles) <img src={post.image_url} alt={post.product_name} /> ) : ( // Overlay: fondo IA + producto real <div className="reality-overlay"> <img src={post.image_url} className="background" alt="AI Background" /> <img src={post.base_image} className="product-overlay" alt={post.product_name} style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', maxWidth: '60%', maxHeight: '60%', mixBlendMode: 'multiply' }} /> </div> )} </div> <div className="fusion-controls"> <button onClick={() => setViewMode(viewMode === 'dream' ? 'reality' : 'dream')} > {viewMode === 'dream' ? '🌟 Dream' : '✨ Reality'} </button> </div> <div className="product-info"> <h4>{post.product_name}</h4> <p className="prompt-hint">{post.prompt_used}</p> </div> </div> ); };
Generar Nueva Imagen (Fusion Button)
const ProductCard: React.FC<{ product: Product }> = ({ product }) => { const [generating, setGenerating] = useState(false); const handleIgniteFusion = async () => { setGenerating(true); try { const prompt = ` Professional advertising shot of ${product.name}. Luxury aesthetic, soft lighting, minimal background. High-end product photography, studio quality. `; const response = await useApi({ method: 'POST', url: '/admin/generate-image', data: { prompt: prompt, image_url: product.image_url } }); if (response.status === 'success') { // Guardar en assets await saveGeneratedVisual(response.url, product); alert('Visual generated!'); } } catch (error) { alert('Generation failed'); } finally { setGenerating(false); } }; return ( <div className="product-card"> <img src={product.image_url} alt={product.name} /> <h3>{product.name}</h3> <p>${product.price}</p> <button onClick={handleIgniteFusion} disabled={generating} className="fusion-btn" > {generating ? 'Generating...' : '🔥 Ignite Fusion'} </button> </div> ); };
5. Backend: Fusion Engine
generate-image Endpoint
# orchestrator_service/app/api/v1/endpoints/forge.py @router.post("/admin/generate-image") async def generate_image( payload: ImageGenerationRequest, current_user = Depends(verify_admin_token) ): """ Genera imagen publicitaria usando Google Imagen 3 """ tenant_id = await resolve_tenant(current_user.id) # Validar credencial de Google google_key = await get_tenant_credential( tenant_id=tenant_id, category="google", name="API_KEY" ) if not google_key: raise HTTPException( status_code=400, detail="Google API key not configured" ) # Opcionalmente, descargar imagen base para context base_image_data = None if payload.image_url: img_response = await httpx.get(payload.image_url) base_image_data = img_response.content # Llamar a Google Imagen 3 try: response = await httpx.post( "https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0:generate", headers={ "Authorization": f"Bearer {google_key}", "Content-Type": "application/json" }, json={ "prompt": payload.prompt, "num_images": 1, "aspect_ratio": "1:1", "safety_filter": "medium" }, timeout=60.0 ) if response.status_code != 200: raise HTTPException( status_code=response.status_code, detail=f"Google Imagen API error: {response.text}" ) data = response.json() generated_url = data['images'][0]['url'] return { "status": "success", "url": generated_url } except Exception as e: logger.error(f"Image generation failed: {str(e)}") raise HTTPException( status_code=500, detail=f"Generation failed: {str(e)}" )
6. Smart Catalog (Product Browser)
Catalog View
const CatalogView: React.FC<{ products: Product[] }> = ({ products }) => { const [categoryFilter, setCategoryFilter] = useState<string | null>(null); // Extraer categorías únicas const categories = Array.from( new Set(products.map(p => p.category).filter(Boolean)) ); const filteredProducts = categoryFilter ? products.filter(p => p.category === categoryFilter) : products; return ( <div className="catalog-view"> {/* Filtro de categorías */} <div className="category-filters"> <button className={!categoryFilter ? 'active' : ''} onClick={() => setCategoryFilter(null)} > All Products </button> {categories.map(cat => ( <button key={cat} className={categoryFilter === cat ? 'active' : ''} onClick={() => setCategoryFilter(cat)} > {cat} </button> ))} </div> {/* Grid de productos */} <div className="product-grid"> {filteredProducts.map(product => ( <ProductCard key={product.id} product={product} /> ))} </div> </div> ); };
7. Persistencia de Assets
Backend: Assets Endpoint
@router.get("/admin/assets") async def list_assets( current_user = Depends(verify_admin_token), type_filter: Optional[str] = None, session: AsyncSession = Depends(get_session) ): """ Lista assets generados """ tenant_id = await resolve_tenant(current_user.id) # Query base stmt = select(BusinessAsset).where( BusinessAsset.tenant_id == tenant_id ) # Filtro opcional por tipo if type_filter: stmt = stmt.where(BusinessAsset.type == type_filter) # Ordenar por más reciente stmt = stmt.order_by(BusinessAsset.created_at.desc()) result = await session.execute(stmt) assets = result.scalars().all() return [ { "id": a.id, "type": a.type, "content": a.content, "created_at": a.created_at.isoformat() } for a in assets ]
Guardar Visual Generado
@router.post("/admin/assets", status_code=201) async def save_asset( payload: AssetCreate, current_user = Depends(verify_admin_token), session: AsyncSession = Depends(get_session) ): tenant_id = await resolve_tenant(current_user.id) asset = BusinessAsset( tenant_id=tenant_id, type=payload.type, content=payload.content ) session.add(asset) await session.commit() await session.refresh(asset) return { "id": asset.id, "status": "saved" }
8. Reality vs Dream Mode (CSS Magic)
CSS Implementation
/* Reality Mode: Overlay */ .reality-overlay { position: relative; width: 100%; aspect-ratio: 1 / 1; overflow: hidden; } .reality-overlay .background { width: 100%; height: 100%; object-fit: cover; filter: brightness(0.9); /* Oscurecer ligeramente fondo */ } .reality-overlay .product-overlay { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 60%; max-height: 60%; object-fit: contain; mix-blend-mode: multiply; /* Mezclar con fondo */ filter: drop-shadow(0 10px 30px rgba(0,0,0,0.3)); /* Sombra realista */ }
9. Export & Download
Exportar Asset
const exportAsset = async (asset: Asset) => { if (asset.type === 'visuals') { // Descargar imagen const imageUrl = asset.content.social_posts[0].image_url; const link = document.createElement('a'); link.href = imageUrl; link.download = `visual_${asset.id}.jpg`; link.click(); } else { // Descargar JSON const blob = new Blob( [JSON.stringify(asset.content, null, 2)], { type: 'application/json' } ); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `${asset.type}_${asset.id}.json`; link.click(); } };
10. Troubleshooting
"No se ve la imagen generada"
Causa: URL de Google Imagen tiene CORS restrictivo Solución: Proxy la imagen a través del backend o guardarla en storage
"Fusion falla silenciosamente"
Causa: Google API quota excedida Solución: Verificar quota en Google Cloud Console
"Overlay no se ve bien"
Causa: Imagen original tiene fondo blanco (no transparente) Solución: Usar productos con PNGs transparentes o aplicar remove-bg
"Assets no cargan"
Causa: tenant_id incorrecto Solución: Verificar resolve_tenant en backend
11. Checklist de Implementación
Frontend
- Tab system (Canvas / Catalog)
- Asset grid con filtros
- Polymorphic asset renderer
- Fusion button funcional
- Reality vs Dream toggle
- Category filters en Catalog
- Export/Download assets
Backend
- GET /admin/assets (con filtros)
- POST /admin/generate-image
- GET /admin/products (desde TiendaNube)
- POST /admin/assets (guardar generados)
- Google Imagen 3 integration
- Validación de credenciales
Visuals
- Branding asset renderer
- Scripts asset renderer
- ROI asset renderer
- Social posts grid
- CSS overlay effect
- Product cards con imagen
Tip: Para mejores resultados en Fusion, usar prompts específicos con estilo deseado (ej: "minimalist white background", "luxury studio lighting").