223 lines
9.0 KiB
Markdown
223 lines
9.0 KiB
Markdown
# 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](https://lunarphp.io) 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`](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`](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`](docs/product-search.md) and
|
|
[`docs/product-listing.md`](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`](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`](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:**
|
|
|
|
```php
|
|
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`](docs/notifications.md).
|
|
|
|
### Activity Logging
|
|
|
|
Thin wrapper around [Spatie Laravel Activity Log](https://github.com/spatie/laravel-activitylog).
|
|
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`](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:
|
|
|
|
```php
|
|
->plugin(\Modules\Core\CorePlugin::make())
|
|
```
|
|
|
|
See [`docs/lunar.md`](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.
|
|
|
|
```php
|
|
// 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`:
|
|
|
|
```json
|
|
{
|
|
"repositories": [
|
|
{
|
|
"type": "vcs",
|
|
"url": "https://code.radical-elements.com/boboko/core.git"
|
|
}
|
|
],
|
|
"require": {
|
|
"boboko/core": "^1.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
Then run:
|
|
|
|
```bash
|
|
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`](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`](docs/otp-auth.md) — OTP authentication flow
|
|
- [`docs/localization.md`](docs/localization.md) — Locale-prefixed routing and storefront translations
|
|
- [`docs/product-search.md`](docs/product-search.md) — Full-text product search
|
|
- [`docs/product-listing.md`](docs/product-listing.md) — Product listing/filtering/detail catalog service
|
|
- [`docs/privacy.md`](docs/privacy.md) — GDPR right of access/erasure, User-scope vs Customer-scope
|
|
- [`docs/shopify-import.md`](docs/shopify-import.md) — Shopify CSV → Lunar field mapping and import design
|
|
- [`docs/activity-log.md`](docs/activity-log.md) — Activity logging
|
|
- [`docs/notifications.md`](docs/notifications.md) — Notification registry
|
|
- [`docs/lunar.md`](docs/lunar.md) — Lunar framework reference and gotchas
|
|
- [`docs/modules.md`](docs/modules.md) — Module architecture, Customer/User pairing, provider registration pitfalls
|