Files
core/README.md

9.0 KiB

Core Module

A Laravel module providing authentication, localization, product search/catalog, privacy/GDPR tooling, notifications, activity logging, CLI tooling, and functional types on top of the Lunar e-commerce package. Designed to be consumed as a standalone Composer package by any Lunar-based e-shop.


What's Inside

OTP Authentication

Passwordless login for both staff (Lunar panel) and customers via 6-digit codes delivered by email. Codes expire after 10 minutes, rate-limited to 5 attempts. The Lunar panel login page is a two-step flow (email → OTP) with a back button to return from the code step to the email step.

See docs/otp-auth.md.

Localization

Locale-prefixed routing (Modules\Core\Localization\LocaleMiddleware) — a locale route middleware, opt-in per shop, that resolves and redirects to the correct language segment (/el/..., /en/...) based on Lunar's own language list, with caching and rename-safe translation migration. Also brings in storefront UI label translations (spatie/laravel-translation-loader) with an admin-editable LanguageLine resource.

See docs/localization.md.

Product Search & Catalog

Two complementary services on top of Meilisearch:

  • Modules\Core\Search\ProductSearchService — locale-aware full-text product search.
  • Modules\Core\Catalog\ProductService — listing/filtering (by collection, brand, price range) and single-product lookup by id or slug, reading directly from the Meilisearch index rather than the database.

Both are backed by Modules\Core\Search\ProductIndexer, which extends Lunar's own indexer with collections, price, variants, media, tags, and reviews — everything needed for both a listing page and a full product detail page from one index.

See docs/product-search.md and docs/product-listing.md.

Product Reviews

Modules\Core\Review\ProductReview — ratings/reviews with staff replies, a Filament sub-navigation page on the product edit screen, and automatic re-indexing (via ReviewServiceProvider) whenever a review is created, updated, or deleted, so a product's Meilisearch document never goes stale.

Privacy / GDPR Data-Subject Requests

Right of access (export) and right of erasure, built as an extensible contract (Modules\Core\Privacy\Contracts\PersonalDataProvider) rather than a fixed table list — any module can register its own data without core knowing it exists.

  • Two independent scopes: erasing/exporting a Lunar Customer (business account) is never the same operation as erasing/exporting a User (individual login) — a Customer erasure never touches any linked User's login, and a User erasure never touches a Customer account's own data. See docs/privacy.md "User-scope vs Customer-scope".
  • Cancellable grace period (default 30 days, configurable) before anything is actually erased — logging back in during the window automatically reverts the request, mirroring Shopify's own account-deletion flow. Immediate erasure exists but is staff-only by type, never reachable from a self-service flow.
  • Sole-owner cascade: erasing the last remaining User on a Customer also opens a (grace period) erasure request for that now-orphaned Customer, so its PII doesn't sit unreachable forever — traced back to the triggering request so login-reactivation can revert exactly that cascade.
  • Queued export: gathering data and writing a CSV-per-provider zip (via the generic, reusable Modules\Core\Export\CsvWriter) runs as a background job; a consuming app hooks its own notification onto the completion event via the Notification Registry (below).

See docs/privacy.md.

Shopify Migration

Modules\Core\MigrateImport\Shopify\ShopifyExportImporter — imports a Shopify CSV product export (products, variants, images, collections, tags, prices) into Lunar, idempotently re-runnable via an import_mappings table. Part of a source-agnostic import framework (boboko:migrate:import) designed to support additional sources later.

See docs/shopify-import.md.

Notification Registry

An event-driven notification system. Each notification class declares which event it listens to and who to notify — the registry wires up the listener automatically. All notifications extend BaseNotification, which implements ShouldQueue, so delivery is async. Supports optional delays.

Creating a notification:

class MyNotification extends BaseNotification
{
    public function __construct(private readonly MyEvent $event) {}

    public static function getKey(): string { return 'my.notification.key'; }
    public static function listensTo(): string { return MyEvent::class; }
    public function via(object $notifiable): array { return ['mail']; }
    public function notifiable(): AnonymousNotifiable { ... }
}

// Register in a service provider:
NotificationRegistry::get()->register([MyNotification::class]);

See docs/notifications.md.

Activity Logging

Thin wrapper around Spatie Laravel Activity Log. Four standardized methods: created(), updated(), failed(), deleted(). Logs to the lunar channel and auto-resolves the actor from the staff session.

See docs/activity-log.md.

Lunar Panel Integration

  • Custom OTP login page replacing the default Lunar panel login
  • StaffResourceExtension — removes password field from Lunar's staff resource
  • CustomerResourceExtension — replaces default address relation manager with a custom implementation
  • Table-rate shipping (ShippingPlugin) registered by default
  • CorePlugin — configures panel path, branding, logos, navigation items, and activity log field exclusions for staff

Register the plugin in your Lunar panel provider:

->plugin(\Modules\Core\CorePlugin::make())

See docs/lunar.md for the full Lunar reference and non-obvious gotchas hit while building against it.

CLI Commands

Command Description
boboko:anonymize Dummy-scrub personal data in users/lunar_customers for local dev safety (local environment only — not the GDPR erasure tool; see Privacy above for that)
boboko:export Dump database + storage files to a timestamped zip
boboko:import Restore from a boboko:export zip archive
boboko:export:cleanup Delete old export zips, keep N most recent
boboko:migrate:import Import a vendor product catalog (Shopify, etc.) into Lunar
boboko:privacy:process-erasure-requests Dispatch an erasure job for every due GDPR erasure request (wire into your own scheduler)
lunar:create-admin Create a Lunar admin user (overrides Lunar's own command)
lunar:install Seed default Lunar store data — countries, channel, currency, tax zone, attributes, product type (overrides Lunar's own command)

Functional Types

Result and Option types for explicit error handling without exceptions.

// Result<T, E>
$result = Success::create($value);
$result = Error::create('something went wrong');
$result->map(fn($v) => ...)->flatMap(fn($v) => ...);

// Option<T>
$option = Some::create($value);
$option = None::create();
$option->map(fn($v) => ...);

Installation

Add the repository to your project's composer.json:

{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://code.radical-elements.com/boboko/core.git"
        }
    ],
    "require": {
        "boboko/core": "^1.0"
    }
}

Then run:

composer require boboko/core
php artisan vendor:publish --tag=core-config
php artisan vendor:publish --tag=core-assets
php artisan migrate

For local core development alongside a consuming app (path-repo symlink + Docker mount), see docs/modules.md "Docker Compose: the local-core mount".


Requirements

  • PHP 8.5+
  • Laravel 12+
  • Lunar 1.3 (lunarphp/lunar)
  • Meilisearch (for product search/listing/catalog)
  • Spatie Laravel Activity Log

Documentation