This commit introduces the data retention and data export Admin Services, accessed by the Boboko admin UI
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 aUser(individual login) — aCustomererasure never touches any linkedUser's login, and aUsererasure never touches aCustomeraccount's own data. Seedocs/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
Useron aCustomeralso opens a (grace period) erasure request for that now-orphanedCustomer, 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.
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]);
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 resourceCustomerResourceExtension— 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
docs/otp-auth.md— OTP authentication flowdocs/localization.md— Locale-prefixed routing and storefront translationsdocs/product-search.md— Full-text product searchdocs/product-listing.md— Product listing/filtering/detail catalog servicedocs/privacy.md— GDPR right of access/erasure, User-scope vs Customer-scopedocs/shopify-import.md— Shopify CSV → Lunar field mapping and import designdocs/activity-log.md— Activity loggingdocs/notifications.md— Notification registrydocs/lunar.md— Lunar framework reference and gotchasdocs/modules.md— Module architecture, Customer/User pairing, provider registration pitfalls