Feature: Store Management
Relevant source files
The following files were used as context for generating this wiki page:- app/Filament/Resources/StoreResource.php
- app/Models/Store.php
- tests/Feature/Api/StoreApiTest.php
- app/Filament/Resources/StoreResource/Api/Handlers/CreateHandler.php
- app/Filament/Resources/StoreResource/Pages/TestStore.php
- tests/Feature/Filament/StoreTest.php
- tests/Feature/Models/StoreTest.php
- app/Models/Product.php
- app/Models/Url.php
- app/Filament/Resources/StoreResource/Api/Requests/UpdateStoreRequest.php
The Store Management feature is a core component of PriceBuddy, enabling the system to identify and extract product information from various online retailers. A "Store" entity defines a retailer by its domains and contains the specific logic (scraping strategies) required to parse product pages for data such as title, price, and image.
Stores are configured through the Filament admin panel, which provides a user interface for creating, editing, and testing store configurations. While the admin panel presents stores as a shared resource among all users, the REST API provides user-scoped endpoints for programmatic management. This allows for both centralized administration and individual user integrations.
Data Model (Store.php)
The Store model is the central Eloquent model for this feature. It stores all configuration related to a specific retailer.
Sources: app/Models/Store.php
Database Schema and Relationships
The stores table holds the configuration for each retailer. It has relationships with users, urls, and through urls, to products.
The following diagram illustrates the Entity-Relationship model for the Store and its related entities.
Table Attributes
The stores table contains the following main fields:
| Field | Type | Description - |
| name | string | The display name of the store. - |
| slug | string | A URL-friendly version of the name, automatically generated. - |
| initials | string | A 2-character representation of the store name, automatically generated if not provided. - |
| domains | json | An array of domain objects (e.g., [{ "domain": "example.com" }]) associated with the store. - |
| scrape_strategy | json | A JSON object defining how to extract title, price, and image from a product page. Each key contains a type (e.g., 'selector') and a value (e.g., 'h1'). - |
| settings | json | A JSON object for various settings, including scraper_service, scraper_service_settings, and locale_settings. - |
| notes | text | Optional notes about the store, supports rich text. - |
| user_id | int | Foreign key linking to the users table. - |
Sources: app/Models/Store.php:38-48, app/Filament/Resources/StoreResource.php:46-120
Computed Attributes
The Store model uses several accessors to provide convenient, computed properties.
| Attribute | Return Type | Description - |
| initials | string | Generates a two-letter initial from the store name (e.g., "Example Store" -> "ES") if not explicitly set. - |
| domains_html | HtmlString | Returns a comma-separated string of all associated domains. - |
| scraper_service | string | Gets the scraper service type (http or api) from the settings array, defaulting to http. - |
| scraper_options | array | Parses the scraper_service_settings string into a key-value array for the scraper API. - |
| locale | string | Gets the locale for the store from settings, with a fallback to the application's default locale. - |
- |
|currency|string| Gets the currency ISO code for the store fromsettings, with a fallback to the application's default currency. - |
Sources: app/Models/Store.php:121-200, tests/Feature/Models/StoreTest.php
Model Events
When a Store is deleted, a deleted event listener performs cleanup:
- It deletes all associated
Urlrecords. - It triggers an update of the
price_cachefor each associatedProductto ensure their price data is refreshed.
Sources: app/Models/Store.php:50-55
Filament Admin Resource
The StoreResource class defines the administrative interface for managing stores within the Filament admin panel. It provides forms for creation/editing, a table for listing, and pages for specific actions like testing.
Sources: app/Filament/Resources/StoreResource.php
Store Form
The form for creating and editing a store is divided into several sections:
| Section | Fields & Description - |
| Basics | name: The store's name. - |
| Domains | domains: A repeater field to list all domains associated with the store. - |
| Scrape Strategy | title, price, image: Each is a group of fields (type, value, prepend, append) to define how to extract a piece of product data. The type can be selector, regex, etc. - |
| Scraper Service | settings.scraper_service: A radio button to choose between Http (fast, for static HTML/JSON) and Api (slower, uses Selenium for JavaScript-rendered pages). settings.scraper_service_settings: A textarea for advanced options when using the Api service. |
| Locale | settings.locale_settings.locale, settings.locale_settings.currency: Fields to override the default locale and currency for this specific store, affecting price parsing and display. - |
| Notes | notes: A rich text editor for any additional information about the store. - |
Sources: app/Filament/Resources/StoreResource.php:44-120, tests/Feature/Filament/StoreTest.php:36-50
Store Listing Table
The StoreResource index page displays a table of all stores. The table shows:
- Name: The store's name and a description with its domains.
- Products Count: The number of products associated with the store.
- Scraper: The
scraper_serviceused (HTTPorAPI), displayed as a colored badge.
The list can be searched by name and filtered by the scraper service.
Sources: app/Filament/Resources/StoreResource.php:130-160
Store Testing Page
A key feature is the "Test Store" page, which allows a user to validate the store's scraping configuration against a specific product URL.
This diagram shows the flow of testing a URL scrape.
REST API
The application exposes a REST API for managing stores, which is user-aware, meaning users can only interact with stores they have created.
Sources: tests/Feature/Api/StoreApiTest.php, app/Filament/Resources/StoreResource/Api/Handlers/CreateHandler.php, app/Filament/Resources/StoreResource/Api/Handlers/UpdateHandler.php
API Endpoints
| Method | Endpoint | Description - |
|---|---|---|
GET | /api/stores | Lists all stores belonging to the authenticated user. Supports pagination, sorting (name), and filtering (domains, scraper_service). - |
GET | /api/stores/{id} | Retrieves a single store by its ID, if it belongs to the authenticated user. Can include related data like user, urls, and products. - |
POST | /api/stores | Creates a new store for the authenticated user. Requires name and domains. - |
PUT | /api/stores/{id} | Updates an existing store by its ID. All fields are optional. The user must own the store. - |
DELETE | /api/stores/{id} | Deletes a store by its ID. The user must own the store. - |
Sources: tests/Feature/Api/StoreApiTest.php, app/Filament/Resources/StoreResource/Api/Handlers/CreateHandler.php:14, app/Filament/Resources/StoreResource/Api/Handlers/UpdateHandler.php:12
Create Store API Flow
This sequence diagram illustrates the process of creating a new store via the POST /api/stores endpoint.
Request Validation
When creating or updating a store via the API, the request data is validated. For example, the UpdateStoreRequest defines the following rules:
| Field | Rules - |
| name | sometimes|string|max:255 - |
| slug | sometimes|string|max:255|unique:stores,slug,{id} - |
| domains.*.domain | required_with:domains|string - |
| settings.scraper_service | sometimes|in:http,api - |
| scrape_strategy.image.value | required_with:scrape_strategy.image.type|string