jez500/pricebuddy/stores
Claude Code and agent skill by jez500/pricebuddy
- community
Checking that the SKILL.md file is still in the repository.
This skill should be used when the user asks to "create a store", "edit a store", "debug a store", "import a store", "export a store", "test a store", "fix store domain matching", discusses store configuration, store settings, store scrape strategies, auto store creation, store seeding, or troubleshoots store-related issues.
Install
npx vskill@latest install jez500/pricebuddy/storesSKILL.md
Stores
Overview
A Store represents a retailer domain (e.g., Amazon, eBay) and holds all configuration for how to scrape product data from that retailer's pages. Stores are the central configuration entity — every URL belongs to a store, and the store's scrape strategy determines how data is extracted.
Database Schema
Table: stores
| Column | Type | Description | |
|---|---|---|---|
id | int | Primary key | |
name | string | Display name (e.g., "Amazon US") | |
slug | string | Auto-generated from name via Spatie HasSlug | |
initials | string, nullable | 2-char code, auto-generated from name if empty | |
domains | json | Array of {"domain": "example.com"} objects | |
scrape_strategy | json | Extraction rules per field (title, price, image, availability) | |
settings | json | Scraper service, locale, currency, test URL, API options | |
notes | text, nullable | Rich text notes | |
cookies | text, nullable | HTTP cookies string (cookie1=value; cookie2=value) | |
user_id | foreign, nullable | Owner user | |
timestamps | created_at, updated_at |
Model: App\Models\Store
Relationships
user()— BelongsToUserurls()— HasManyUrlproducts()— HasManyThroughProduct(viaUrl)
Key Accessors
initials— Auto-generates 2-letter code from name ("Example Store" -> "ES", "Amazon" -> "AM")domains_html— Comma-separated domains as HtmlStringscraper_service— Fromsettings.scraper_service, defaults tohttpscraper_options— Parsessettings.scraper_service_settingsnewline-separatedkey=valuepairs into arraytest_url— Fromsettings.test_urllocale— Fromsettings.locale_settings.locale, falls back toCurrencyHelper::getLocale()currency— Fromsettings.locale_settings.currency, falls back toCurrencyHelper::getCurrency()
Domain Matching
The scopeDomainFilter(Builder $query, string|array $domains) scope filters stores by domain using whereJsonContains against the domains JSON column. It accepts a single domain string or array.
hasDomain($domain) is an instance method that checks if a store contains a specific domain.
Important: ScrapeUrl::getStore() resolves a store by extracting the URL host via Uri::of($url)->host() and querying with domainFilter($host)->oldest()->first(). The oldest() ensures deterministic results when multiple stores share a domain.
Deletion Cascade
When a store is deleted (via model booted event):
- All affected products are collected first
- URLs are deleted individually (triggers URL model events which cascade to prices)
- All affected product price caches are updated
Store JSON Structure
domains Column
Always register both www and non-www variants.
scrape_strategy Column
Each field (title, price, image, availability) has a strategy entry. See the url-scraping skill for complete strategy type documentation.
settings Column
scraper_service—http(curl, fast) orapi(browser-based, JS rendering)scraper_service_settings— Only used for API scraper. Newline-separatedkey=valueoptions passed to seleniumbasetest_url— Saved when testing a store via the Test pagelocale_settings— Used byCurrencyHelperfor price parsing and formatting
Auto Store Creation
AutoCreateStore (app/Services/AutoCreateStore.php) automatically creates a store when a URL is submitted for an unrecognized domain.
Flow
createStoreFromUrl($url)extracts the host and checks for an existing store viadomainFilter- If no store exists, it fetches the page HTML and runs
strategyParse() strategyParse()attempts extraction for title, price, and image in priority order:
- Schema.org JSON-LD (
@type: Product) — checked first, most reliable - CSS selectors from
config/price_buddy.phpauto_create_store_strategies - Regex patterns from the same config
- If title and price extraction succeed,
getStoreAttributes()builds the store data - The
CreateStoreActionaction creates the store with locale/currency defaults
Domain Handling During Auto-Creation
The store name is set to ucfirst($host) (e.g., "Example.com").
Auto-Detection Config
config/price_buddy.php defines the fallback selectors and regex patterns. Key price selectors include:
meta[property="product:price:amount"]|contentmeta[property="og:price:amount"]|content.a-price .a-offscreen(Amazon)[itemProp="price"]|content.price,.product-price,[class*="price"]
Filament Admin UI
Resource: StoreResource
Location: app/Filament/Resources/StoreResource.php
Pages
| Page | Class | Purpose | |
|---|---|---|---|
| List | StoreResource/Pages/ListStores.php | Store listing with product count, scraper badge | |
| Create | StoreResource/Pages/CreateStore.php | New store form with "Create & test" option | |
| Edit | StoreResource/Pages/EditStore.php | Edit form with Share, Test, Delete actions | |
| Test | StoreResource/Pages/TestStore.php | Test scrape with URL, shows results widget |
Form Sections
- Basics — Name (required)
- Domains — Repeater of domain entries
- Scrape Strategy — Per-field strategy inputs (title, price, image, availability) built via
HasScraperTrait::makeStrategyInput(). Each has type select, value input, prepend/append fields. Schema.org type hides value/prepend/append - Availability Match — Dynamic form groups for each non-InStock
StockStatuscase. Each has match type (exact/regex) and value. First match wins, with configurable default fallback - Scraper Service — HTTP vs API radio with API-only settings textarea
- Locale — Locale and currency selects
- Cookies — Cookie string input
- Notes — RichEditor
HasScraperTrait
app/Filament/Concerns/HasScraperTrait.php provides:
makeStrategyInput($key, $default, $required)— Creates the type/value/prepend/append field groupgetScraperSettings()— Creates the scraper service section
Actions
- ImportStoreAction — Modal with JSON textarea, validates with
ImportStorerule, creates viaCreateStoreAction. Keyboard shortcut:mod+i - ShareStoreAction — Modal displaying JSON export (name, slug, domains, scrape_strategy, settings) with copy-to-clipboard
- TestAfterEdit trait — Adds "Save & test" button that redirects to TestStore page after saving
Test Store Page
- Enter a product URL and click "Test url scrape"
ScrapeUrl::new($url)->scrape(['store' => $store, 'use_cache' => false])runs with cache bypass- Test URL is saved to
settings.test_url TestResultsWidgetdisplays scraped title, price, image, availability with stock status resolution details
Validation Rules
StoreUrl (app/Rules/StoreUrl.php)
Used when adding URLs to products. Validates that:
- The URL's domain belongs to an existing store, OR
- A store can be auto-created from the URL (
AutoCreateStore::canAutoCreateFromUrl()) - The scrape returns a valid title and price (unless product is unavailable)
ImportStore (app/Rules/ImportStore.php)
Validates JSON import structure requires:
name— Store namedomains— Array of domain objectsscrape_strategy.title— Title strategy with type and valuescrape_strategy.price— Price strategy with type and valuesettings.scraper_service— ValidScraperServiceenum value
Factory & Seeding
StoreFactory (database/factories/StoreFactory.php)
Defaults:
- Random name, domains
[['domain' => 'example.com']] - Selector strategies using
og:title,og:price:amount,og:imagemeta tags - HTTP scraper service
States:
forUrl(string $url)— Generates name and domains from a URL's hostname
StoreSeeder (database/seeders/StoreSeeder.php)
Loads country-specific store data from database/seeders/Stores/:
usa.php— Amazon US, eBay USaustralia.php— 15 stores including Amazon AU, JB Hi-Fi, Good Guys, BWS, etc.
Each seeder entry includes real-world scrape strategies for that retailer.
Testing
Test Files
| File | Coverage | |
|---|---|---|
tests/Feature/Filament/StoreTest.php | Admin CRUD (list, create, edit forms) | |
tests/Feature/Api/StoreApiTest.php | API endpoints (15 tests: CRUD, auth, filtering, sorting, relationships) | |
tests/Feature/Models/StoreTest.php | Model behavior (initials, domains, scraper options, deletion cascade) | |
tests/Unit/Rules/ImportStoreTest.php | Import JSON validation | |
tests/Unit/Services/AutoCreateStoreTest.php | Auto-detection from HTML (meta tags, selectors, regex, schema.org) |
Testing Patterns
Debugging Stores
Common Issues
Store not found for a URL — Check domain registration. The host extracted from the URL must exactly match a domain entry in the store's domains JSON. Test with ScrapeUrl::new($url)->getStore().
Auto-creation fails — AutoCreateStore requires both title and price extraction to succeed. Test with AutoCreateStore::new($url)->strategyParse() to see what was detected. If the page needs JavaScript, auto-creation uses HTTP by default and may fail.
Wrong store matched — getStore() uses oldest()->first(), so the earliest-created store with a matching domain wins. Check for duplicate domain entries across stores.
Scraper options not applied — The scraper_service_settings field must be newline-separated key=value format. The accessor scraper_options parses these. Invalid entries (missing =) are silently filtered out.
Locale/currency issues — If prices display incorrectly, check settings.locale_settings on the store. CurrencyHelper::toFloat() uses locale-aware parsing. A store with en_US locale parses 1,234.56 differently than de_DE which expects 1.234,56.
Tinker Debugging
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryChecking.ai/skills/stores/SKILL.md
Popularity
- Repository stars
- 941
- Repository forks
- 52
- 7-day trend score
- 34
Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 30 May 2026, 5 months ago.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/jez500/pricebuddy/stores)