Files
coop/backend/src/index.ts
T
hobokenchicken e8d9b1fd42 feat: add CoopCredits Solana media rewards ecosystem
Add complete  token system with Plex/Tautulli/Overseer integration:
- Anchor program for SPL token mint/burn/transfer
- Express backend with OAuth, webhooks, Solana integration
- Next.js frontend with dashboard, admin panel, wallet management
- Docker deployment for 172.20.1.0/24 infrastructure
- Production configs with SSL, Nginx, health monitoring

Tautulli webhooks auto-mint  on watch events.
Overseer integration burns  for content requests.
2026-04-14 11:09:50 -04:00

127 lines
3.2 KiB
TypeScript

import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import morgan from 'morgan';
import rateLimit from 'express-rate-limit';
import { createServer } from 'http';
import { Server } from 'socket.io';
import dotenv from 'dotenv';
dotenv.config();
import { prisma } from './utils/prisma';
import { errorHandler } from './middleware/errorHandler';
import { authRouter } from './routes/auth';
import { userRouter } from './routes/users';
import { walletRouter } from './routes/wallet';
import { transactionsRouter } from './routes/transactions';
import { adminRouter } from './routes/admin';
import { tautulliRouter } from './routes/tautulli';
import { overseerRouter } from './routes/overseer';
import { webhookRouter } from './routes/webhooks';
import { setupSocketHandlers } from './services/socket';
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: process.env.FRONTEND_URL || 'http://localhost:3000',
credentials: true
}
});
// Security middleware
app.use(helmet());
app.use(cors({
origin: process.env.FRONTEND_URL || 'http://localhost:3000',
credentials: true
}));
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use(limiter);
// Body parsing
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Logging
app.use(morgan('combined'));
// Health check
app.get('/health', (_req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
// API routes
app.use('/api/auth', authRouter);
app.use('/api/users', userRouter);
app.use('/api/wallet', walletRouter);
app.use('/api/transactions', transactionsRouter);
app.use('/api/admin', adminRouter);
app.use('/api/tautulli', tautulliRouter);
app.use('/api/overseer', overseerRouter);
app.use('/webhooks', webhookRouter);
// Error handling
app.use(errorHandler);
// Setup WebSocket handlers
setupSocketHandlers(io);
// Start server
const PORT = process.env.PORT || 3001;
async function startServer() {
try {
// Connect to database
await prisma.$connect();
console.log('✅ Connected to database');
// Ensure default settings exist
const settings = await prisma.systemSettings.findFirst();
if (!settings) {
await prisma.systemSettings.create({
data: {
id: 'default'
}
});
console.log('✅ Created default system settings');
}
httpServer.listen(PORT, () => {
console.log(`🚀 Server running on port ${PORT}`);
console.log(`📊 API URL: ${process.env.API_URL || `http://localhost:${PORT}`}`);
});
} catch (error) {
console.error('Failed to start server:', error);
process.exit(1);
}
}
// Graceful shutdown
process.on('SIGTERM', async () => {
console.log('SIGTERM received, shutting down gracefully');
await prisma.$disconnect();
httpServer.close(() => {
console.log('Server closed');
process.exit(0);
});
});
process.on('SIGINT', async () => {
console.log('SIGINT received, shutting down gracefully');
await prisma.$disconnect();
httpServer.close(() => {
console.log('Server closed');
process.exit(0);
});
});
startServer();
export { io };