Files
cannaiq/docs/platform-slug-mapping.md
Kelly b4a2fb7d03 feat: Add v2 architecture with multi-state support and orchestrator services
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>
2025-12-07 11:30:57 -07:00

163 lines
6.0 KiB
Markdown

# 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)
```bash
# 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
```bash
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
```bash
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
```bash
curl -X POST "https://api.cannaiq.co/api/orchestrator/platforms/dt/promote/123"
```
### Get Discovery Summary
```bash
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:
1. **Assign a slug**: Choose a two-letter neutral slug
2. **Update validation**: Add to `validPlatforms` array in `backend/src/index.ts`
3. **Create routes**: Implement platform-specific discovery routes
4. **Update docs**: Add to this document
### Example: Adding Jane Support
```typescript
// 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):
```sql
-- 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