- Add backend stale process monitoring API (/api/stale-processes) - Add users management route - Add frontend landing page and stale process monitor UI on /scraper-tools - Move old development scripts to backend/archive/ - Update frontend build with new features 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
477 lines
11 KiB
Markdown
477 lines
11 KiB
Markdown
# Dutchie Analytics API - Usage Guide
|
|
|
|
## Base URL
|
|
```
|
|
http://localhost:3010/api
|
|
```
|
|
|
|
## Authentication
|
|
All endpoints require JWT authentication via Bearer token:
|
|
```
|
|
Authorization: Bearer YOUR_JWT_TOKEN
|
|
```
|
|
|
|
## Products API
|
|
|
|
### Get Products with Filtering, Sorting & Field Selection
|
|
|
|
**Endpoint:** `GET /products`
|
|
|
|
#### Basic Usage
|
|
```bash
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&limit=10"
|
|
```
|
|
|
|
#### Field Selection (Reduce Payload Size)
|
|
Only return specific fields to reduce bandwidth and improve performance:
|
|
|
|
```bash
|
|
# Only get essential fields
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&fields=id,name,price,brand,in_stock"
|
|
|
|
# Get fields needed for product cards
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&fields=id,name,price,brand,thc_percentage,image_url_full,in_stock"
|
|
```
|
|
|
|
#### Advanced Filtering
|
|
|
|
**Filter by Category:**
|
|
```bash
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&category_id=5"
|
|
```
|
|
|
|
**Filter by Stock Status:**
|
|
```bash
|
|
# Only in-stock products
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&in_stock=true"
|
|
```
|
|
|
|
**Search Products:**
|
|
```bash
|
|
# Search in name, brand, and description
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?search=blue+dream"
|
|
```
|
|
|
|
**Filter by Brand:**
|
|
```bash
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&brand=Cresco"
|
|
```
|
|
|
|
**Filter by Price Range:**
|
|
```bash
|
|
# Products between $20 and $50
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&min_price=20&max_price=50"
|
|
```
|
|
|
|
**Filter by THC Percentage:**
|
|
```bash
|
|
# High THC products (>20%)
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&min_thc=20"
|
|
```
|
|
|
|
**Filter by Strain Type:**
|
|
```bash
|
|
# Get only indica strains
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&strain_type=indica"
|
|
```
|
|
|
|
#### Sorting
|
|
|
|
**Sort by Price:**
|
|
```bash
|
|
# Lowest price first
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&sort_by=price&sort_order=asc"
|
|
|
|
# Highest price first
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&sort_by=price&sort_order=desc"
|
|
```
|
|
|
|
**Sort by THC:**
|
|
```bash
|
|
# Highest THC first
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&sort_by=thc_percentage&sort_order=desc"
|
|
```
|
|
|
|
**Sort by Name:**
|
|
```bash
|
|
# Alphabetical
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&sort_by=name&sort_order=asc"
|
|
```
|
|
|
|
**Available Sort Fields:**
|
|
- `id`
|
|
- `name`
|
|
- `brand`
|
|
- `price`
|
|
- `thc_percentage`
|
|
- `cbd_percentage`
|
|
- `last_seen_at`
|
|
- `created_at`
|
|
|
|
#### Pagination
|
|
|
|
```bash
|
|
# Get first page (50 items)
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&limit=50&offset=0"
|
|
|
|
# Get second page
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?store_id=1&limit=50&offset=50"
|
|
```
|
|
|
|
#### Complex Query Example
|
|
|
|
Get affordable indica products sorted by THC:
|
|
```bash
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products?\
|
|
store_id=1&\
|
|
strain_type=indica&\
|
|
max_price=40&\
|
|
min_thc=15&\
|
|
in_stock=true&\
|
|
sort_by=thc_percentage&\
|
|
sort_order=desc&\
|
|
limit=20&\
|
|
fields=id,name,brand,price,thc_percentage,strain_type,image_url_full"
|
|
```
|
|
|
|
#### Response Format
|
|
|
|
```json
|
|
{
|
|
"products": [
|
|
{
|
|
"id": 123,
|
|
"name": "Blue Dream 3.5g",
|
|
"brand": "Cresco Labs",
|
|
"price": 45.00,
|
|
"thc_percentage": 24.5,
|
|
"cbd_percentage": 0.5,
|
|
"strain_type": "hybrid",
|
|
"in_stock": true,
|
|
"image_url_full": "http://localhost:9020/dutchie/products/123/full.jpg",
|
|
"thumbnail_url": "http://localhost:9020/dutchie/products/123/thumb.jpg",
|
|
"medium_url": "http://localhost:9020/dutchie/products/123/medium.jpg",
|
|
"store_name": "Curaleaf - Phoenix",
|
|
"category_name": "Flower"
|
|
}
|
|
],
|
|
"total": 145,
|
|
"limit": 50,
|
|
"offset": 0,
|
|
"filters": {
|
|
"store_id": "1",
|
|
"category_id": null,
|
|
"in_stock": "true",
|
|
"search": null,
|
|
"brand": null,
|
|
"min_price": null,
|
|
"max_price": null,
|
|
"min_thc": null,
|
|
"max_thc": null,
|
|
"strain_type": null,
|
|
"sort_by": "last_seen_at",
|
|
"sort_order": "DESC"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Get Single Product
|
|
|
|
**Endpoint:** `GET /products/:id`
|
|
|
|
```bash
|
|
# Full product data
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products/123"
|
|
|
|
# With field selection
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products/123?fields=id,name,price,description,image_url_full"
|
|
```
|
|
|
|
### Get Available Brands (Meta Endpoint)
|
|
|
|
**Endpoint:** `GET /products/meta/brands`
|
|
|
|
Get list of all brands for filter dropdowns:
|
|
|
|
```bash
|
|
# All brands
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products/meta/brands"
|
|
|
|
# Brands for specific store
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products/meta/brands?store_id=1"
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"brands": [
|
|
"Cresco Labs",
|
|
"Select",
|
|
"Timeless",
|
|
"Canamo",
|
|
"Item 9"
|
|
]
|
|
}
|
|
```
|
|
|
|
### Get Price Range (Meta Endpoint)
|
|
|
|
**Endpoint:** `GET /products/meta/price-range`
|
|
|
|
Get min/max/avg prices for filter sliders:
|
|
|
|
```bash
|
|
# All products
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products/meta/price-range"
|
|
|
|
# For specific store
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/products/meta/price-range?store_id=1"
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"min_price": 15.00,
|
|
"max_price": 120.00,
|
|
"avg_price": 42.50
|
|
}
|
|
```
|
|
|
|
## Stores API
|
|
|
|
### Get All Stores
|
|
```bash
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/stores"
|
|
```
|
|
|
|
### Get Single Store
|
|
```bash
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/stores/1"
|
|
```
|
|
|
|
### Get Store Brands
|
|
```bash
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/stores/1/brands"
|
|
```
|
|
|
|
### Get Store Specials
|
|
```bash
|
|
# Today's specials
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/stores/1/specials"
|
|
|
|
# Specials for specific date
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/stores/1/specials?date=2025-01-15"
|
|
```
|
|
|
|
### Trigger Store Scrape (Admin)
|
|
```bash
|
|
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"parallel": 3}' \
|
|
"http://localhost:3010/api/stores/1/scrape"
|
|
```
|
|
|
|
## Categories API
|
|
|
|
### Get Categories (Flat List)
|
|
```bash
|
|
# All categories
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/categories"
|
|
|
|
# For specific store
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/categories?store_id=1"
|
|
```
|
|
|
|
### Get Category Tree (Hierarchical)
|
|
```bash
|
|
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
|
"http://localhost:3010/api/categories/tree?store_id=1"
|
|
```
|
|
|
|
## Real-World Usage Examples
|
|
|
|
### Build a Product Filter UI
|
|
|
|
1. **Get filter options:**
|
|
```javascript
|
|
// Get brands for dropdown
|
|
const brands = await fetch('/api/products/meta/brands?store_id=1');
|
|
|
|
// Get price range for slider
|
|
const priceRange = await fetch('/api/products/meta/price-range?store_id=1');
|
|
|
|
// Get categories for checkboxes
|
|
const categories = await fetch('/api/categories?store_id=1');
|
|
```
|
|
|
|
2. **Fetch filtered products:**
|
|
```javascript
|
|
const params = new URLSearchParams({
|
|
store_id: '1',
|
|
brand: selectedBrand,
|
|
min_price: minPrice,
|
|
max_price: maxPrice,
|
|
category_id: selectedCategory,
|
|
in_stock: 'true',
|
|
sort_by: 'price',
|
|
sort_order: 'asc',
|
|
fields: 'id,name,price,brand,thc_percentage,image_url_full,in_stock'
|
|
});
|
|
|
|
const products = await fetch(`/api/products?${params}`);
|
|
```
|
|
|
|
### Build a WordPress Product Grid
|
|
|
|
```php
|
|
// Efficient field selection for grid display
|
|
$fields = 'id,name,price,brand,thc_percentage,image_url_full,in_stock';
|
|
|
|
$response = wp_remote_get(
|
|
"http://localhost:3010/api/products?store_id=1&in_stock=true&limit=12&fields=$fields",
|
|
['headers' => ['Authorization' => 'Bearer ' . $token]]
|
|
);
|
|
|
|
$data = json_decode(wp_remote_retrieve_body($response));
|
|
foreach ($data->products as $product) {
|
|
// Only contains requested fields = smaller payload
|
|
echo render_product_card($product);
|
|
}
|
|
```
|
|
|
|
### Build Price Comparison Tool
|
|
|
|
```javascript
|
|
// Get cheapest products across all stores
|
|
const cheapProducts = await fetch(
|
|
'/api/products?in_stock=true&sort_by=price&sort_order=asc&limit=50&fields=id,name,price,store_name'
|
|
);
|
|
|
|
// Get highest THC products
|
|
const strongProducts = await fetch(
|
|
'/api/products?in_stock=true&min_thc=25&sort_by=thc_percentage&sort_order=desc&limit=50'
|
|
);
|
|
```
|
|
|
|
## Performance Tips
|
|
|
|
1. **Use Field Selection:** Only request fields you need to reduce bandwidth
|
|
2. **Pagination:** Use reasonable `limit` values (50-100)
|
|
3. **Caching:** Cache brand lists, price ranges, and category data
|
|
4. **Combine Filters:** Use multiple filters to reduce result set size
|
|
5. **Index Optimization:** The API uses indexed fields for filtering
|
|
|
|
## Rate Limits
|
|
|
|
- Standard users: 100 requests/minute
|
|
- Admin users: 500 requests/minute
|
|
- Exceeded limits return `429 Too Many Requests`
|
|
|
|
## Error Responses
|
|
|
|
```json
|
|
{
|
|
"error": "Failed to fetch products"
|
|
}
|
|
```
|
|
|
|
HTTP Status Codes:
|
|
- `200` - Success
|
|
- `400` - Bad Request
|
|
- `401` - Unauthorized
|
|
- `404` - Not Found
|
|
- `429` - Too Many Requests
|
|
- `500` - Server Error
|
|
|
|
---
|
|
|
|
## WordPress Plugin
|
|
|
|
### Plugin Download
|
|
|
|
The WordPress plugin is available for download from the admin dashboard landing page.
|
|
|
|
**Download URL Pattern:**
|
|
```
|
|
/downloads/cb-wpmenu-{version}.zip
|
|
```
|
|
|
|
Example: `/downloads/cb-wpmenu-1.5.1.zip`
|
|
|
|
### Building the Plugin
|
|
|
|
Use the build script to create a new plugin zip for distribution:
|
|
|
|
```bash
|
|
cd wordpress-plugin
|
|
./build-plugin.sh
|
|
```
|
|
|
|
The build script will:
|
|
1. Extract the version from `crawlsy-menus.php`
|
|
2. Create a zip file named `cb-wpmenu-{version}.zip`
|
|
3. Output the file to `backend/public/downloads/`
|
|
4. Display a reminder to update the landing page
|
|
|
|
### Release Checklist
|
|
|
|
When releasing a new plugin version:
|
|
|
|
1. **Update the version** in `wordpress-plugin/crawlsy-menus.php`:
|
|
```php
|
|
* Version: 1.5.2
|
|
```
|
|
|
|
2. **Build the plugin**:
|
|
```bash
|
|
cd wordpress-plugin
|
|
./build-plugin.sh
|
|
```
|
|
|
|
3. **Update the landing page** (`frontend/src/pages/LandingPage.tsx`):
|
|
- Update download URLs: `href="/downloads/cb-wpmenu-{version}.zip"`
|
|
- Update button text: `Download Plugin v{version}`
|
|
|
|
4. **Deploy**:
|
|
- Local: The zip is served from `backend/public/downloads/`
|
|
- Remote: Commit and push changes, then deploy
|
|
|
|
### Naming Convention
|
|
|
|
| Component | Format | Example |
|
|
|-----------|--------|---------|
|
|
| Plugin file | `crawlsy-menus.php` | - |
|
|
| Zip file | `cb-wpmenu-{version}.zip` | `cb-wpmenu-1.5.1.zip` |
|
|
| Download URL | `/downloads/cb-wpmenu-{version}.zip` | `/downloads/cb-wpmenu-1.5.1.zip` |
|
|
| Shortcodes | `[cb_products]`, `[cb_product]` | `[cb_products limit="12"]` |
|