Files
core/CHANGELOG.md
T
2026-07-12 05:38:14 +03:00

7.9 KiB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog.

[0.3.0] - 2026-07-12

Added

  • Meilisearch product search: pulled in lunarphp/search (Lunar's driver-agnostic search abstraction — database/meilisearch/typesense engines, selectable via Scout's own SCOUT_DRIVER config) and lunarphp/meilisearch, wiring Meilisearch in as the search engine for products.
    • Search\ProductIndexer overrides Lunar's own indexer to strip HTML tags from string fields (e.g. name_en, description_en) before they reach the search index — Lunar's default indexer sends raw attribute HTML straight through, which pollutes relevance ranking and highlighting with markup.
    • Meilisearch itself is treated as app-level infrastructure, not a boboko-core concern: the actual Meilisearch container, host port, and master key live in each consuming app's own docker-compose.yml/.env (e.g. 3dealer), the same way Postgres and Valkey do — boboko-core only declares the PHP package dependency and the indexing code.

[0.2.0] - 2026-07-10

Added

  • Product reviews (Modules\Core\Review): a new ProductReview model + product_reviews table (plain, unprefixed — same convention as import_mappings), linked to Lunar's Product via a Product::reviews() macro (registered in CorePlugin, since Lunar\Models\Product is a vendor model and can't be edited directly).
    • JudgeMe CSV review importer (MigrateImport\JudgeMe\JudgeMeExportImporter), wired into the existing boboko:migrate:import --source=judgeme --type=export command: reads a Judge.me review export, resolves each row's product_handle to a Lunar product via Lunar\Models\Url, and creates/updates ProductReview rows idempotently via import_mappings (source=judgeme, source_type=review, keyed on Judge.me's metaobject_handle). Rows with no matching product are skipped with a logged warning rather than failing the whole import.
    • Review images (picture_urls in the CSV) are downloaded and stored as real media via Spatie MediaLibrary (ProductReview::IMAGES_COLLECTION), not just linked by URL — consistent with how product images are handled.
    • Admin UI: a new "Reviews" sub-navigation page on the product edit screen (Review\Pages\ManageProductReviews, wired via Review\Extensions\ProductResourceExtension), listing rating/title/reviewer with View, Reply, and Delete actions. The Reply action lets staff write/edit a reply directly from the table, setting replied_at. The View modal shows full review detail (body, reviewer email, location, source, dates, reply, downloaded images).

Fixed

  • Shopify\ShopifyExportImporter never wrote a Lunar Url (slug) row for imported products, despite docs/shopify-import.md specifying it should — meaning no code outside the importer itself could resolve "which Lunar product has handle X" (only the importer's own private import_mappings bookkeeping could). It now creates/updates a default Url row (slug = Shopify handle) per product on every import, which the new JudgeMe review importer depends on for product resolution.

[0.1.0] - 2026-07-09

Added

  • Shipping: registered Lunar's lunarphp/table-rate-shipping plugin (ShippingPlugin) directly on CorePlugin, so table-rate shipping is available to every consumer app without per-app wiring.
  • Product migration/import framework (Modules\Core\MigrateImport): a source-agnostic pipeline for importing a vendor's product catalog into Lunar.
    • boboko:migrate:import Artisan command — interactively prompts for source, type (export/API), and credentials or file path, then dispatches the import as a queued job (RunMigrateImportJob) on the default queue. The file-path prompt resolves relative to storage/app/private/imports/, so answering e.g. shopify picks up the first CSV found in imports/shopify/ automatically.
    • ImportSpec, Importer interface, and ImporterFactory (source+type → importer class) as the extension points for future sources (WooCommerce, etc.) and mechanisms (API vs. file export).
    • import_mappings table + ImportMapping model: a polymorphic (source, source_type, external_id) → model mapping used by every resolver to make imports idempotent and safely re-runnable.
    • DefaultLocale helper wrapping Lunar's Language::getDefault()->code, used anywhere a translatable field needs a locale key, instead of assuming app()->getLocale() matches Lunar's configured default.
    • Shopify CSV export importer (Shopify\ShopifyExportImporter), the first working source/type combination, verified end-to-end against a real 183-product/693-variant/332-image Shopify export (row counts in the CSV match 1:1 with imported Products/Variants/Media):
      • ShopifyCsvReader + ProductGroup group Shopify's flat, repeated-handle CSV rows into one row-group per product (product row, variant rows, image rows).
      • Ten resolvers under Shopify\Resolvers, each responsible for idempotently resolving-or-creating one Lunar entity: TaxClassResolver, ProductTypeResolver (auto-attaches system attributes to new types), BrandResolver, TagResolver, CollectionResolver (multi-level, multi-collection support via >-delimited breadcrumbs), ProductOptionResolver (dedupes options/values by slugified name so case variants like "Size"/"size" resolve to one row), AssetResolver (Spatie MediaLibrary via Product::addMedia(), matches local export images by UUID first, filename fallback), PriceResolver (minor-unit conversion per currency), ImportAttributeResolver and ProductAttributeResolver (custom cost_per_item/seo_title/seo_description attributes, field-type-aware attribute_data writing).
    • docs/shopify-import.md — full CSV-to-Lunar field mapping reference and import design notes.
    • docs/lunar.md — new "Gotchas" section documenting non-obvious Lunar behavior hit while building the importer (table-prefix/nested-set race, required ProductOption.handle, per-group Attribute.position, etc.).
    • CONTRIBUTE.md — local dev setup (path-repo + bin/dc-core.sh), and the manual DB-verification workflow used to build this feature.

Fixed

  • ProductOptionResolver created duplicate ProductOption/ProductOptionValue rows when the same option or value appeared with different casing across products (e.g. Shopify export rows using both "Size" and "size"), and could create a duplicate value within a single product's own variant rows due to relying on a stale lazy-loaded relation. Both now resolve by normalized (slugified) identity queried fresh from the database.
  • boboko:migrate:import could dispatch an import job with a blank file path (silent no-op failure) if the file-path prompt was answered empty; it now re-prompts until a valid, existing file is given.

[0.0.1] - 2026-07-03

First release.

Added

  • OTP-based authentication built around User instead of Customer (UserOtpService, UserOtpMail), replacing the earlier customer-scoped OTP flow.
  • UserCreated event with a CreateCustomerForUser listener to provision a Lunar customer automatically when a user is created.
  • UserRelationManager for managing users from the customer resource in the panel.
  • Stoic image UI component (resources/views/ui/stoic-image.blade.php) and its YAML-driven config/service (see Stoic::class).
  • config/core.php for module-level configuration.
  • AuthServiceProvider and CustomerServiceProvider now register alongside CoreServiceProvider.
  • Migrations: add OTP to users, drop OTP from Lunar customers, drop password from users, make name nullable on users and Lunar customers.
  • docs/modules.md documenting module structure.

Removed

  • CustomerOtpMail and CustomerOtpService, superseded by the user-based OTP flow.

Dependencies

  • Added explicit symfony/yaml requirement (used directly by Stoic::loadConfig()).