Files
snakkimo-API/src/index.js

80 lines
3.1 KiB
JavaScript

require('dotenv').config();
const express = require('express');
const cors = require('cors');
const auth = require('./middleware/auth');
const { pool } = require('./db');
const migrate = require('./db-migrate');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(cors());
app.use(express.json());
// Health check — always 200 so Coolify doesn't kill the container
app.get('/health', async (req, res) => {
let db = 'connected';
try {
await pool.query('SELECT 1');
} catch (err) {
db = err.message;
}
res.json({ status: 'ok', db });
});
// Public routes
app.use('/auth', require('./routes/auth'));
app.use('/auth/feed', require('./routes/feed').router);
// Routes — protected by Bearer token
app.use('/api', auth, require('./routes/index'));
app.use('/api/pictures', auth, require('./routes/pictures'));
app.use('/api/words', auth, require('./routes/words'));
app.use('/api/categories', auth, require('./routes/categories'));
app.use('/api/objects', auth, require('./routes/objects'));
app.use('/api/pairs', auth, require('./routes/pairs'));
app.use('/api/questions', auth, require('./routes/questions'));
app.use('/api/statements', auth, require('./routes/statements'));
app.use('/api/blocklist', auth, require('./routes/blocklist'));
app.use('/api/languages', auth, require('./routes/languages'));
app.use('/api/user-names', auth, require('./routes/user-names'));
app.use('/api/users-public', auth, require('./routes/users-public'));
app.use('/api/users', auth, require('./routes/users'));
app.use('/api/audios', auth, require('./routes/audios'));
app.use('/api/tts-settings', auth, require('./routes/tts-settings'));
app.use('/api/claude', auth, require('./routes/claude'));
app.use('/api/pipeline', auth, require('./routes/pipeline'));
app.use('/api/word-generative', auth, require('./routes/wordGenerative'));
// 404
app.use((req, res) => {
res.status(404).json({ error: 'Not found' });
});
// Error handler
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Internal server error' });
});
migrate()
.then(() => {
app.listen(PORT, '0.0.0.0', () => console.log(`snakkimo-API running on port ${PORT}`));
// Hängengebliebene Pipeline-Läufe (z.B. nach Redeploy) wieder aufnehmen
require('./lib/pipeline').resumePending()
.catch(err => console.error('Pipeline-Resume fehlgeschlagen:', err));
// Automatische Wort-Kategorisierung (Message Batches API): kurz nach Boot + stündlich.
// Submit/Collect-Ticks, entkoppelt von generate-words und Publish.
const { runCategorizationTick } = require('./lib/classifyWords');
const { runEnrichTick } = require('./lib/enrichWords');
const HOUR = 60 * 60 * 1000;
const tick = () => runCategorizationTick().catch(err => console.error('Auto-Kategorisierung:', err.message));
const enrichTick = () => runEnrichTick().catch(err => console.error('Auto-Anreicherung:', err.message));
setTimeout(tick, 30_000);
setTimeout(enrichTick, 60_000);
setInterval(tick, HOUR);
setInterval(enrichTick, HOUR);
})
.catch(err => { console.error('Migration failed:', err); process.exit(1); });