בניית חנות מסחר אלקטרוני על Spree: ממונולית ל-Headless
לקוח ביקש להוסיף מבצע "קנה 3, קבל את הרביעי בחינם" עם אימות היסטוריית הזמנות. ב-Shopify, זה ידרוש אפליקציית צד שלישי עם מנוי נפרד; ב-Spree — 50 שורות של דקורטור. Spree Commerce הוא מנוע Rails בקוד פתוח שאנו משתמשים בו לפרויקטים הדורשים התאמה אישית עמוקה. במאמר זה, נראה כיצד להגדיר ארכיטקטורת מונולית או headless ונסקור דוגמאות אמיתיות.
למה לבחור ב-Spree: מונולית או Headless?
Spree משתלב באפליקציית Rails כמנוע וחולק את אותו מסד נתונים. החל מגרסה 4.3, מצב headless דרך REST API v2 מאפשר שימוש ב-Spree כקצה אחורי לחזיתות React/Vue. זה מתאים גם לחנויות פשוטות עם רינדור שרת וגם ל-SPA מורכבים. בואו נשווה.
| קריטריון | מונולית (קלאסי) | Headless |
|---|---|---|
| ארכיטקטורה | מנוע Rails עם חנות ברינדור שרת (ERB + Turbo) | Spree מספק API, החזית נפרסת בנפרד (Next.js, Nuxt) |
| צוות | מפתחי Rails + אולי חזית | צוות חזית נפרד, Ruby בצד השרת |
| ביצועים | SSR, שמירה במטמון קלה | גמישות, פונקציות קצה אפשריות |
| זמן פיתוח | מהיר יותר, פחות חלקים נעים | ארוך יותר אך ניתן להרחבה |
| מתי לבחור | צוותים קטנים, חנויות פשוטות, ללא דרישות אפליקציית מובייל | פרויקטים מורכבים, אפליקציות לקוח מרובות, עומס גבוה |
איך להגדיר את Spree לפרויקט שלך?
הגדרת הסביבה כוללת התקנת gems נדרשים והרצת generators. התקנה סטנדרטית: הוספת gems, הרצת generators, העברת מסד הנתונים. מלכודות נפוצות: הגדרת מסד נתונים שגויה או קונפליקטים בגרסאות gems.
# Gemfile
gem 'spree', '~> 4.10'
gem 'spree_auth_devise', '~> 4.6'
gem 'spree_gateway', '~> 3.10'
gem 'spree_backend', '~> 4.10'
gem 'spree_sample', '~> 4.10' # тестовые данные
# Для headless: gem 'spree_api', '~> 4.10'
bundle install bin/rails g spree:install bin/rails g spree:auth:install bin/rails db:migrate bin/rails db:seed לאחר ההתקנה, אתה מקבל:
-
# Gemfile gem 'spree', '~> 4.10' gem 'spree_auth_devise', '~> 4.6' gem 'spree_gateway', '~> 3.10' gem 'spree_backend', '~> 4.10' gem 'spree_sample', '~> 4.10' # тестовые данные # Для headless: gem 'spree_api', '~> 4.10'— פאנל ניהול -
bundle install bin/rails g spree:install bin/rails g spree:auth:install bin/rails db:migrate bin/rails db:seed— REST API לחזית -
/admin— חנות קלאסית (אם/api/v2/storefrontמותקן)
מודל הנתונים של Spree
מסד הנתונים של Spree סובב סביב ישויות מפתח: חנויות (תמיכה בריבוי חנויות), קטגוריות (מקוננות דרך ancestry), מוצרים עם וריאנטים (SKU, מחיר, אפשרויות), הזמנות עם פריטי שורה, תשלומים ומשלוחים, משתמשים.
Spree::Store
├── Spree::Taxon (категории через ancestry)
├── Spree::Product
│ ├── Spree::Variant
│ ├── Spree::Price
│ └── Spree::Image
├── Spree::Order
│ ├── Spree::LineItem
│ ├── Spree::Payment
│ └── Spree::Shipment
└── Spree::User (через spree_auth_devise) בניית חנות Headless עם Next.js ו-Spree API
לפרויקטים של headless, אנו משתמשים ב-/ ועובדים דרך REST API. בפרויקט אחד, החלפנו את החנות המונוליתית ב-Next.js 14 עם ISR, והשגנו LCP מתחת ל-0.8 שניות — שיפור משמעותי ב-Core Web Vitals. React Server Components מאפשרים רינדור שרת מהיר של דפי מוצר.
// lib/spreeClient.ts
import { makeClient } from "@spree/storefront-api-v2-sdk";
export const client = makeClient({
host: process.env.NEXT_PUBLIC_SPREE_URL!,
});
// Получить товары
const products = await client.products.list(
{
include: "default_variant,images,taxons",
filter: {
taxons: taxonId,
},
},
{
sort: "name",
page: 1,
per_page: 24,
}
);
// Создать корзину
const cart = await client.cart.create();
const orderToken = cart.success().data.attributes.token;
await client.cart.addItem(
{ orderToken },
{
variant_id: variantId,
quantity: 1,
}
);
התאמת לוגיקה עסקית ללא Fork
Spree משתמש בתבנית הדקורטור: אנו מוסיפים מתודות ואסוציאציות במודול שמעורבב במודל. זה מרחיב פונקציונליות מבלי לגעת בליבה.
# app/models/spree/product_decorator.rb
module Spree
module ProductDecorator
def self.prepended(base)
base.has_many :bundle_parts, class_name: "Spree::BundlePart", foreign_key: :bundle_product_id
end
def bundle?
bundle_parts.any?
end
def effective_price_for(quantity)
if quantity >= 10
price * 0.9
elsif quantity >= 5
price * 0.95
else
price
end
end
end
end
Spree::Product.prepend(Spree::ProductDecorator)למבצעים, השתמש במערכת spree_frontend המובנית. לדוגמה, כלל "15% הנחה על הזמנות מעל 2000 רובל":
promotion = Spree::Promotion.create!(
name: "Летняя скидка 15%",
code: "SUMMER15",
starts_at: Date.today,
expires_at: 3.months.from_now,
usage_limit: 1000
)
promotion.actions.create!(
type: "Spree::Promotion::Actions::CreateAdjustment",
calculator: Spree::Calculator::FlatPercentItemTotal.create!(preferred_flat_percent: 15.0)
)
promotion.rules.create!(
type: "Spree::Promotion::Rules::ItemTotal",
preferred_operator: "gte",
preferred_amount: 2000.0
)גמישות זו מאפשרת מבצעים מורכבים ללא תוספים נוספים.
מה כלול בעבודה: מחזור פיתוח מלא
אנו מציעים פיתוח turnkey. שלבי הפרויקט:
| שלב | תיאור | משך (ימים) |
|---|---|---|
| התקנה והגדרה | אפליקציית Rails, מנוע Spree, מסד נתונים | 2–3 |
| קטלוג + ייבוא מוצרים | משימות Rake, ייבוא CSV/API | 4–8 |
| לוגיקה עסקית מותאמת | דקורטורים, מבצעים, משלוח | 5–10 |
| חזית (Headless) | Next.js + Spree SDK | 10–20 |
| אינטגרציות תשלום | 2–3 ספקים | 4–6 |
| התאמת פאנל ניהול | סעיפים נוספים, דוחות | 3–5 |
| סה"כ | 28–52 |
התוצאה כוללת: תיעוד API, גישה למאגר ולשרת, הדרכת צוות הלקוח, אחריות ל-30 יום על באגים. למהנדסים שלנו יש 10+ פרויקטים מסחריים של Spree.
אינטגרציית תשלום וריבוי מטבעות
Spree::Store ├── Spree::Taxon (категории через ancestry) ├── Spree::Product │ ├── Spree::Variant │ ├── Spree::Price │ └── Spree::Image ├── Spree::Order │ ├── Spree::LineItem │ ├── Spree::Payment │ └── Spree::Shipment └── Spree::User (через spree_auth_devise) מספק מתאמים מוכנים ל-Stripe, Braintree, PayPal. עבור YooKassa או Tinkoff, אנו כותבים שער מותאם אישית (מימוש ממשק @spree/storefront-api-v2-sdk). ריבוי מטבעות מוגדר דרך תכונות החנות: הגדר // lib/spreeClient.ts import { makeClient } from "@spree/storefront-api-v2-sdk"; export const client = makeClient({ host: process.env.NEXT_PUBLIC_SPREE_URL! }); // Получить товары const products = await client.products.list( { include: "default_variant,images,taxons", filter: { taxons: taxonId } }, { sort: "name", page: 1, per_page: 24 } ); // Создать корзину const cart = await client.cart.create(); const orderToken = cart.success().data.attributes.token; await client.cart.addItem({ orderToken }, { variant_id: variantId, quantity: 1 }); ו-# app/models/spree/product_decorator.rb module Spree module ProductDecorator def self.prepended(base) base.has_many :bundle_parts, class_name: "Spree::BundlePart", foreign_key: :bundle_product_id end def bundle? bundle_parts.any? end def effective_price_for(quantity) if quantity >= 10 then price * 0.9 elsif quantity >= 5 then price * 0.95 else price; end end end end Spree::Product.prepend(Spree::ProductDecorator) . מחירים מקושרים למטבע של הוריאנט.
טעויות נפוצות כשמתחילים עם Spree
- אי שימוש בדקורטורים — עריכת ליבת Spree ישירות הופכת עדכונים לבלתי אפשריים.
- שכחת שאילתות N+1 ב-API — תמיד כלול
Spree::Promotionבבקשות. - התעלמות מביצועי פאנל הניהול — עבור קטלוגים גדולים, יש צורך ב-Elasticsearch.
- אי הגדרת שמירה במטמון — Redis הוא חובה לייצור. בלעדיו, החנות מאטה עם 1000+ מוצרים.
איך לבחור בין מונולית ל-Headless?
אם הצוות שלך חזק ב-Rails ואתה צריך חנות טיפוסית, לך על מונולית — זה מהיר יותר להתחיל. אם אתה מתכנן אפליקציית מובייל, חזית מורכבת או עומס גבוה, headless מציע גמישות אך דורש יותר משאבי פיתוח. הזמן פיתוח חנות Spree — ניצור איתך קשר תוך יום. קבל ייעוץ דרך הטופס באתר או במסנג'רים.







