Skip to content

Ecommerce

Location: dg_smart_pos_api/modules/Ecommerce. The largest of the five modules covered here (13 controllers). It has two distinct halves that run under two different route files and two different trust boundaries:

  1. Public storefront API (api/v1/storefront/*): unauthenticated, domain-resolved catalog browsing, checkout, and content pages consumed by the separate Storefront Astro app.
  2. Website Studio (website-studio/stores/{store}/*): authenticated, tenant-side self-service editing of that same storefront’s branding, homepage sections, and content pages.

Per-website customization on top of the tenant’s shared POS catalog (brand, category, and product overrides) is this module’s own data; the checkout flow creates a real Sales Sale under the hood rather than owning orders as a separate concept.

  • Brand: name, slug, logo_url, is_visible; hasMany Modules\Inventory\Models\NewStock via brand_id.
  • WebsiteCategoryOverride: a per-website publishing overlay on top of the tenant’s shared new_stock_categories: website_id, category_id, parent_override_id (self-referencing, lets a website build its own category tree shape), slug, image_url, is_visible, is_featured, sort_order.
  • WebsiteProductOverride: a per-website publishing/SEO overlay on the tenant’s shared new_stocks catalog: website_id, stock_id, slug, is_published, is_featured, seo_title/seo_description, override_description, sort_order.

Both override models’ website_id is deliberately not an Eloquent relation: Website (App\Models\Website) lives in the central database, a different MySQL connection from the tenant DB these override tables live in, so website_id is only ever compared as a plain integer against the Website resolved by ResolveWebsiteMiddleware, never belongsTo’d.

StorefrontConfigController::show returns a website’s public config in one call (branding, enabled content pages, etc.) so the storefront can bootstrap in a single request. ProductController::index/show and CategoryController::index read through StorefrontCatalogService, which is what actually merges the tenant’s shared catalog with this website’s WebsiteProductOverride/WebsiteCategoryOverride rows. BrandController::index lists brands. PaymentMethodController::index asks PaymentGatewayRegistry::availableFor($website) which of the three gateways (see below) this website has turned on.

CheckoutController::store validates cart items, customer details, and a payment_method (tuma/cod/pickup), then hands off to StorefrontCheckoutService::checkout(), which creates the actual Sale and initiates payment through the selected gateway. OrderController::show looks an order back up by receipt number for the storefront’s order-confirmation page. StorefrontPageController::show serves static content pages (about-us, contact, return-policy, etc.) by slug. ProductFeedController generates a Google Merchant XML feed and a Meta Catalog CSV, described in docs/STOREFRONT_PLATFORM_INTEGRATIONS.md as “Phase 1 platform-integration feeds (no OAuth).”

PaymentGatewayContract is implemented by three classes under PaymentGateways/: TumaGateway (delegates to TumaPaymentService, the Tuma module), CashOnDeliveryGateway, and StorePickupGateway. PaymentGatewayRegistry resolves which are available/enabled for a given website and exposes their settings.

Website Studio (tenant self-service editing)

Section titled “Website Studio (tenant self-service editing)”

WebsiteStudioController::show/update read and write the website’s full record (theme, branding, homepage sections, navigation, SEO, name, currency, locale); uploadHomepageSectionImage/deleteHomepageSectionImage manage per-section images. WebsitePageStudioController edits the same built-in content pages the public API serves (index/show/update/reset, keyed by a fixed page {key}, explicitly not the page’s slug, “slugs are fixed and never editable”). WebsitePaymentGatewayStudioController::index is read-only, showing which gateways are live so the studio’s Checkout screen matches what customers actually see; enabling a gateway needs credentials and stays with central admin.

Public storefront (modules/Ecommerce/Routes/ecommerce.php)

Section titled “Public storefront (modules/Ecommerce/Routes/ecommerce.php)”

Required from routes/storefront.php, which wraps it in ['api', ResolveWebsiteMiddleware, CheckSubscriptionStatus] and prefix api/v1/storefront. routes/storefront.php itself is registered from TenancyServiceProvider, not routes/tenant.php, explicitly “a different trust boundary… assumes an already-authenticated POS client,” unlike this one, which is public and domain-resolved. No auth:sanctum on any of these:

Method Path Controller method
GET config StorefrontConfigController::show
GET products ProductController::index
GET products/{slug} ProductController::show
GET categories CategoryController::index
GET brands BrandController::index
GET payment-methods PaymentMethodController::index
POST checkout CheckoutController::store
GET orders/{receipt} OrderController::show
GET pages/{slug} StorefrontPageController::show
GET feed/google-merchant.xml ProductFeedController::googleMerchant
GET feed/meta-catalog.csv ProductFeedController::metaCatalog

Website Studio (modules/Ecommerce/Routes/website_studio.php)

Section titled “Website Studio (modules/Ecommerce/Routes/website_studio.php)”

All under auth:sanctum, prefix website-studio/stores/{store}, required from routes/tenant.php:

Method Path Controller method Permission
GET / WebsiteStudioController::show storefront:view-settings
PUT / WebsiteStudioController::update storefront:manage-settings
POST homepage-sections/{sectionId}/image WebsiteStudioController::uploadHomepageSectionImage storefront:manage-settings
DELETE homepage-sections/{sectionId}/image WebsiteStudioController::deleteHomepageSectionImage storefront:manage-settings
GET pages WebsitePageStudioController::index storefront:view-settings
GET pages/{key} WebsitePageStudioController::show storefront:view-settings
PUT pages/{key} WebsitePageStudioController::update storefront:manage-settings
POST pages/{key}/reset WebsitePageStudioController::reset storefront:manage-settings
GET payment-gateways WebsitePaymentGatewayStudioController::index storefront:view-settings

GET/PUT inventory/stores/{store}/storefront-settings -> StorefrontSettingsController::show/update, registered in modules/Inventory/Routes/stock.php.

  • Inventory: shared catalog (new_stocks, new_stock_categories) that the override models sit on top of; also where StorefrontSettingsController’s routes actually live
  • Sales: checkout creates a real Sale
  • Tuma: TumaGateway payment method
  • SaleCustomers: checkout customer records