Files

223 lines
9.0 KiB
Markdown
Raw Permalink Normal View History

2026-07-01 18:35:39 +03:00
# 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.
2026-07-01 18:35:39 +03:00
---
## 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.
2026-07-01 18:35:39 +03:00
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).
2026-07-01 18:35:39 +03:00
### 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.
2026-07-01 18:35:39 +03:00
**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).
2026-07-01 18:35:39 +03:00
### 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.
2026-07-01 18:35:39 +03:00
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
2026-07-01 18:35:39 +03:00
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.
2026-07-01 18:35:39 +03:00
### 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) |
2026-07-01 18:35:39 +03:00
### Functional Types
Result and Option types for explicit error handling without exceptions.
2026-07-01 18:35:39 +03:00
```php
// Result<T, E>
$result = Success::create($value);
$result = Error::create('something went wrong');
2026-07-01 18:35:39 +03:00
$result->map(fn($v) => ...)->flatMap(fn($v) => ...);
// Option<T>
$option = Some::create($value);
$option = None::create();
$option->map(fn($v) => ...);
2026-07-01 18:35:39 +03:00
```
---
## 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
2026-07-02 19:38:05 +03:00
composer require boboko/core
php artisan vendor:publish --tag=core-config
2026-07-01 18:35:39 +03:00
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".
2026-07-01 18:35:39 +03:00
---
## Requirements
- PHP 8.5+
- Laravel 12+
- Lunar 1.3 (`lunarphp/lunar`)
- Meilisearch (for product search/listing/catalog)
2026-07-01 18:35:39 +03:00
- 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
2026-07-01 18:35:39 +03:00
- [`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