giorgigrdzelidze/laravel-shopify-sdk
Laravel Shopify SDK provides a clean integration for building Shopify apps and store integrations in Laravel. It helps manage Shopify API access, authentication, webhooks, and common resources so you can focus on app logic instead of boilerplate.
This release completes an authorization story rather than adding features. v2.0.0 gated 11 of 15 Filament resources behind a HasShopifyPermissions trait; v2.1.0 closes the remaining four (DraftOrderResource, FulfillmentResource, DiscountResource, MetafieldResource) and adds analytics.view to the Analytics page. From a TPM lens, the value is that a consumer app can delete bespoke authorization workarounds — deny-all policies on four models plus disabling and re-registering a page — and inherit a consistent gate.
Architecture fit. The package is a domain SDK with a presentation layer attached: Filament resources over Shopify data. The trait is a cross-cutting concern implemented at the resource boundary (Filament's canViewAny / canCreate / canEdit / canDelete), and it inverts control correctly by delegating the actual decision to a method the host application owns — hasShopifyPermission(). The package does not own the RBAC store, does not assume a roles table schema, and does not couple to a specific permission backend. That is the right seam for a package that will be embedded in many differently-shaped apps. Permission naming is namespaced per resource (draft_orders.*, fulfillments.*, discounts.*, metafields.*, analytics.view), and the unit test explicitly asserts no cross-prefix leakage — a small but meaningful signal that the author treats the prefix as a contract, not an implementation detail.
Integration feasibility. High for any team already on Laravel + Filament. The release is fully backward compatible and the migration is essentially one method on the User model plus permission data. The require-dev move for filament/filament is the correct packaging decision — it makes Filament a peer dependency rather than forcing a version on consumers — and it is what allows the gating tests to run against real Filament classes instead of stubs. The test suite (106 passing, 226 assertions) with a dedicated FilamentResourceGatingTest covering the no-user / no-grant / granted / legacy-user matrix, plus a Filament-free unit matrix over the trait itself, is roughly the right shape for this risk class.
Technical risk.
hasShopifyPermission() receives full access. This is deliberate and necessary for backward compatibility, but it means the security posture of the consuming app depends on a method existing. This is the single most important item to verify during integration, and it should be an explicit checklist item rather than an assumption.DiscountResource are cheap insurance.discount.view vs discounts.view) produces a silent deny with no error surface. Seed data and policies must be tested against exact strings.require-dev, the tested Filament version is a proxy for support, not an enforced constraint. Confirm the supported major(s) before planning an upgrade cadence.Gate::before super-admin bypass. Consumers who left their deny-all policies in place may now double-deny or hit undefined ordering.Key questions.
composer.json?hasShopifyPermission() store-scoped? The release frames permissions as belonging to "a store"; if the signature is global, multi-store installs need a store-aware wrapper.Gate::before? Which wins?hasShopifyPermission() throws (e.g., upstream Shopify API unavailable) — fail open or fail closed?Stack fit. Laravel + Filament admin panel over Shopify merchant data: orders, draft orders, fulfillments, discounts, metafields, plus an Analytics dashboard. This is exactly the "we need an internal ops console for Shopify data" problem, and the package converts that from a build to a configuration exercise. Teams not on Filament get no value from this release.
Migration path (sequenced).
v2.1.0 explicitly. Confirm Filament is already a direct dependency at a version the package tests against; do not let require-dev lull you into an untested Filament upgrade in the same change.hasShopifyPermission() on the User model. This is the switch that turns gating on — until it exists, nothing changes. Build it against the permission backend you already have; the package does not care what it is.Compatibility. Fully backward compatible per the release notes. The one behavior change is for apps that had adopted the permission contract and were also relying on deny-all policies to mask the four resources — those policies are now redundant, and if left in place may interact with the trait in an undefined order. Clean them up rather than layering.
Sequencing caution. Enabling hasShopifyPermission() is a global flip: it turns on gating for the 11 already-gated resources and the Analytics page at the same moment, not per-resource. Do not attempt a partial rollout by resource; plan the permission data for the full set before the flip, or the first deploy will hide things users expect.
Maintenance. Net reduction. The release's own framing — "those workarounds can be deleted" — is the operational headline: custom authorization code in the consumer app shrinks, and the maintenance burden shifts to a versioned dependency with a changelog and a real test suite. Ongoing cost is version pinning plus a periodic upgrade pass tied to Filament majors.
Support. Expect recurring tickets of the form "why can everyone see Discounts?" — that is the fail-open legacy path surfacing. Write the switch into an internal runbook: if hasShopifyPermission() is missing, all gated resources are open. Also expect permission-denied states to become user-visible, so the 403/empty-state copy in the admin panel needs to be intentional rather than Filament's default.
Scaling. The check itself is a string comparison and is negligible. The scaling question is whether hasShopifyPermission() performs I/O. Filament evaluates canViewAny, canCreate, canEdit, and canDelete per resource and potentially per row; if each check hits the database or an external service, large tables will show it. Cache the resolved permission set per request (or per user per request) inside the implementation — this is a consumer-side responsibility the package deliberately does not take.
Failure modes.
hasShopifyPermission() throws (upstream latency, Shopify API outage) and the page 500s instead of degrading. Define fail-closed explicitly.Ramp-up. Low for a Laravel developer: one trait, one method, one set of strings. Half a day to wire and verify for someone already familiar with the app. The real effort is not code — it is the RBAC data design (who should see draft orders, discounts, metafields) and the audit of current visibility, which is a product and operations task rather than an engineering one. Budget that separately, and do not let the small diff size set expectations for the change management effort.
TPM recommendation. Adopt. This is the release that makes the package's authorization model usable without a bespoke wrapper, and the deletion of consumer-side workarounds is a genuine reduction in owned risk. Condition the definition of done on two things: an explicit verification that the fail-open legacy path does not apply to any real user in your install, and a consumer-side test that asserts a denied user cannot reach DiscountResource. Pin the version, and treat the permission prefix strings as a public contract in your own codebase.
How can I help you explore Laravel packages today?