first commit
This commit is contained in:
776
PRICING_SYSTEM.md
Normal file
776
PRICING_SYSTEM.md
Normal file
@@ -0,0 +1,776 @@
|
||||
# Pricing System & Phase Detection Guide
|
||||
|
||||
Complete guide for the automated pricing system using SteamAPIs.com, phase detection for Doppler items, and hourly price updates.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
The pricing system automatically fetches and updates market prices for CS2 and Rust items every hour using SteamAPIs.com. It includes:
|
||||
|
||||
- **Phase Detection** - Automatically detects Doppler phases (Ruby, Sapphire, Phase 1-4, etc.)
|
||||
- **Market Price Storage** - Stores prices in database for fast access
|
||||
- **Automatic Updates** - Scheduled hourly updates (configurable)
|
||||
- **Manual Triggers** - Admin panel for manual price updates
|
||||
- **Estimation Fallback** - Smart price estimation when market data unavailable
|
||||
|
||||
---
|
||||
|
||||
## 📊 Features
|
||||
|
||||
### 1. Phase Detection
|
||||
|
||||
Automatically detects Doppler and Gamma Doppler phases from item names and descriptions:
|
||||
|
||||
**Supported Phases:**
|
||||
- ✅ Ruby (highest value)
|
||||
- ✅ Sapphire (highest value)
|
||||
- ✅ Black Pearl (rare)
|
||||
- ✅ Emerald (Gamma Doppler)
|
||||
- ✅ Phase 1
|
||||
- ✅ Phase 2 (popular)
|
||||
- ✅ Phase 3
|
||||
- ✅ Phase 4 (popular)
|
||||
|
||||
**How It Works:**
|
||||
```javascript
|
||||
// Example detection from item name/description
|
||||
"★ Karambit | Doppler (Factory New) - Ruby" → Phase: "Ruby"
|
||||
"★ M9 Bayonet | Doppler (Minimal Wear) - Phase 2" → Phase: "Phase 2"
|
||||
```
|
||||
|
||||
**Phase Multipliers (Price Impact):**
|
||||
- Ruby: 3.5x base price
|
||||
- Sapphire: 3.8x base price
|
||||
- Emerald: 4.0x base price
|
||||
- Black Pearl: 2.5x base price
|
||||
- Phase 2: 1.3x base price
|
||||
- Phase 4: 1.2x base price
|
||||
- Phase 1: 1.0x base price
|
||||
- Phase 3: 0.95x base price
|
||||
|
||||
### 2. Market Price Fetching
|
||||
|
||||
**Source:** SteamAPIs.com `/market/items/{AppID}` endpoint
|
||||
|
||||
**Supported Games:**
|
||||
- CS2 (AppID: 730)
|
||||
- Rust (AppID: 252490)
|
||||
|
||||
**Price Data:**
|
||||
- Uses 30-day average price (most stable)
|
||||
- Currency: USD
|
||||
- Updates every hour
|
||||
- Caches last update timestamp
|
||||
|
||||
**Example API Call:**
|
||||
```
|
||||
GET https://api.steamapis.com/market/items/730?api_key=YOUR_KEY
|
||||
```
|
||||
|
||||
**Response Format:**
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"AK-47 | Redline (Field-Tested)": {
|
||||
"prices": {
|
||||
"7": 42.50,
|
||||
"30": 41.80,
|
||||
"all_time": 45.00
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Database Storage
|
||||
|
||||
**Item Model Fields:**
|
||||
```javascript
|
||||
{
|
||||
name: String, // Item name (used for price matching)
|
||||
price: Number, // Seller's listing price
|
||||
marketPrice: Number, // Current market price from SteamAPIs
|
||||
priceUpdatedAt: Date, // Last price update timestamp
|
||||
phase: String, // Doppler phase (if applicable)
|
||||
wear: String, // fn, mw, ft, ww, bs
|
||||
statTrak: Boolean,
|
||||
souvenir: Boolean
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Price Estimation
|
||||
|
||||
When market data is unavailable, the system uses intelligent estimation:
|
||||
|
||||
**Factors Considered:**
|
||||
- Item name patterns (knives, gloves, high-tier skins)
|
||||
- Wear condition multipliers
|
||||
- Phase multipliers
|
||||
- StatTrak multiplier (1.5x)
|
||||
- Souvenir multiplier (1.3x)
|
||||
|
||||
**Wear Multipliers:**
|
||||
- Factory New (FN): 1.0x
|
||||
- Minimal Wear (MW): 0.85x
|
||||
- Field-Tested (FT): 0.70x
|
||||
- Well-Worn (WW): 0.55x
|
||||
- Battle-Scarred (BS): 0.40x
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Setup & Configuration
|
||||
|
||||
### 1. Environment Variables
|
||||
|
||||
Add to `.env` file:
|
||||
|
||||
```env
|
||||
# Steam API Key (SteamAPIs.com)
|
||||
STEAM_APIS_KEY=your_steamapis_key_here
|
||||
STEAM_API_KEY=fallback_key_here
|
||||
|
||||
# Admin Configuration
|
||||
ADMIN_STEAM_IDS=76561198000000000,76561198111111111
|
||||
|
||||
# Enable automatic price updates (optional in dev)
|
||||
ENABLE_PRICE_UPDATES=true
|
||||
```
|
||||
|
||||
### 2. Admin Access
|
||||
|
||||
**Option A: Steam ID Whitelist**
|
||||
Add admin Steam IDs to `.env`:
|
||||
```env
|
||||
ADMIN_STEAM_IDS=76561198000000000,76561198111111111
|
||||
```
|
||||
|
||||
**Option B: Staff Level**
|
||||
Update user in database:
|
||||
```javascript
|
||||
db.users.updateOne(
|
||||
{ steamId: "76561198000000000" },
|
||||
{ $set: { staffLevel: 3 } }
|
||||
)
|
||||
```
|
||||
|
||||
**Admin Levels:**
|
||||
- 0: Regular user
|
||||
- 1: Moderator
|
||||
- 2: Staff
|
||||
- 3+: Admin (has pricing access)
|
||||
|
||||
### 3. Start Price Updates
|
||||
|
||||
**Automatic (on server start):**
|
||||
```javascript
|
||||
// Runs every 1 hour automatically
|
||||
pricingService.scheduleUpdates(60 * 60 * 1000);
|
||||
```
|
||||
|
||||
**Manual via API:**
|
||||
```bash
|
||||
POST /api/admin/prices/schedule
|
||||
{
|
||||
"intervalMinutes": 60
|
||||
}
|
||||
```
|
||||
|
||||
**Disable in Development:**
|
||||
```env
|
||||
# Don't set ENABLE_PRICE_UPDATES or set to false
|
||||
ENABLE_PRICE_UPDATES=false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📡 API Endpoints
|
||||
|
||||
### Admin Endpoints (Require Authentication + Admin Access)
|
||||
|
||||
#### 1. Trigger Price Update
|
||||
|
||||
```http
|
||||
POST /api/admin/prices/update
|
||||
Content-Type: application/json
|
||||
Cookie: accessToken=your_jwt_token
|
||||
|
||||
{
|
||||
"game": "cs2" // "cs2", "rust", or "all"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Price update completed",
|
||||
"data": {
|
||||
"cs2": {
|
||||
"success": true,
|
||||
"game": "cs2",
|
||||
"total": 150,
|
||||
"updated": 142,
|
||||
"notFound": 8,
|
||||
"errors": 0,
|
||||
"timestamp": "2024-01-10T12:00:00.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. Get Price Update Status
|
||||
|
||||
```http
|
||||
GET /api/admin/prices/status
|
||||
Cookie: accessToken=your_jwt_token
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"status": {
|
||||
"cs2": {
|
||||
"lastUpdate": "2024-01-10T11:00:00.000Z",
|
||||
"needsUpdate": false,
|
||||
"stats": {
|
||||
"total": 150,
|
||||
"withMarketPrice": 142,
|
||||
"avgMarketPrice": 45.50,
|
||||
"minMarketPrice": 0.50,
|
||||
"maxMarketPrice": 8999.99
|
||||
}
|
||||
},
|
||||
"rust": {
|
||||
"lastUpdate": "2024-01-10T11:00:00.000Z",
|
||||
"needsUpdate": false,
|
||||
"stats": {
|
||||
"total": 50,
|
||||
"withMarketPrice": 45,
|
||||
"avgMarketPrice": 25.30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Get Items Without Prices
|
||||
|
||||
```http
|
||||
GET /api/admin/prices/missing?game=cs2&limit=50
|
||||
Cookie: accessToken=your_jwt_token
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"total": 8,
|
||||
"items": [
|
||||
{
|
||||
"_id": "item_id",
|
||||
"name": "AK-47 | Redline (Field-Tested)",
|
||||
"game": "cs2",
|
||||
"category": "rifles",
|
||||
"rarity": "rare",
|
||||
"wear": "ft",
|
||||
"phase": null,
|
||||
"seller": {
|
||||
"username": "User123"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. Estimate Price for Specific Item
|
||||
|
||||
```http
|
||||
POST /api/admin/prices/estimate
|
||||
Content-Type: application/json
|
||||
Cookie: accessToken=your_jwt_token
|
||||
|
||||
{
|
||||
"itemId": "item_id_here"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Price estimated and updated",
|
||||
"item": {
|
||||
"id": "item_id",
|
||||
"name": "AK-47 | Redline (Field-Tested)",
|
||||
"marketPrice": 42.50,
|
||||
"priceUpdatedAt": "2024-01-10T12:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 5. Schedule Price Updates
|
||||
|
||||
```http
|
||||
POST /api/admin/prices/schedule
|
||||
Content-Type: application/json
|
||||
Cookie: accessToken=your_jwt_token
|
||||
|
||||
{
|
||||
"intervalMinutes": 60
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- Minimum: 15 minutes
|
||||
- Maximum: 1440 minutes (24 hours)
|
||||
- Default: 60 minutes (1 hour)
|
||||
|
||||
#### 6. Get System Statistics
|
||||
|
||||
```http
|
||||
GET /api/admin/stats
|
||||
Cookie: accessToken=your_jwt_token
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"stats": {
|
||||
"items": {
|
||||
"total": 250,
|
||||
"active": 200,
|
||||
"sold": 50
|
||||
},
|
||||
"users": {
|
||||
"total": 1500
|
||||
},
|
||||
"marketplace": {
|
||||
"totalValue": 125000.00,
|
||||
"totalRevenue": 75000.00
|
||||
},
|
||||
"recentSales": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 How It Works
|
||||
|
||||
### Automatic Price Updates
|
||||
|
||||
**Flow:**
|
||||
1. **Scheduler triggers** (every 1 hour)
|
||||
2. **Fetch prices** from SteamAPIs.com
|
||||
3. **Parse response** - Extract item names and prices
|
||||
4. **Query database** - Get all active items for game
|
||||
5. **Match items** - Compare by name (exact match)
|
||||
6. **Update prices** - Save marketPrice and timestamp
|
||||
7. **Log results** - Report success/failures
|
||||
|
||||
**Example Log Output:**
|
||||
```
|
||||
⏰ Scheduling automatic price updates every 60 minutes
|
||||
📊 Fetching CS2 market prices...
|
||||
✅ Fetched 5000 prices for CS2
|
||||
🔄 Updating database prices for CS2...
|
||||
✅ Price update complete for CS2:
|
||||
- Total items: 150
|
||||
- Updated: 142
|
||||
- Not found: 8
|
||||
- Errors: 0
|
||||
```
|
||||
|
||||
### Phase Detection in Inventory
|
||||
|
||||
**When user loads Sell page:**
|
||||
|
||||
1. **Fetch inventory** from Steam/SteamAPIs
|
||||
2. **Parse descriptions** - Extract item descriptions
|
||||
3. **Detect phase** - Scan name + description for phase keywords
|
||||
4. **Store phase** - Add to item data
|
||||
5. **Calculate price** - Apply phase multipliers
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// Item from Steam inventory
|
||||
{
|
||||
name: "★ Karambit | Doppler (Factory New)",
|
||||
descriptions: [
|
||||
{ value: "Phase 2" },
|
||||
{ value: "Rare Special Item" }
|
||||
]
|
||||
}
|
||||
|
||||
// After phase detection
|
||||
{
|
||||
name: "★ Karambit | Doppler (Factory New)",
|
||||
phase: "Phase 2",
|
||||
estimatedPrice: 520.00 // Base 400 * 1.3 (Phase 2 multiplier)
|
||||
}
|
||||
```
|
||||
|
||||
### Price Calculation
|
||||
|
||||
**Priority Order:**
|
||||
1. **Database marketPrice** (if available and recent)
|
||||
2. **SteamAPIs market data** (if available)
|
||||
3. **Estimation algorithm** (fallback)
|
||||
|
||||
**Calculation Steps:**
|
||||
```javascript
|
||||
let price = basePrice;
|
||||
|
||||
// 1. Apply wear multiplier
|
||||
if (wear) {
|
||||
price *= wearMultipliers[wear];
|
||||
}
|
||||
|
||||
// 2. Apply phase multiplier
|
||||
if (phase) {
|
||||
price *= phaseMultipliers[phase];
|
||||
}
|
||||
|
||||
// 3. Apply StatTrak multiplier
|
||||
if (statTrak) {
|
||||
price *= 1.5;
|
||||
}
|
||||
|
||||
// 4. Apply Souvenir multiplier
|
||||
if (souvenir) {
|
||||
price *= 1.3;
|
||||
}
|
||||
|
||||
return Math.round(price * 100) / 100;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### 1. Test Price Fetching
|
||||
|
||||
**Via Admin API:**
|
||||
```bash
|
||||
# Get auth token first (login via Steam)
|
||||
# Then trigger update
|
||||
|
||||
curl -X POST http://localhost:3000/api/admin/prices/update \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Cookie: accessToken=YOUR_TOKEN" \
|
||||
-d '{"game": "cs2"}'
|
||||
```
|
||||
|
||||
**Expected Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Price update completed",
|
||||
"data": {
|
||||
"cs2": {
|
||||
"success": true,
|
||||
"updated": 142,
|
||||
"notFound": 8
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Test Phase Detection
|
||||
|
||||
**Load item with Doppler:**
|
||||
```javascript
|
||||
// In Sell page, select a Doppler knife
|
||||
// Check console logs or item data
|
||||
|
||||
console.log(item.phase); // Should show "Ruby", "Phase 2", etc.
|
||||
```
|
||||
|
||||
### 3. Verify Database Updates
|
||||
|
||||
**MongoDB Shell:**
|
||||
```javascript
|
||||
// Check items with market prices
|
||||
db.items.find({
|
||||
marketPrice: { $exists: true, $ne: null }
|
||||
}).count();
|
||||
|
||||
// Check recent price updates
|
||||
db.items.find({
|
||||
priceUpdatedAt: { $gte: new Date(Date.now() - 3600000) }
|
||||
});
|
||||
|
||||
// Check items with phases
|
||||
db.items.find({
|
||||
phase: { $ne: null }
|
||||
});
|
||||
```
|
||||
|
||||
### 4. Test Scheduled Updates
|
||||
|
||||
**Enable in development:**
|
||||
```env
|
||||
ENABLE_PRICE_UPDATES=true
|
||||
```
|
||||
|
||||
**Watch logs:**
|
||||
```
|
||||
⏰ Starting automatic price update scheduler...
|
||||
📊 Fetching CS2 market prices...
|
||||
✅ Fetched 5000 prices for CS2
|
||||
🔄 Updating database prices for CS2...
|
||||
✅ Price update complete
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 Monitoring
|
||||
|
||||
### Check Price Update Status
|
||||
|
||||
**Via Admin Dashboard:**
|
||||
```
|
||||
GET /api/admin/prices/status
|
||||
```
|
||||
|
||||
**Look for:**
|
||||
- Last update timestamp
|
||||
- Number of items with prices
|
||||
- Items missing prices
|
||||
- Average market prices
|
||||
|
||||
### Check Logs
|
||||
|
||||
**Successful Update:**
|
||||
```
|
||||
✅ Fetched 5000 prices for CS2
|
||||
✅ Price update complete for CS2:
|
||||
- Total items: 150
|
||||
- Updated: 142
|
||||
```
|
||||
|
||||
**Failures:**
|
||||
```
|
||||
❌ Error fetching market prices for cs2: 429 Rate limit exceeded
|
||||
❌ Failed to update item AK-47 | Redline: Not found in market data
|
||||
```
|
||||
|
||||
### Database Health Check
|
||||
|
||||
```javascript
|
||||
// Check price coverage
|
||||
db.items.aggregate([
|
||||
{
|
||||
$group: {
|
||||
_id: "$game",
|
||||
total: { $sum: 1 },
|
||||
withPrice: {
|
||||
$sum: { $cond: [{ $ne: ["$marketPrice", null] }, 1, 0] }
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
// Output:
|
||||
// { _id: "cs2", total: 150, withPrice: 142 }
|
||||
// { _id: "rust", total: 50, withPrice: 45 }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: No Prices Being Fetched
|
||||
|
||||
**Check:**
|
||||
1. ✅ `STEAM_APIS_KEY` in `.env`
|
||||
2. ✅ API key is valid
|
||||
3. ✅ SteamAPIs.com service status
|
||||
4. ✅ Rate limits not exceeded
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
# Verify API key
|
||||
curl "https://api.steamapis.com/market/items/730?api_key=YOUR_KEY"
|
||||
|
||||
# Check backend logs
|
||||
# Should see: "📊 Fetching CS2 market prices..."
|
||||
```
|
||||
|
||||
### Issue: Phase Not Detected
|
||||
|
||||
**Check:**
|
||||
1. Item name contains phase info
|
||||
2. Item description parsed correctly
|
||||
3. Phase keywords match exactly
|
||||
|
||||
**Debug:**
|
||||
```javascript
|
||||
// Add logging in inventory route
|
||||
console.log("Item name:", item.name);
|
||||
console.log("Descriptions:", item.descriptions);
|
||||
console.log("Detected phase:", item.phase);
|
||||
```
|
||||
|
||||
### Issue: Prices Not Updating
|
||||
|
||||
**Check:**
|
||||
1. Scheduler is running
|
||||
2. Last update timestamp
|
||||
3. Items match by name exactly
|
||||
4. No errors in logs
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
# Manually trigger update
|
||||
POST /api/admin/prices/update
|
||||
|
||||
# Check status
|
||||
GET /api/admin/prices/status
|
||||
|
||||
# Check missing prices
|
||||
GET /api/admin/prices/missing
|
||||
```
|
||||
|
||||
### Issue: Rate Limit Exceeded
|
||||
|
||||
**Error:** `429 Rate limit exceeded`
|
||||
|
||||
**Solutions:**
|
||||
1. Reduce update frequency (e.g., 2 hours instead of 1)
|
||||
2. Upgrade SteamAPIs.com plan
|
||||
3. Implement caching
|
||||
4. Batch updates
|
||||
|
||||
**Configure:**
|
||||
```javascript
|
||||
// Update every 2 hours instead
|
||||
pricingService.scheduleUpdates(120 * 60 * 1000);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Production Recommendations
|
||||
|
||||
### 1. Monitoring
|
||||
|
||||
- Set up alerts for failed price updates
|
||||
- Monitor API usage and rate limits
|
||||
- Track price coverage percentage
|
||||
- Log all admin actions
|
||||
|
||||
### 2. Optimization
|
||||
|
||||
- Cache price data in Redis (5-10 minutes)
|
||||
- Batch API requests when possible
|
||||
- Only update changed prices
|
||||
- Use webhooks if available
|
||||
|
||||
### 3. Backup Strategy
|
||||
|
||||
- Keep historical price data
|
||||
- Store last N successful fetches
|
||||
- Fallback to estimation if API down
|
||||
- Manual override capability
|
||||
|
||||
### 4. Security
|
||||
|
||||
- Restrict admin endpoints to IP whitelist
|
||||
- Log all price modifications
|
||||
- Implement audit trail
|
||||
- Rate limit admin endpoints
|
||||
|
||||
---
|
||||
|
||||
## 📚 API Reference
|
||||
|
||||
### SteamAPIs.com Endpoints
|
||||
|
||||
**Market Items:**
|
||||
```
|
||||
GET /market/items/{appId}?api_key={key}
|
||||
```
|
||||
|
||||
**Rate Limits:**
|
||||
- Free: 100,000 requests/month
|
||||
- Pro: Higher limits available
|
||||
|
||||
**Documentation:**
|
||||
https://steamapis.com/docs
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Examples
|
||||
|
||||
### Example 1: Manual Price Update
|
||||
|
||||
```javascript
|
||||
// Admin triggers update for CS2
|
||||
const response = await fetch('/api/admin/prices/update', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({ game: 'cs2' })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
console.log(`Updated ${result.data.cs2.updated} items`);
|
||||
```
|
||||
|
||||
### Example 2: Phase Detection
|
||||
|
||||
```javascript
|
||||
// Service method
|
||||
const phase = pricingService.detectPhase(
|
||||
"★ Karambit | Doppler (Factory New)",
|
||||
"Phase 2 pattern with pink/purple playside"
|
||||
);
|
||||
|
||||
console.log(phase); // "Phase 2"
|
||||
```
|
||||
|
||||
### Example 3: Price Estimation
|
||||
|
||||
```javascript
|
||||
const price = await pricingService.estimatePrice({
|
||||
name: "AK-47 | Redline (Field-Tested)",
|
||||
wear: "ft",
|
||||
phase: null,
|
||||
statTrak: false,
|
||||
souvenir: false
|
||||
});
|
||||
|
||||
console.log(price); // 42.50
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Checklist
|
||||
|
||||
**Setup:**
|
||||
- [ ] Added `STEAM_APIS_KEY` to `.env`
|
||||
- [ ] Configured admin Steam IDs or staff levels
|
||||
- [ ] Tested API key with manual request
|
||||
- [ ] Enabled price updates in environment
|
||||
|
||||
**Testing:**
|
||||
- [ ] Manual price update works
|
||||
- [ ] Automatic updates scheduled
|
||||
- [ ] Phase detection working
|
||||
- [ ] Database storing prices correctly
|
||||
- [ ] Admin endpoints accessible
|
||||
|
||||
**Production:**
|
||||
- [ ] Monitoring configured
|
||||
- [ ] Rate limits understood
|
||||
- [ ] Backup strategy in place
|
||||
- [ ] Security measures implemented
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2024
|
||||
**Version:** 1.0
|
||||
**Maintained by:** TurboTrades Team
|
||||
Reference in New Issue
Block a user