Features
All features are gated by environment flags. When disabled, routes are not registered and Filament resources are hidden.
Inventory Per Location
Flag: SHOPIFY_FEATURE_INVENTORY
Exposes product stock levels per physical location through the App Proxy.
How It Works
- Theme JS calls
GET /apps/lamashopi/inventory/{productHandle} - The app checks Redis cache for the product's inventory data
- On cache miss, queries the Shopify Admin API for inventory levels per location
- Returns stock data grouped by location (with optional slug mapping)
Cache Invalidation
Stock data is cached in Redis with a configurable TTL (SHOPIFY_INVENTORY_CACHE_TTL). When Shopify sends an inventory_levels/update webhook, the cache is invalidated for the affected product.
Location Slugs
Map Shopify location GIDs to URL-friendly slugs via SHOPIFY_LOCATION_SLUGS in .env. This lets the theme display clean location names instead of Shopify's internal identifiers.
Key Classes
ShopifyInventoryService— cache-aside inventory fetchingInventoryController— proxy endpointInventoryItemMapping— model for product-to-inventory-item mappings
Wishlists
Flag: SHOPIFY_FEATURE_WISHLISTS
Full wishlist functionality for both anonymous and authenticated shoppers.
Proxy Endpoints
| Method | Path | Description |
|---|---|---|
GET | /wishlists | Get wishlist items |
POST | /wishlists | Add item |
DELETE | /wishlists/{id} | Remove item |
POST | /wishlists/check | Check if items are in wishlist |
POST | /wishlists/merge | Merge anonymous wishlist into customer wishlist |
GET | /wishlists/share/{token} | Get shared wishlist |
Anonymous vs Authenticated
- Anonymous wishlists are identified by a session/device identifier
- Authenticated wishlists are tied to a Shopify customer ID
- On login, the theme should call the merge endpoint to combine anonymous items into the customer's wishlist
Filament Resource
Wishlists are viewable in the Agency panel for support and debugging.
Out-of-Stock Notifications
Flag: SHOPIFY_FEATURE_OOS
Lets shoppers subscribe to back-in-stock alerts for specific product variants.
Flow
- Shopper subscribes via
POST /apps/lamashopi/oos - Confirmation email is sent (double opt-in)
- Shopper confirms via
GET /oos/confirm/{token} - When
inventory_levels/updatewebhook fires and stock is now > 0, theDispatchBackInStockNotificationsjob sends notifications - Shopper can unsubscribe via
GET /oos/unsubscribe/{token}
Klaviyo Integration
When KLAVIYO_OOS_ENABLED=true, OOS events are synced to Klaviyo and email flows are handled by Klaviyo Flows instead of the built-in mailer.
Filament Resource
OOS subscriptions are manageable in the Agency panel.
Bundles
Flag: SHOPIFY_FEATURE_BUNDLES
Configurable product bundles with automatic Shopify discount creation.
Concepts
- Bundle — a named group of product slots that can be purchased together
- Bundle Slot — a position in the bundle that accepts specific products
- Bundle Slot Item — a product/variant that can fill a slot
- Bundle Anchor — the product(s) that trigger the bundle on PDP
- Bundle Discount — a Shopify automatic discount or discount code created for the bundle
Pricing Types
| Type | Enum | Description |
|---|---|---|
| Percentage | BundlePricingType::Percentage | Percentage off the bundle total |
| Fixed Amount | BundlePricingType::FixedAmount | Fixed amount off the bundle total |
| Fixed Total | BundlePricingType::FixedTotal | Bundle sells for a fixed total price |
Discount Lifecycle
The BundleDiscountService creates Shopify discounts via GraphQL. It first attempts an automatic discount; if that fails (e.g., limit reached), it falls back to a discount code.
Scheduled commands manage discount health:
bundles:cleanup— removes orphaned or expired discountsbundles:health— monitors discount status and alerts on issuesbundles:refresh-anchors— refreshes cached anchor-product mappings
Proxy Endpoints
| Method | Path | Description |
|---|---|---|
GET | /bundles/for-product/{handle} | Get bundles for a product |
GET | /bundles/for-products | Get bundles for multiple products |
GET | /bundles/{id}/slots/{slotId}/products | Get products for a slot |
POST | /bundles/add-to-cart | Add bundle to cart |
Filament Resource
Bundles are fully manageable in the Agency panel with a form for slots, items, anchors, and pricing.
Store Locator
Flag: SHOPIFY_FEATURE_STORE_LOCATOR
Physical store directory with geocoding and category filtering.
Features
- Store CRUD in Filament with address, coordinates, hours, and category
- Automatic geocoding via
NominatimGeocodingService(dispatched as a job) - CSV import via
StoreImporter - Store categories for filtering
- Proxy endpoint:
GET /apps/lamashopi/stores
Filament Resources
- Stores — full CRUD with geocoding
- Store Categories — category management
Free Shipping Bar
Flag: SHOPIFY_FEATURE_FREE_SHIPPING_BAR
Provides shipping threshold data from Shopify's shipping profiles.
Proxy Endpoint
GET /apps/lamashopi/shipping/thresholds — returns free shipping thresholds via ShopifyShippingService.
The theme uses this data to display a progress bar showing how much more the shopper needs to add for free shipping.