# 3dealer Storefront for 3dealer.gr: Laravel 12 + Lunar PHP (headless), on top of `boboko/core`. Front-end conventions are in [CLAUDE.md](CLAUDE.md). ## Scheduled jobs These run in the `scheduler` container (`php artisan schedule:work`). | Command | When | What it does | |---|---|---| | `custom-fields:prune-uploads` | Daily, 04:00 | Deletes custom-field photo uploads older than 24 h that no cart line or order line references. | | `lunar:search:index` | Daily, 03:00 | Full product reindex. Registered by `boboko/core`. | ## Product custom fields Admins can add custom fields to a product in the Lunar admin (the product's **Custom Fields** section, from `boboko/core`). The customer fills them in on the product page before adding the product to the cart. The answers are stored on the cart line (`meta.custom_fields`) and carried over to the order line. | Field type | Storefront input | Limit | |---|---|---| | Short text | text input | 255 characters | | Long text | textarea | 2,000 characters | | File upload | photo upload | JPG, PNG, WEBP, HEIC/HEIF, up to 10 MB | - **Photos upload as soon as they're picked.** They go to `POST /{locale}/custom-field-uploads`, which is limited to 20 per minute per client. They're stored on the private `local` disk under `storage/app/private/custom-field-uploads/`. Only an encrypted reference is sent with add-to-cart. The allowed types and size are set in `App\Http\Controllers\CustomFieldUploadController`. - **Photos are never public.** The cart drawer, checkout summary and order confirmation link to a photo through a signed URL that expires after 2 hours. - **Emails show text answers only**, never photos. - **Photos are cleaned up automatically.** Photos never added to a cart are deleted by `custom-fields:prune-uploads` (see above). A photo on a cart line is kept as long as that cart line exists, and a photo on an order is kept indefinitely. - **Products with custom fields can't be quick-added.** On product cards, the "add to cart" button becomes a link to the product page. - Field labels are entered once in the admin and aren't translated, so they appear as entered in both `/el` and `/en`.