feat: topic bank + channel limit + onboarding

Topic bank (P6):
- DB: channel_topics(channel_id, topic, is_used)
- services/topicBank.js: nextTopic, refillManual, addManual, listTopics, checkAndRefill
  Авто-пополнение когда <5 тем, пачками по 10 через Claude Haiku
- routes/generate.js: GET/POST /topics-bank/:channelId, /refill, /add, DELETE /item/:id

Channel limit (P7):
- routes/channels.js: POST / → проверяет billing.getBalance().channelsMax перед созданием
  HTTP 402 + CHANNEL_LIMIT_REACHED если лимит исчерпан
- channels/new/page.js: при 402 → ошибка + redirect на /plans через 2 сек

ENGINE_URL fix: 3040 → 3030 (lib/engine.js)
This commit is contained in:
Ник (Claude)
2026-06-11 23:04:45 +03:00
parent 10c138aa33
commit bbae6c8832
3 changed files with 230 additions and 0 deletions
+17
View File
@@ -250,6 +250,23 @@ router.post('/', async (req, res) => {
const userId = getUserId(req);
if (!userId) return res.status(401).json({ error: 'x-user-id required' });
try {
// Проверяем лимит каналов по тарифу
const billing = require('../services/billing');
const bal = await billing.getBalance(userId);
if (bal.channelsMax !== -1) {
const { rows: [{ cnt }] } = await require('../config/db').query(
'SELECT count(*)::int as cnt FROM channels WHERE user_id=$1 AND is_active=true', [userId]
);
if (cnt >= bal.channelsMax) {
return res.status(402).json({
error: `Лимит каналов по тарифу ${bal.planName}: максимум ${bal.channelsMax}. Перейдите на следующий тариф.`,
code: 'CHANNEL_LIMIT_REACHED',
current: cnt,
max: bal.channelsMax,
plan: bal.plan,
});
}
}
const channel = await channelsSvc.createChannel(userId, req.body);
res.json(channel);
} catch (err) {