Files
manoon-headless/ecommerce-features-checklist.md
Unchained 7b94537670 feat(saleor): Phase 1 - GraphQL Client Setup
- Add Apollo Client for Saleor GraphQL API
- Create GraphQL fragments (Product, Variant, Checkout)
- Create GraphQL queries (Products, Checkout)
- Create GraphQL mutations (Checkout operations)
- Add TypeScript types for Saleor entities
- Add product helper functions
- Install @apollo/client and graphql dependencies

Part of WordPress/WooCommerce → Saleor migration
2026-03-21 12:36:21 +02:00

12 KiB

Advanced E-Commerce Features Checklist

Saleor Built-in vs Missing Features

Built-in (Ready to Use)

Feature Saleor Support Notes
Products & Variants Native Simple & variable products
Categories Native Hierarchical with nesting
Collections Native Manual & automated collections
Inventory Native Multi-warehouse support
Multi-language Native Full translation support
Multi-currency Native Per-channel pricing
Promotions Native % off, fixed amount, vouchers
Gift Cards Native Digital gift cards
Taxes Native Per-country tax rates
Shipping Native Zones & methods
Customer Accounts Native Full account management
Order Management Native Status tracking, fulfillments
Staff Permissions Native Role-based access
Pages & Menus Native CMS features
Checkout Native Customizable flow
Payments Native Stripe, Adyen, etc.

Missing Features (Need to Build/Add)

1. Product Reviews HIGH PRIORITY

Status: NOT in Saleor (on roadmap but not planned)

Solutions:

Solution Cost Effort Best For
Judge.me Free-$15/mo 2 hours Budget option, works well
Trustpilot $200+/mo 2 hours SEO, brand trust
Yotpo $300+/mo 4 hours Enterprise, UGC
Build Custom Free 2-4 weeks Full control

Custom Build SQL:

CREATE TABLE product_review (
    id SERIAL PRIMARY KEY,
    product_id INTEGER REFERENCES product_product(id),
    user_id INTEGER REFERENCES account_user(id),
    rating INTEGER CHECK (rating >= 1 AND rating <= 5),
    title VARCHAR(255),
    comment TEXT,
    is_verified_purchase BOOLEAN DEFAULT false,
    is_approved BOOLEAN DEFAULT false,
    helpful_count INTEGER DEFAULT 0,
    created_at TIMESTAMP DEFAULT NOW()
);

2. Upsells & Cross-sells HIGH PRIORITY

Status: NOT in Saleor (confirmed missing)

What You Need:

-- Related products / upsells table
CREATE TABLE product_related (
    id SERIAL PRIMARY KEY,
    product_id INTEGER REFERENCES product_product(id),
    related_product_id INTEGER REFERENCES product_product(id),
    type VARCHAR(50), -- 'upsell', 'cross_sell', 'related'
    sort_order INTEGER DEFAULT 0,
    created_at TIMESTAMP DEFAULT NOW(),
    UNIQUE(product_id, related_product_id, type)
);

Types of Upsells:

Type Example Location
Upsell 500ml → 1L (upgrade) Product page
Cross-sell Olive oil + vinegar (complementary) Cart page
Related Same category products Product page
Bundle Oil + vinegar + herbs package Product page
Frequently Bought Together AI-based recommendations Cart page

Implementation Options:

Option A: Manual (Product-Level)

-- Admin manually assigns related products
INSERT INTO product_related (product_id, related_product_id, type, sort_order)
VALUES 
(1, 5, 'upsell', 1),      -- Product 1 shows Product 5 as upsell
(1, 6, 'cross_sell', 1),  -- Product 1 shows Product 6 as cross-sell
(1, 7, 'related', 1);     -- Product 1 shows Product 7 as related

Admin UI Needed:

  • Product edit page with "Related Products" section
  • Search & select products
  • Drag to reorder
  • Choose type (upsell/cross-sell/related)

Option B: Automated (Category-Based)

// Automatically show products from same category
const getRelatedProducts = async (productId: string, categoryId: string) => {
  return await saleorClient.query({
    query: gql`
      query GetRelatedProducts($categoryId: ID!, $excludeId: ID!) {
        products(
          first: 4,
          filter: {categories: [$categoryId]},
          channel: "default-channel"
        ) {
          edges {
            node {
              id
              name
              slug
              thumbnail { url }
              variants {
                channelListings {
                  price { amount currency }
                }
              }
            }
          }
        }
      }
    `,
    variables: { categoryId, excludeId: productId }
  });
};

Option C: AI/ML Recommendations (Advanced)

Services:

  • Recombee - $99/mo+
  • Amazon Personalize - Pay per use
  • Algolia Recommend - $29/mo+
  • Build custom - Requires order history analysis

Effort: High (4-8 weeks)


3. Product Bundles MEDIUM PRIORITY

Status: NOT in Saleor (requested, on roadmap)

Example:

  • Olive Oil 500ml + Vinegar 250ml = Bundle price $15 (save $3)

Custom Implementation:

-- Bundle definition
CREATE TABLE product_bundle (
    id SERIAL PRIMARY KEY,
    name VARCHAR(250),
    slug VARCHAR(255) UNIQUE,
    description JSONB,
    product_type_id INTEGER REFERENCES product_producttype(id),
    bundle_price_amount NUMERIC(20,3),
    currency VARCHAR(3),
    is_active BOOLEAN DEFAULT true,
    created_at TIMESTAMP DEFAULT NOW()
);

-- Bundle items
CREATE TABLE product_bundle_item (
    id SERIAL PRIMARY KEY,
    bundle_id INTEGER REFERENCES product_bundle(id),
    product_variant_id INTEGER REFERENCES product_productvariant(id),
    quantity INTEGER DEFAULT 1,
    sort_order INTEGER DEFAULT 0
);

Storefront Display:

// Show bundle on product page
<ProductBundle 
  bundle={{
    name: "Mediterranean Starter Pack",
    items: [
      { name: "Olive Oil 500ml", price: 12 },
      { name: "Balsamic Vinegar 250ml", price: 6 },
    ],
    regularPrice: 18,
    bundlePrice: 15,
    savings: 3
  }}
/>

4. Abandoned Cart Recovery HIGH PRIORITY

Status: NOT in Saleor

Solutions:

  1. Mautic (FREE - you have it!) - See mautic-abandoned-cart.md
  2. Klaviyo - $20-50/mo
  3. N8N automation - FREE

5. Email Marketing MEDIUM PRIORITY

Status: NOT in Saleor

Solutions:

  1. Mautic (FREE - you have it!)
  2. Klaviyo - Best for e-commerce
  3. Mailchimp - Good free tier

Email Types Needed:

  • Welcome email
  • Order confirmation
  • Shipping notification
  • Post-purchase follow-up
  • Win-back campaign
  • Birthday discount

6. Loyalty/Rewards Program MEDIUM PRIORITY

Status: NOT in Saleor

Custom Build:

-- Loyalty points
CREATE TABLE loyalty_account (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES account_user(id),
    points_balance INTEGER DEFAULT 0,
    lifetime_points INTEGER DEFAULT 0,
    tier VARCHAR(50) DEFAULT 'bronze', -- bronze, silver, gold
    created_at TIMESTAMP DEFAULT NOW()
);

-- Points transactions
CREATE TABLE loyalty_transaction (
    id SERIAL PRIMARY KEY,
    account_id INTEGER REFERENCES loyalty_account(id),
    points INTEGER, -- positive for earn, negative for redeem
    type VARCHAR(50), -- 'purchase', 'referral', 'redemption', 'bonus'
    description TEXT,
    order_id INTEGER REFERENCES order_order(id),
    created_at TIMESTAMP DEFAULT NOW()
);

7. Subscription/Recurring Products LOW PRIORITY

Status: NOT in Saleor

Solutions:

  • Stripe Billing - Best integration
  • Recharge - $300/mo+ (Shopify-focused)
  • Chargebee - $249/mo+
  • Build custom with Stripe

8. Wishlist/Favorites MEDIUM PRIORITY

Status: NOT in Saleor

Simple Implementation:

CREATE TABLE wishlist_item (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES account_user(id),
    product_variant_id INTEGER REFERENCES product_productvariant(id),
    added_at TIMESTAMP DEFAULT NOW(),
    UNIQUE(user_id, product_variant_id)
);

9. Recently Viewed Products LOW PRIORITY

Implementation:

// Store in localStorage or Redis
const trackProductView = (productId: string) => {
  const recentlyViewed = JSON.parse(localStorage.getItem('recentlyViewed') || '[]');
  recentlyViewed.unshift(productId);
  localStorage.setItem('recentlyViewed', JSON.stringify(recentlyViewed.slice(0, 10)));
};

10. Product Comparison LOW PRIORITY

Implementation:

// Allow users to compare 2-3 products side-by-side
const ProductComparison = ({ products }) => {
  return (
    <table>
      <thead>
        <tr>
          <th>Feature</th>
          {products.map(p => <th key={p.id}>{p.name}</th>)}
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Price</td>
          {products.map(p => <td key={p.id}>${p.price}</td>)}
        </tr>
        <tr>
          <td>Volume</td>
          {products.map(p => <td key={p.id}>{p.volume}</td>)}
        </tr>
      </tbody>
    </table>
  );
};

11. Quick View (Modal) LOW PRIORITY

Implementation:

// Product card with quick view button
<ProductCard>
  <Image src={product.thumbnail} />
  <h3>{product.name}</h3>
  <button onClick={() => openQuickView(product.id)}>
    Quick View
  </button>
</ProductCard>

// Modal fetches product details
<QuickViewModal productId={selectedProductId} />

12. AJAX Add to Cart (No Page Reload) MEDIUM PRIORITY

Implementation:

const AddToCartButton = ({ variantId }) => {
  const [adding, setAdding] = useState(false);
  
  const handleAdd = async () => {
    setAdding(true);
    await saleorClient.mutate({
      mutation: ADD_TO_CART,
      variables: { variantId, quantity: 1 }
    });
    setAdding(false);
    showToast('Added to cart!');
    updateCartCount(); // Update header cart icon
  };
  
  return <button onClick={handleAdd} disabled={adding}>Add to Cart</button>;
};

13. Dynamic Pricing / Volume Discounts LOW PRIORITY

Example:

  • Buy 1: $12
  • Buy 2: $11 each (save $2)
  • Buy 3+: $10 each (save $6)

Saleor Native: Not supported

Custom:

const getVolumePrice = (basePrice: number, quantity: number) => {
  if (quantity >= 3) return basePrice * 0.83; // 17% off
  if (quantity >= 2) return basePrice * 0.92; // 8% off
  return basePrice;
};

14. Back in Stock Notifications MEDIUM PRIORITY

Implementation:

CREATE TABLE stock_notification_request (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255),
    product_variant_id INTEGER REFERENCES product_productvariant(id),
    is_notified BOOLEAN DEFAULT false,
    created_at TIMESTAMP DEFAULT NOW()
);

-- When stock is updated, check and send emails

Phase 1: Essential (Launch)

  • Saleor core products
  • Reviews (Judge.me or custom)
  • Upsells/Cross-sells (manual assignment)
  • AJAX cart
  • Mautic abandoned cart

Phase 2: Growth (1-3 months post-launch)

  • Email marketing (Mautic or Klaviyo)
  • Wishlist
  • Bundles
  • Recently viewed

Phase 3: Advanced (6+ months)

  • Loyalty program
  • AI recommendations
  • Subscriptions
  • Product comparison

Cost Summary

Feature DIY Build Third-Party Recommended
Reviews 2-4 weeks Judge.me FREE Judge.me
Upsells 1-2 weeks N/A Custom
Bundles 2-3 weeks N/A Custom
Abandoned Cart 2-3 days Klaviyo $20/mo Mautic FREE
Email Marketing 1 week Klaviyo $20/mo Mautic FREE
Loyalty 2-3 weeks Smile.io $199/mo Custom later
Subscriptions 4-6 weeks Recharge $300/mo Stripe later

Total Estimated Dev Time

Phase 1: 4-6 weeks Phase 2: 3-4 weeks
Phase 3: 6-8 weeks

Total: 3-4 months for full-featured store