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:
- Public storefront API (
api/v1/storefront/*): unauthenticated, domain-resolved catalog browsing, checkout, and content pages consumed by the separate Storefront Astro app. - 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.
Data model
Section titled “Data model”Brand:name,slug,logo_url,is_visible;hasManyModules\Inventory\Models\NewStockviabrand_id.WebsiteCategoryOverride: a per-website publishing overlay on top of the tenant’s sharednew_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 sharednew_stockscatalog: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.
Public storefront catalog and checkout
Section titled “Public storefront catalog and checkout”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).”
Payment gateways
Section titled “Payment gateways”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.
Route surface
Section titled “Route surface”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 |
Elsewhere (see caution above)
Section titled “Elsewhere (see caution above)”GET/PUT inventory/stores/{store}/storefront-settings -> StorefrontSettingsController::show/update, registered in modules/Inventory/Routes/stock.php.
Related
Section titled “Related”- Inventory: shared catalog (
new_stocks,new_stock_categories) that the override models sit on top of; also whereStorefrontSettingsController’s routes actually live - Sales: checkout creates a real
Sale - Tuma:
TumaGatewaypayment method - SaleCustomers: checkout customer records