Files
cannaiq/backend/src/index.ts
Kelly 8b4292fbb2 Add local product detail page with Dutchie comparison
- Add ProductDetail page for viewing products locally
- Add Dutchie and Details buttons to product cards in Products and StoreDetail pages
- Add Last Updated display showing data freshness
- Add parallel scrape scripts and routes
- Add K8s deployment configurations
- Add frontend Dockerfile with nginx

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 06:34:38 -07:00

101 lines
3.6 KiB
TypeScript
Executable File

import express from 'express';
import cors from 'cors';
import path from 'path';
import dotenv from 'dotenv';
import { initializeMinio, isMinioEnabled } from './utils/minio';
import { logger } from './services/logger';
import { cleanupOrphanedJobs } from './services/proxyTestQueue';
dotenv.config();
const app = express();
const PORT = process.env.PORT || 3010;
app.use(cors());
app.use(express.json());
// Serve static images when MinIO is not configured
const LOCAL_IMAGES_PATH = process.env.LOCAL_IMAGES_PATH || '/app/public/images';
app.use('/images', express.static(LOCAL_IMAGES_PATH));
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
// Endpoint to check server's outbound IP (for proxy whitelist setup)
app.get('/outbound-ip', async (req, res) => {
try {
const axios = require('axios');
const response = await axios.get('https://api.ipify.org?format=json', { timeout: 10000 });
res.json({ outbound_ip: response.data.ip });
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
import authRoutes from './routes/auth';
import dashboardRoutes from './routes/dashboard';
import storesRoutes from './routes/stores';
import dispensariesRoutes from './routes/dispensaries';
import changesRoutes from './routes/changes';
import categoriesRoutes from './routes/categories';
import productsRoutes from './routes/products';
import campaignsRoutes from './routes/campaigns';
import analyticsRoutes from './routes/analytics';
import settingsRoutes from './routes/settings';
import proxiesRoutes from './routes/proxies';
import logsRoutes from './routes/logs';
import scraperMonitorRoutes from './routes/scraper-monitor';
import apiTokensRoutes from './routes/api-tokens';
import apiPermissionsRoutes from './routes/api-permissions';
import parallelScrapeRoutes from './routes/parallel-scrape';
import { trackApiUsage, checkRateLimit } from './middleware/apiTokenTracker';
import { validateWordPressPermissions } from './middleware/wordpressPermissions';
// Apply WordPress permissions validation first (sets req.apiToken)
app.use(validateWordPressPermissions);
// Apply API tracking middleware globally
app.use(trackApiUsage);
app.use(checkRateLimit);
app.use('/api/auth', authRoutes);
app.use('/api/dashboard', dashboardRoutes);
app.use('/api/stores', storesRoutes);
app.use('/api/dispensaries', dispensariesRoutes);
app.use('/api/changes', changesRoutes);
app.use('/api/categories', categoriesRoutes);
app.use('/api/products', productsRoutes);
app.use('/api/campaigns', campaignsRoutes);
app.use('/api/analytics', analyticsRoutes);
app.use('/api/settings', settingsRoutes);
app.use('/api/proxies', proxiesRoutes);
app.use('/api/logs', logsRoutes);
app.use('/api/scraper-monitor', scraperMonitorRoutes);
app.use('/api/api-tokens', apiTokensRoutes);
app.use('/api/api-permissions', apiPermissionsRoutes);
app.use('/api/parallel-scrape', parallelScrapeRoutes);
async function startServer() {
try {
logger.info('system', 'Starting server...');
await initializeMinio();
logger.info('system', isMinioEnabled() ? 'MinIO storage initialized' : 'Local filesystem storage initialized');
// Clean up any orphaned proxy test jobs from previous server runs
await cleanupOrphanedJobs();
app.listen(PORT, () => {
logger.info('system', `Server running on port ${PORT}`);
console.log(`🚀 Server running on port ${PORT}`);
});
} catch (error) {
logger.error('system', `Failed to start server: ${error}`);
console.error('Failed to start server:', error);
process.exit(1);
}
}
startServer();