chore: Clean up deprecated code and docs
- Move deprecated directories to src/_deprecated/: - hydration/ (old pipeline approach) - scraper-v2/ (old Puppeteer scraper) - canonical-hydration/ (merged into tasks) - Unused services: availability, crawler-logger, geolocation, etc - Unused utils: age-gate-playwright, HomepageValidator, stealthBrowser - Archive outdated docs to docs/_archive/: - ANALYTICS_RUNBOOK.md - ANALYTICS_V2_EXAMPLES.md - BRAND_INTELLIGENCE_API.md - CRAWL_PIPELINE.md - TASK_WORKFLOW_2024-12-10.md - WORKER_TASK_ARCHITECTURE.md - ORGANIC_SCRAPING_GUIDE.md - Add docs/CODEBASE_MAP.md as single source of truth - Add warning files to deprecated/archived directories - Slim down CLAUDE.md to essential rules only 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
594
backend/docs/_archive/ANALYTICS_V2_EXAMPLES.md
Normal file
594
backend/docs/_archive/ANALYTICS_V2_EXAMPLES.md
Normal file
@@ -0,0 +1,594 @@
|
||||
# Analytics V2 API Examples
|
||||
|
||||
## Overview
|
||||
|
||||
All endpoints are prefixed with `/api/analytics/v2`
|
||||
|
||||
### Filtering Options
|
||||
|
||||
**Time Windows:**
|
||||
- `?window=7d` - Last 7 days
|
||||
- `?window=30d` - Last 30 days (default)
|
||||
- `?window=90d` - Last 90 days
|
||||
|
||||
**Legal Type Filtering:**
|
||||
- `?legalType=recreational` - Recreational states only
|
||||
- `?legalType=medical_only` - Medical-only states (not recreational)
|
||||
- `?legalType=no_program` - States with no cannabis program
|
||||
|
||||
---
|
||||
|
||||
## 1. Price Analytics
|
||||
|
||||
### GET /price/product/:id
|
||||
|
||||
Get price trends for a specific store product.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/price/product/12345?window=30d
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"store_product_id": 12345,
|
||||
"product_name": "Blue Dream 3.5g",
|
||||
"brand_name": "Cookies",
|
||||
"category": "Flower",
|
||||
"dispensary_id": 101,
|
||||
"dispensary_name": "Green Leaf Dispensary",
|
||||
"state_code": "AZ",
|
||||
"data_points": [
|
||||
{
|
||||
"date": "2024-11-06",
|
||||
"price_rec": 45.00,
|
||||
"price_med": 40.00,
|
||||
"price_rec_special": null,
|
||||
"price_med_special": null,
|
||||
"is_on_special": false
|
||||
},
|
||||
{
|
||||
"date": "2024-11-07",
|
||||
"price_rec": 42.00,
|
||||
"price_med": 38.00,
|
||||
"price_rec_special": null,
|
||||
"price_med_special": null,
|
||||
"is_on_special": false
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"current_price": 42.00,
|
||||
"min_price": 40.00,
|
||||
"max_price": 48.00,
|
||||
"avg_price": 43.50,
|
||||
"price_change_count": 3,
|
||||
"volatility_percent": 8.2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GET /price/rec-vs-med
|
||||
|
||||
Get recreational vs medical-only price comparison by category.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/price/rec-vs-med?category=Flower
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"category": "Flower",
|
||||
"rec_avg": 38.50,
|
||||
"rec_median": 35.00,
|
||||
"med_avg": 42.00,
|
||||
"med_median": 40.00
|
||||
},
|
||||
{
|
||||
"category": "Concentrates",
|
||||
"rec_avg": 45.00,
|
||||
"rec_median": 42.00,
|
||||
"med_avg": 48.00,
|
||||
"med_median": 45.00
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Brand Analytics
|
||||
|
||||
### GET /brand/:name/penetration
|
||||
|
||||
Get brand penetration metrics with state breakdown.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/brand/Cookies/penetration?window=30d
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"brand_name": "Cookies",
|
||||
"total_dispensaries": 125,
|
||||
"total_skus": 450,
|
||||
"avg_skus_per_dispensary": 3.6,
|
||||
"states_present": ["AZ", "CA", "CO", "NV", "MI"],
|
||||
"state_breakdown": [
|
||||
{
|
||||
"state_code": "CA",
|
||||
"state_name": "California",
|
||||
"legal_type": "recreational",
|
||||
"dispensary_count": 45,
|
||||
"sku_count": 180,
|
||||
"avg_skus_per_dispensary": 4.0,
|
||||
"market_share_percent": 12.5
|
||||
},
|
||||
{
|
||||
"state_code": "AZ",
|
||||
"state_name": "Arizona",
|
||||
"legal_type": "recreational",
|
||||
"dispensary_count": 32,
|
||||
"sku_count": 128,
|
||||
"avg_skus_per_dispensary": 4.0,
|
||||
"market_share_percent": 15.2
|
||||
}
|
||||
],
|
||||
"penetration_trend": [
|
||||
{
|
||||
"date": "2024-11-01",
|
||||
"dispensary_count": 120,
|
||||
"new_dispensaries": 0,
|
||||
"dropped_dispensaries": 0
|
||||
},
|
||||
{
|
||||
"date": "2024-11-08",
|
||||
"dispensary_count": 123,
|
||||
"new_dispensaries": 3,
|
||||
"dropped_dispensaries": 0
|
||||
},
|
||||
{
|
||||
"date": "2024-11-15",
|
||||
"dispensary_count": 125,
|
||||
"new_dispensaries": 2,
|
||||
"dropped_dispensaries": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GET /brand/:name/rec-vs-med
|
||||
|
||||
Get brand presence in recreational vs medical-only states.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/brand/Cookies/rec-vs-med
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"brand_name": "Cookies",
|
||||
"rec_states_count": 4,
|
||||
"rec_states": ["AZ", "CA", "CO", "NV"],
|
||||
"rec_dispensary_count": 110,
|
||||
"rec_avg_skus": 3.8,
|
||||
"med_only_states_count": 2,
|
||||
"med_only_states": ["FL", "OH"],
|
||||
"med_only_dispensary_count": 15,
|
||||
"med_only_avg_skus": 2.5
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Category Analytics
|
||||
|
||||
### GET /category/:name/growth
|
||||
|
||||
Get category growth metrics with state breakdown.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/category/Flower/growth?window=30d
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"category": "Flower",
|
||||
"current_sku_count": 5200,
|
||||
"current_dispensary_count": 320,
|
||||
"avg_price": 38.50,
|
||||
"growth_data": [
|
||||
{
|
||||
"date": "2024-11-01",
|
||||
"sku_count": 4800,
|
||||
"dispensary_count": 310,
|
||||
"avg_price": 39.00
|
||||
},
|
||||
{
|
||||
"date": "2024-11-15",
|
||||
"sku_count": 5000,
|
||||
"dispensary_count": 315,
|
||||
"avg_price": 38.75
|
||||
},
|
||||
{
|
||||
"date": "2024-12-01",
|
||||
"sku_count": 5200,
|
||||
"dispensary_count": 320,
|
||||
"avg_price": 38.50
|
||||
}
|
||||
],
|
||||
"state_breakdown": [
|
||||
{
|
||||
"state_code": "CA",
|
||||
"state_name": "California",
|
||||
"legal_type": "recreational",
|
||||
"sku_count": 2100,
|
||||
"dispensary_count": 145,
|
||||
"avg_price": 36.00
|
||||
},
|
||||
{
|
||||
"state_code": "AZ",
|
||||
"state_name": "Arizona",
|
||||
"legal_type": "recreational",
|
||||
"sku_count": 950,
|
||||
"dispensary_count": 85,
|
||||
"avg_price": 40.00
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GET /category/rec-vs-med
|
||||
|
||||
Get category comparison between recreational and medical-only states.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/category/rec-vs-med
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"category": "Flower",
|
||||
"recreational": {
|
||||
"state_count": 15,
|
||||
"dispensary_count": 650,
|
||||
"sku_count": 12500,
|
||||
"avg_price": 35.50,
|
||||
"median_price": 32.00
|
||||
},
|
||||
"medical_only": {
|
||||
"state_count": 8,
|
||||
"dispensary_count": 220,
|
||||
"sku_count": 4200,
|
||||
"avg_price": 42.00,
|
||||
"median_price": 40.00
|
||||
},
|
||||
"price_diff_percent": -15.48
|
||||
},
|
||||
{
|
||||
"category": "Concentrates",
|
||||
"recreational": {
|
||||
"state_count": 15,
|
||||
"dispensary_count": 600,
|
||||
"sku_count": 8500,
|
||||
"avg_price": 42.00,
|
||||
"median_price": 40.00
|
||||
},
|
||||
"medical_only": {
|
||||
"state_count": 8,
|
||||
"dispensary_count": 200,
|
||||
"sku_count": 3100,
|
||||
"avg_price": 48.00,
|
||||
"median_price": 45.00
|
||||
},
|
||||
"price_diff_percent": -12.50
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Store Analytics
|
||||
|
||||
### GET /store/:id/summary
|
||||
|
||||
Get change summary for a store over a time window.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/store/101/summary?window=30d
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"dispensary_id": 101,
|
||||
"dispensary_name": "Green Leaf Dispensary",
|
||||
"state_code": "AZ",
|
||||
"window": "30d",
|
||||
"products_added": 45,
|
||||
"products_dropped": 12,
|
||||
"brands_added": ["Alien Labs", "Connected"],
|
||||
"brands_dropped": ["House Brand"],
|
||||
"price_changes": 156,
|
||||
"avg_price_change_percent": 3.2,
|
||||
"stock_in_events": 89,
|
||||
"stock_out_events": 34,
|
||||
"current_product_count": 512,
|
||||
"current_in_stock_count": 478
|
||||
}
|
||||
```
|
||||
|
||||
### GET /store/:id/events
|
||||
|
||||
Get recent product change events for a store.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/store/101/events?window=7d&limit=50
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"store_product_id": 12345,
|
||||
"product_name": "Blue Dream 3.5g",
|
||||
"brand_name": "Cookies",
|
||||
"category": "Flower",
|
||||
"event_type": "price_change",
|
||||
"event_date": "2024-12-05T14:30:00.000Z",
|
||||
"old_value": "45.00",
|
||||
"new_value": "42.00"
|
||||
},
|
||||
{
|
||||
"store_product_id": 12346,
|
||||
"product_name": "OG Kush 1g",
|
||||
"brand_name": "Alien Labs",
|
||||
"category": "Flower",
|
||||
"event_type": "added",
|
||||
"event_date": "2024-12-04T10:00:00.000Z",
|
||||
"old_value": null,
|
||||
"new_value": null
|
||||
},
|
||||
{
|
||||
"store_product_id": 12300,
|
||||
"product_name": "Sour Diesel Cart",
|
||||
"brand_name": "Select",
|
||||
"category": "Vaporizers",
|
||||
"event_type": "stock_out",
|
||||
"event_date": "2024-12-03T16:45:00.000Z",
|
||||
"old_value": "true",
|
||||
"new_value": "false"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. State Analytics
|
||||
|
||||
### GET /state/:code/summary
|
||||
|
||||
Get market summary for a specific state with rec/med breakdown.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/state/AZ/summary
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"state_code": "AZ",
|
||||
"state_name": "Arizona",
|
||||
"legal_status": {
|
||||
"recreational_legal": true,
|
||||
"rec_year": 2020,
|
||||
"medical_legal": true,
|
||||
"med_year": 2010
|
||||
},
|
||||
"coverage": {
|
||||
"dispensary_count": 145,
|
||||
"product_count": 18500,
|
||||
"brand_count": 320,
|
||||
"category_count": 12,
|
||||
"snapshot_count": 2450000,
|
||||
"last_crawl_at": "2024-12-06T02:30:00.000Z"
|
||||
},
|
||||
"pricing": {
|
||||
"avg_price": 42.50,
|
||||
"median_price": 38.00,
|
||||
"min_price": 5.00,
|
||||
"max_price": 250.00
|
||||
},
|
||||
"top_categories": [
|
||||
{ "category": "Flower", "count": 5200 },
|
||||
{ "category": "Concentrates", "count": 3800 },
|
||||
{ "category": "Vaporizers", "count": 2950 },
|
||||
{ "category": "Edibles", "count": 2400 },
|
||||
{ "category": "Pre-Rolls", "count": 1850 }
|
||||
],
|
||||
"top_brands": [
|
||||
{ "brand": "Cookies", "count": 450 },
|
||||
{ "brand": "Alien Labs", "count": 380 },
|
||||
{ "brand": "Connected", "count": 320 },
|
||||
{ "brand": "Stiiizy", "count": 290 },
|
||||
{ "brand": "Raw Garden", "count": 275 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### GET /state/legal-breakdown
|
||||
|
||||
Get breakdown by legal status (recreational, medical-only, no program).
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/state/legal-breakdown
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"recreational_states": {
|
||||
"count": 24,
|
||||
"dispensary_count": 850,
|
||||
"product_count": 125000,
|
||||
"snapshot_count": 15000000,
|
||||
"states": [
|
||||
{ "code": "CA", "name": "California", "dispensary_count": 250 },
|
||||
{ "code": "CO", "name": "Colorado", "dispensary_count": 150 },
|
||||
{ "code": "AZ", "name": "Arizona", "dispensary_count": 145 },
|
||||
{ "code": "MI", "name": "Michigan", "dispensary_count": 120 }
|
||||
]
|
||||
},
|
||||
"medical_only_states": {
|
||||
"count": 18,
|
||||
"dispensary_count": 320,
|
||||
"product_count": 45000,
|
||||
"snapshot_count": 5000000,
|
||||
"states": [
|
||||
{ "code": "FL", "name": "Florida", "dispensary_count": 120 },
|
||||
{ "code": "OH", "name": "Ohio", "dispensary_count": 85 },
|
||||
{ "code": "PA", "name": "Pennsylvania", "dispensary_count": 75 }
|
||||
]
|
||||
},
|
||||
"no_program_states": {
|
||||
"count": 9,
|
||||
"states": [
|
||||
{ "code": "ID", "name": "Idaho" },
|
||||
{ "code": "WY", "name": "Wyoming" },
|
||||
{ "code": "KS", "name": "Kansas" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GET /state/recreational
|
||||
|
||||
Get list of recreational state codes.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/state/recreational
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"legal_type": "recreational",
|
||||
"states": ["AK", "AZ", "CA", "CO", "CT", "DE", "IL", "MA", "MD", "ME", "MI", "MN", "MO", "MT", "NJ", "NM", "NV", "NY", "OH", "OR", "RI", "VA", "VT", "WA"],
|
||||
"count": 24
|
||||
}
|
||||
```
|
||||
|
||||
### GET /state/medical-only
|
||||
|
||||
Get list of medical-only state codes (not recreational).
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/state/medical-only
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"legal_type": "medical_only",
|
||||
"states": ["AR", "FL", "HI", "LA", "MS", "ND", "NH", "OK", "PA", "SD", "UT", "WV"],
|
||||
"count": 12
|
||||
}
|
||||
```
|
||||
|
||||
### GET /state/rec-vs-med-pricing
|
||||
|
||||
Get rec vs med price comparison by category.
|
||||
|
||||
**Request:**
|
||||
```bash
|
||||
GET /api/analytics/v2/state/rec-vs-med-pricing?category=Flower
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"category": "Flower",
|
||||
"recreational": {
|
||||
"state_count": 15,
|
||||
"product_count": 12500,
|
||||
"avg_price": 35.50,
|
||||
"median_price": 32.00
|
||||
},
|
||||
"medical_only": {
|
||||
"state_count": 8,
|
||||
"product_count": 5200,
|
||||
"avg_price": 42.00,
|
||||
"median_price": 40.00
|
||||
},
|
||||
"price_diff_percent": -15.48
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How These Endpoints Support Portals
|
||||
|
||||
### Brand Portal Use Cases
|
||||
|
||||
1. **Track brand penetration**: Use `/brand/:name/penetration` to see how many stores carry the brand
|
||||
2. **Compare rec vs med markets**: Use `/brand/:name/rec-vs-med` to understand footprint by legal status
|
||||
3. **Identify expansion opportunities**: Use `/state/coverage-gaps` to find underserved markets
|
||||
4. **Monitor pricing**: Use `/price/brand/:brand` to track pricing by state
|
||||
|
||||
### Buyer Portal Use Cases
|
||||
|
||||
1. **Compare stores**: Use `/store/:id/summary` to see activity levels
|
||||
2. **Track price changes**: Use `/store/:id/events` to monitor competitor pricing
|
||||
3. **Analyze categories**: Use `/category/:name/growth` to identify trending products
|
||||
4. **State-level insights**: Use `/state/:code/summary` for market overview
|
||||
|
||||
---
|
||||
|
||||
## Time Window Filtering
|
||||
|
||||
All time-based endpoints support the `window` query parameter:
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `7d` | Last 7 days |
|
||||
| `30d` | Last 30 days (default) |
|
||||
| `90d` | Last 90 days |
|
||||
|
||||
The window affects:
|
||||
- `store_product_snapshots.captured_at` for historical data
|
||||
- `store_products.first_seen_at` / `last_seen_at` for product lifecycle
|
||||
- `crawl_runs.started_at` for crawl-based metrics
|
||||
|
||||
---
|
||||
|
||||
## Rec/Med Segmentation
|
||||
|
||||
All state-level endpoints automatically segment by:
|
||||
|
||||
- **Recreational**: `states.recreational_legal = TRUE`
|
||||
- **Medical-only**: `states.medical_legal = TRUE AND states.recreational_legal = FALSE`
|
||||
- **No program**: Both flags are FALSE or NULL
|
||||
|
||||
This segmentation appears in:
|
||||
- `legal_type` field in responses
|
||||
- State breakdown arrays
|
||||
- Price comparison endpoints
|
||||
Reference in New Issue
Block a user