Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Dystore Laravel Package

dystcz/dystore

Dystore is a Laravel/PHP e-commerce package that provides a flexible foundation for building online stores, with tools for product, cart, and order management and an extendable architecture suited to custom storefronts and commerce features.

View on GitHub
Deep Wiki
Context7

Getting Started

Dystore is a headless commerce API for Laravel built on top of Lunar. It exposes JSON:API endpoints (products, variants, carts, orders, customers, checkout, etc.) that you consume from a storefront (Next.js, Nuxt, mobile, etc.). As of 1.0.15 it targets PHP 8.3+ and Laravel 12, with Lunar 1.5.0-beta.6 as the underlying commerce engine.

  1. Confirm your stack: php -v (≥ 8.3), composer show laravel/framework (12.x). Laravel 11 and PHP 8.2 are no longer supported.
  2. Install: composer require dystcz/dystore. Lunar is pulled in transitively — check composer show lunarphp/lunar matches the beta line Dystore expects.
  3. Publish and run: publish Dystore config + migrations, then php artisan migrate, then seed the Lunar base data (countries, currencies, tax classes, etc.) if you have not already.
  4. Look first at:
    • config/dystore.php — model bindings, route prefix, media/URL config.
    • routes/dystore.php (or the route service provider) — the canonical endpoint list. php artisan route:list --path=api is the fastest way to see what is live.
    • src/JsonApi/ — the resource/schema classes you will extend to add fields.
  5. First use case: GET /api/v1/products with ?include=variants,prices&fields[products]=name,slug to confirm the API boots end-to-end. Then wire an auth flow using the new check-account-exists endpoint before hitting register (which can now create users without a password).

Implementation Patterns

Adding fields to the API. Dystore's schemas are plain classes extending LaravelJsonApi\Eloquent\Schema. Register a custom schema in config/dystore.php, override fields() and getRelations(), and add a Field or Attribute for anything not exposed by default. Never edit vendor files.

Swapping models. Dystore binds Lunar models (Product, Variant, Order, Cart, User…). To extend behaviour — say a custom User with extra profile columns — subclass the Dystore model and rebind it in config/dystore.php. Because Dystore models already extend Lunar's, you compose rather than replace.

Password-less registration. Since 1.0.15 register accepts users without a password. Typical pattern: a guest checkout flow where the user is created on first order, then a "set your password" email is sent. Guard against duplicate emails by calling the check-account-exists endpoint first; it returns a boolean so the storefront can branch into login vs. registration.

Account deletion. The delete-user endpoint (1.0.15) enables self-service GDPR erasure. Wire it to a confirmation modal and consider queuing a soft-delete/anonymisation listener rather than hard-deleting, since orders and reviews reference the user.

Availability filtering. Use the new product and variant availability scopes instead of reimplementing "in stock and published" logic. They compose with the existing nested collection group filters (1.0.15) so a storefront can request e.g. filter[collection.groups]=... and filter[available]=true in one call — ideal for category pages and mega-menus.

Reviews. Reviews now carry an order relation (1.0.15) and the Filament admin shows all reviews (the PublishedScope was removed). If you want verified-purchase badges on the storefront, expose the relation and check review.order_id against the current customer's orders. Keep your own publish filter on the API-facing schema if you do not want unpublished reviews leaking.

Filament admin. Dystore ships admin resources. Run php artisan filament:upgrade after updating and ensure your panel provider registers the Dystore plugin. Use it to validate storefront behaviour against real order data.

Testing. Dystore moved to Pest 4. Use RefreshDatabase + the published factories, and assert against the JSON:API document shape (assertJsonPath('data.0.type', 'products')) rather than raw arrays. Fake the Lunar cart/checkout pipeline where you can — full checkout tests are slow.

Integration tips. Use sparse fieldsets aggressively (fields[...]) and cache product responses at the edge — the payloads are large by default. Keep Dystore routes behind a versioned prefix and add your own middleware (CORS, throttling) at the route-group level, not inside vendor routes.

Gotchas and Tips

  • Breaking upgrades first: 1.0.15 drops Laravel 11 and PHP 8.2. Bump both in CI matrices before pulling this release, or the update will fail at composer resolution.
  • Lunar is a beta. 1.5.0-beta.6 means internal APIs can shift between patch releases. Pin lunarphp/lunar with an exact constraint and read Lunar's release notes as carefully as Dystore's — this is the most common source of surprise breakage.
  • JSON:API strictness. Requests must send Content-Type: application/vnd.api+json and Accept: application/vnd.api+json. A missing header yields a 4xx that looks like an auth error. Error bodies are JSON:API errors[] arrays, not Laravel's message shape — handle both if you have shared frontend error handling.
  • Password-less users can't password-login. A user created without a password will fail standard Auth::attempt. Decide up front whether you use magic links, OTP, or a forced password-set step.
  • Filament review scope change. The admin now shows unpublished reviews. If a merchant previously relied on the admin hiding drafts, the "Published" toggle becomes the only control — document it or add a custom table filter.
  • Rebinding models requires clearing caches. After editing config/dystore.php, run php artisan config:clear and route:clear. Stale config is the #1 cause of "my custom model is ignored."
  • Migration order matters. Publish Lunar migrations before Dystore's, and run Dystore's after any upstream Lunar schema changes from the beta. Squash on fresh installs rather than trying to migrate a beta-era database forward.
  • N+1 on includes. ?include=variants,prices,media can fan out fast. Prefer sparse fieldsets plus explicit includes, and add indexes on product_id/variant_id foreign keys for large catalogues.
  • Availability scopes assume stock config. They respect Lunar's stock settings — if you manage inventory externally, override the scope or sync stock before querying, otherwise "available" will be wrong.
  • Debugging. Use php artisan route:list --path=api -v to confirm which controller/model served a request, Telescope for query counts, and log the raw JSON:API request body when a write endpoint returns 422 — validation errors are buried in errors[].source.pointer.
  • Extension points to prefer: config model bindings, custom schemas, custom route groups, and event listeners on Dystore/Lunar domain events. Avoid subclassing controllers; they are the least stable surface across minor versions.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource