Major additions: - Multi-state expansion: states table, StateSelector, NationalDashboard, StateHeatmap, CrossStateCompare - Orchestrator services: trace service, error taxonomy, retry manager, proxy rotator - Discovery system: dutchie discovery service, geo validation, city seeding scripts - Analytics infrastructure: analytics v2 routes, brand/pricing/stores intelligence pages - Local development: setup-local.sh starts all 5 services (postgres, backend, cannaiq, findadispo, findagram) - Migrations 037-056: crawler profiles, states, analytics indexes, worker metadata Frontend pages added: - Discovery, ChainsDashboard, IntelligenceBrands, IntelligencePricing, IntelligenceStores - StateHeatmap, CrossStateCompare, SyncInfoPanel Components added: - StateSelector, OrchestratorTraceModal, WorkflowStepper 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.0 KiB
6.0 KiB
Platform Slug Mapping
Overview
To avoid trademark issues in public-facing API URLs, CannaiQ uses neutral two-letter slugs instead of vendor names in route paths.
Important: The actual platform value stored in the database remains the full name (e.g., 'dutchie'). Only the URL paths use neutral slugs.
Platform Slug Reference
| Slug | Platform | DB Value | Status |
|---|---|---|---|
dt |
Dutchie | 'dutchie' |
Active |
jn |
Jane | 'jane' |
Future |
wm |
Weedmaps | 'weedmaps' |
Future |
lf |
Leafly | 'leafly' |
Future |
tz |
Treez | 'treez' |
Future |
bl |
Blaze | 'blaze' |
Future |
fl |
Flowhub | 'flowhub' |
Future |
API Route Patterns
Discovery Routes
/api/discovery/platforms/:platformSlug/locations
/api/discovery/platforms/:platformSlug/locations/:id
/api/discovery/platforms/:platformSlug/locations/:id/verify-create
/api/discovery/platforms/:platformSlug/locations/:id/verify-link
/api/discovery/platforms/:platformSlug/locations/:id/reject
/api/discovery/platforms/:platformSlug/locations/:id/unreject
/api/discovery/platforms/:platformSlug/locations/:id/match-candidates
/api/discovery/platforms/:platformSlug/cities
/api/discovery/platforms/:platformSlug/summary
Orchestrator Routes
/api/orchestrator/platforms/:platformSlug/promote/:id
Example Usage
Fetch Discovered Locations (Dutchie)
# Using neutral slug 'dt' instead of 'dutchie'
curl "https://api.cannaiq.co/api/discovery/platforms/dt/locations?status=discovered&state_code=AZ"
Verify and Create Dispensary
curl -X POST "https://api.cannaiq.co/api/discovery/platforms/dt/locations/123/verify-create" \
-H "Content-Type: application/json" \
-d '{"verifiedBy": "admin"}'
Link to Existing Dispensary
curl -X POST "https://api.cannaiq.co/api/discovery/platforms/dt/locations/123/verify-link" \
-H "Content-Type: application/json" \
-d '{"dispensaryId": 456, "verifiedBy": "admin"}'
Promote to Crawlable
curl -X POST "https://api.cannaiq.co/api/orchestrator/platforms/dt/promote/123"
Get Discovery Summary
curl "https://api.cannaiq.co/api/discovery/platforms/dt/summary"
Migration Guide
Old Routes (DEPRECATED)
| Old Route | New Route |
|---|---|
/api/discovery/dutchie/locations |
/api/discovery/platforms/dt/locations |
/api/discovery/dutchie/locations/:id |
/api/discovery/platforms/dt/locations/:id |
/api/discovery/dutchie/locations/:id/verify-create |
/api/discovery/platforms/dt/locations/:id/verify-create |
/api/discovery/dutchie/locations/:id/verify-link |
/api/discovery/platforms/dt/locations/:id/verify-link |
/api/discovery/dutchie/locations/:id/reject |
/api/discovery/platforms/dt/locations/:id/reject |
/api/discovery/dutchie/locations/:id/unreject |
/api/discovery/platforms/dt/locations/:id/unreject |
/api/discovery/dutchie/locations/:id/match-candidates |
/api/discovery/platforms/dt/locations/:id/match-candidates |
/api/discovery/dutchie/cities |
/api/discovery/platforms/dt/cities |
/api/discovery/dutchie/summary |
/api/discovery/platforms/dt/summary |
/api/discovery/dutchie/nearby |
/api/discovery/platforms/dt/nearby |
/api/discovery/dutchie/geo-stats |
/api/discovery/platforms/dt/geo-stats |
/api/discovery/dutchie/locations/:id/validate-geo |
/api/discovery/platforms/dt/locations/:id/validate-geo |
/api/orchestrator/dutchie/promote/:id |
/api/orchestrator/platforms/dt/promote/:id |
API Client Changes
| Old Method | New Method |
|---|---|
getDutchieDiscoverySummary() |
getPlatformDiscoverySummary('dt') |
getDutchieDiscoveryLocations(params) |
getPlatformDiscoveryLocations('dt', params) |
getDutchieDiscoveryLocation(id) |
getPlatformDiscoveryLocation('dt', id) |
verifyCreateDutchieLocation(id) |
verifyCreatePlatformLocation('dt', id) |
verifyLinkDutchieLocation(id, dispId) |
verifyLinkPlatformLocation('dt', id, dispId) |
rejectDutchieLocation(id, reason) |
rejectPlatformLocation('dt', id, reason) |
unrejectDutchieLocation(id) |
unrejectPlatformLocation('dt', id) |
getDutchieLocationMatchCandidates(id) |
getPlatformLocationMatchCandidates('dt', id) |
getDutchieDiscoveryCities(params) |
getPlatformDiscoveryCities('dt', params) |
getDutchieNearbyLocations(lat, lon) |
getPlatformNearbyLocations('dt', lat, lon) |
getDutchieGeoStats() |
getPlatformGeoStats('dt') |
validateDutchieLocationGeo(id) |
validatePlatformLocationGeo('dt', id) |
promoteDutchieDiscoveryLocation(id) |
promotePlatformDiscoveryLocation('dt', id) |
Adding New Platforms
When adding support for a new platform:
- Assign a slug: Choose a two-letter neutral slug
- Update validation: Add to
validPlatformsarray inbackend/src/index.ts - Create routes: Implement platform-specific discovery routes
- Update docs: Add to this document
Example: Adding Jane Support
// backend/src/index.ts
const validPlatforms = ['dt', 'jn']; // Add 'jn' for Jane
// Create Jane discovery routes
const jnDiscoveryRoutes = createJaneDiscoveryRoutes(getPool());
app.use('/api/discovery/platforms/jn', jnDiscoveryRoutes);
Database Schema
The platform column in discovery tables stores the full platform name (not the slug):
-- dutchie_discovery_locations table
SELECT * FROM dutchie_discovery_locations WHERE platform = 'dutchie';
-- dutchie_discovery_cities table
SELECT * FROM dutchie_discovery_cities WHERE platform = 'dutchie';
This keeps the database schema clean and allows for future renaming of URL slugs without database migrations.
Safe Naming Conventions
DO
- Use neutral two-letter slugs in URLs:
dt,jn,wm - Use generic terms in user-facing text: "platform", "menu provider"
- Store full platform names in the database for clarity
DON'T
- Use trademarked names in URL paths
- Use vendor names in public-facing error messages
- Expose vendor-specific identifiers in consumer APIs