feat: zeropost-tool — Next.js 16 кабинет

- Auth: iron-session, регистрация/логин по email+password
- Дашборд со списком каналов
- 3-шаговая анкета создания канала (база/стиль/примеры+табу)
- Страница канала с генератором постов через polling
- Тёмная тема, Tailwind 3.4, accent emerald
- Прокси-API к zeropost-engine с x-user-id
- Совместимость с Next 16 async cookies/params
This commit is contained in:
Alexey Pavlov
2026-05-31 08:38:10 +03:00
parent 8e979c3045
commit 5dd975a9cd
26 changed files with 3334 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
/**
* Engine client — единая точка вызовов к zeropost-engine
*/
const ENGINE_URL = process.env.ENGINE_URL || 'http://127.0.0.1:3040';
const ENGINE_SECRET = process.env.ENGINE_SECRET || 'zeropost_internal_2026';
async function call(path, options = {}) {
const { userId, body, method = 'GET' } = options;
const headers = {
'Content-Type': 'application/json',
'x-internal-secret': ENGINE_SECRET,
};
if (userId) headers['x-user-id'] = String(userId);
const url = `${ENGINE_URL}${path}`;
const res = await fetch(url, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
cache: 'no-store',
});
if (!res.ok) {
const err = await res.json().catch(() => ({ error: res.statusText }));
throw new Error(err.error || `Engine ${res.status}`);
}
return res.json();
}
export const engine = {
// Channels
listChannels: (userId) => call('/api/channels/', { userId }),
getChannel: (userId, id) => call(`/api/channels/${id}`, { userId }),
createChannel: (userId, data) => call('/api/channels/', { userId, method: 'POST', body: data }),
updateChannel: (userId, id, data) => call(`/api/channels/${id}`, { userId, method: 'PATCH', body: data }),
deleteChannel: (userId, id) => call(`/api/channels/${id}`, { userId, method: 'DELETE' }),
// Generation
generate: (userId, data) => call('/api/generate/', { userId, method: 'POST', body: data }),
getJob: (userId, id) => call(`/api/generate/${id}`, { userId }),
};